You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
4.4 KiB

  1. const _ = require('lodash')
  2. const cheerio = require('cheerio')
  3. /* global WIKI */
  4. module.exports = {
  5. async render() {
  6. const $ = cheerio.load(this.input)
  7. if ($.root().children().length < 1) {
  8. return ''
  9. }
  10. for (let child of this.children) {
  11. const renderer = require(`../${_.kebabCase(child.key)}/renderer.js`)
  12. renderer.init($, child.config)
  13. }
  14. // --------------------------------
  15. // Detect internal / external links
  16. // --------------------------------
  17. let internalRefs = []
  18. const reservedPrefixes = /^\/[a-z]\//gi
  19. const isHostSet = WIKI.config.host.length > 7 && WIKI.config.host !== 'http://'
  20. if (!isHostSet) {
  21. WIKI.logger.warn('Host is not set. You must set the Site Host under General in the Administration Area!')
  22. }
  23. $('a').each((i, elm) => {
  24. let href = $(elm).attr('href')
  25. // -> Ignore empty / anchor links
  26. if (!href || href.length < 1 || href.indexOf('#') === 0 || href.indexOf('mailto:') === 0) {
  27. return
  28. }
  29. // -> Strip host from local links
  30. if (isHostSet && href.indexOf(WIKI.config.host) === 0) {
  31. href = href.replace(WIKI.config.host, '')
  32. }
  33. // -> Assign local / external tag
  34. if (href.indexOf('://') < 0) {
  35. // -> Remove trailing slash
  36. if (_.endsWith('/')) {
  37. href = href.slice(0, -1)
  38. }
  39. // -> Check for system prefix
  40. if (!reservedPrefixes.test(href)) {
  41. $(elm).addClass(`is-internal-link`)
  42. // -> Reformat paths
  43. if (href.indexOf('/') !== 0) {
  44. href = `/${this.page.localeCode}/${this.page.path}/${href}`
  45. } else if (href.charAt(3) !== '/') {
  46. href = `/${this.page.localeCode}${href}`
  47. }
  48. // -> Save internal references
  49. internalRefs.push({
  50. localeCode: href.substring(1, 3),
  51. path: _.head(href.substring(4).split('#'))
  52. })
  53. } else {
  54. $(elm).addClass(`is-system-link`)
  55. }
  56. } else {
  57. $(elm).addClass(`is-external-link`)
  58. }
  59. // -> Update element
  60. $(elm).attr('href', href)
  61. })
  62. // --------------------------------
  63. // Detect internal link states
  64. // --------------------------------
  65. const pastLinks = await this.page.$relatedQuery('links')
  66. if (internalRefs.length > 0) {
  67. // -> Find matching pages
  68. const results = await WIKI.models.pages.query().column('id', 'path', 'localeCode').where(builder => {
  69. internalRefs.forEach((ref, idx) => {
  70. if (idx < 1) {
  71. builder.where(ref)
  72. } else {
  73. builder.orWhere(ref)
  74. }
  75. })
  76. })
  77. // -> Apply tag to internal links for found pages
  78. $('a.is-internal-link').each((i, elm) => {
  79. const href = $(elm).attr('href')
  80. const hrefObj = {
  81. localeCode: href.substring(1, 3),
  82. path: _.head(href.substring(4).split('#'))
  83. }
  84. if (_.some(results, r => {
  85. return r.localeCode === hrefObj.localeCode && r.path === hrefObj.path
  86. })) {
  87. $(elm).addClass(`is-valid-page`)
  88. } else {
  89. $(elm).addClass(`is-invalid-page`)
  90. }
  91. })
  92. // -> Add missing links
  93. const missingLinks = _.differenceWith(internalRefs, pastLinks, (nLink, pLink) => {
  94. return nLink.localeCode === pLink.localeCode && nLink.path === pLink.path
  95. })
  96. if (missingLinks.length > 0) {
  97. if (WIKI.config.db.type === 'postgres') {
  98. await WIKI.models.pageLinks.query().insert(missingLinks.map(lnk => ({
  99. pageId: this.page.id,
  100. path: lnk.path,
  101. localeCode: lnk.localeCode
  102. })))
  103. } else {
  104. for (const lnk of missingLinks) {
  105. await WIKI.models.pageLinks.query().insert({
  106. pageId: this.page.id,
  107. path: lnk.path,
  108. localeCode: lnk.localeCode
  109. })
  110. }
  111. }
  112. }
  113. }
  114. // -> Remove outdated links
  115. if (pastLinks) {
  116. const outdatedLinks = _.differenceWith(pastLinks, internalRefs, (nLink, pLink) => {
  117. return nLink.localeCode === pLink.localeCode && nLink.path === pLink.path
  118. })
  119. if (outdatedLinks.length > 0) {
  120. await WIKI.models.pageLinks.query().delete().whereIn('id', _.map(outdatedLinks, 'id'))
  121. }
  122. }
  123. return $.html('body').replace('<body>', '').replace('</body>', '')
  124. }
  125. }