Skip to content

Commit

Permalink
Fixed markup encode issue (#572)
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-yao committed Oct 18, 2019
1 parent 07dda4b commit 0af1e83
Show file tree
Hide file tree
Showing 13 changed files with 121 additions and 71 deletions.
24 changes: 22 additions & 2 deletions packages/components/Atoms/Global/utils/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,27 @@ function _isTelOrEmailUrl (url) {
return false
}

export const truncateText = (text, stop = 150, clamp) => {
const decodeSpecialCharacters = (html) => {
const map = {
'&': '&',
'>': '>',
'&lt;': '<',
'&apos;': "'",
'&#039;': "'",
'&quot;': '"',
'&nbsp;': ' '
}
let replaceableCodes = '('
let first = true
for (const code in map) {
replaceableCodes += first ? code : `|${code}`
first = false
}
replaceableCodes += ')'
return html.replace(new RegExp(replaceableCodes, 'gi'), (code) => { return map[code.toLowerCase()] })
}

const truncateText = (text, stop = 150, clamp) => {
if (text && typeof text === 'string') {
if (text.length > stop) {
return text.slice(0, stop) + (stop < text.length ? clamp || '...' : '')
Expand All @@ -95,4 +115,4 @@ export const truncateText = (text, stop = 150, clamp) => {
return ''
}

export { isRelativeUrl, isExternalUrl, isAnchorLink, getAnchorLinkName, formatMoney, isClient }
export { isRelativeUrl, isExternalUrl, isAnchorLink, getAnchorLinkName, formatMoney, isClient, truncateText, decodeSpecialCharacters }
10 changes: 8 additions & 2 deletions packages/components/Atoms/Link/TextLink.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<rpl-link class="rpl-text-link" :class="{ 'rpl-text-link--underline': underline }" :href="url" :innerWrap="innerWrap">
<rpl-text-label :theme="theme" :size="size" :underline="underline" :emphasis="emphasis">
<rpl-text-icon :text="text" :symbol="iconSymbolFinal" :color="iconColor" :placement="iconPlacement" :size="iconSize" />
<rpl-text-icon :text="textDecoded" :symbol="iconSymbolFinal" :color="iconColor" :placement="iconPlacement" :size="iconSize" />
</rpl-text-label>
</rpl-link>
</template>
Expand All @@ -10,7 +10,7 @@
import { RplTextIcon } from '@dpc-sdp/ripple-icon'
import RplLink from './Link.vue'
import RplTextLabel from './TextLabel.vue'
import { isExternalUrl } from '@dpc-sdp/ripple-global/utils/helpers.js'
import { isExternalUrl, decodeSpecialCharacters } from '@dpc-sdp/ripple-global/utils/helpers.js'
export default {
name: 'RplTextLink',
Expand All @@ -33,6 +33,12 @@ export default {
RplTextLabel
},
computed: {
textDecoded: function () {
// TODO: This is a temporary fix.
// In Markup component, We can't avoid taking HTML encoded link text(especially for `"`) from CMS and feeding them into the text icon.
// We may just change all link text to HTML to solve this issue eventally.
return decodeSpecialCharacters(this.text)
},
iconSymbolFinal () {
if (isExternalUrl(this.url, this.rplOptions.hostname)) {
return 'external_link'
Expand Down
12 changes: 9 additions & 3 deletions packages/components/Molecules/DocumentLink/DocumentLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
<a class="rpl-document-link__link" :aria-label="`${name} File type: ${extension}. Size: ${filesize}`" :href="url" :download="isExternalLink ? false : ''" :target="isExternalLink ? '_blank' : false">
<rpl-icon class="rpl-document-link__icon" :symbol="icon" color="primary" size="l" />
<div class="rpl-document-link__info">
<span class="rpl-document-link__title">{{name}}</span>
<span class="rpl-document-link__title">{{nameDecoded}}</span>
<div class="rpl-document-link__meta">
<span v-if="extension" class="rpl-document-link__type">{{extension}}</span>
<span v-if="filesize" class="rpl-document-link__size" :class="{'rpl-document-link__size--seperator': extension && filesize}">{{filesize}}</span>
</div>
</div>
</a>
<figcaption class="rpl-document-link__caption" v-if="caption">{{caption}}</figcaption>
<figcaption class="rpl-document-link__caption" v-if="caption" v-html="caption"></figcaption>
</figure>
</template>

<script>
import RplIcon from '@dpc-sdp/ripple-icon'
import { isExternalUrl } from '@dpc-sdp/ripple-global/utils/helpers.js'
import { isExternalUrl, decodeSpecialCharacters } from '@dpc-sdp/ripple-global/utils/helpers.js'
export default {
name: 'RplDocumentLink',
Expand All @@ -29,6 +29,12 @@ export default {
filesize: String
},
computed: {
nameDecoded: function () {
// TODO: This is a temporary fix.
// In Markup component, We can't avoid taking HTML encoded link text from CMS and feeding them into the text icon.
// We may just change all link text to HTML to solve this issue eventally.
return decodeSpecialCharacters(this.name)
},
icon () {
switch (this.extension) {
case 'ai':
Expand Down
24 changes: 24 additions & 0 deletions packages/components/Organisms/Markup/markup-transpiler.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
import cheerio from 'cheerio'

// This is a hack to cheerio to solve the unwanted encode issue.
// https://github.com/cheeriojs/cheerio/issues/866#issuecomment-275699121
// We don't want cheerio to encode our vue template, as it will add encoded entities into Vue props.
// NOTE: Any HTML encoded entities in original HTML will be kept as it is.
const cheerioHtml = cheerio.prototype.html
cheerio.prototype.html = function wrappedHtml () {
var result = cheerioHtml.apply(this, arguments)

if (typeof result === 'string') {
result = result.replace(/&#x([0-9a-f]{1,6});/ig, function (entity, code) {
code = parseInt(code, 16)

// don't unescape ascii characters, assuming that all ascii characters
// are encoded for a good reason
if (code < 0x80) return entity

return String.fromCodePoint(code)
})
}

return result
}

// A markup transplier for converting HTML into Vue template by giving plugins.
const markupTranspiler = (html, plugins = {}, options = {}) => {
const $ = cheerio.load(html, options)
const $body = $('body')
Expand Down
16 changes: 11 additions & 5 deletions packages/ripple-nuxt-tide/lib/config/markup-plugins.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import htmlUtilities from './../core/html-utilities'
import { getAnchorLinkName } from '@dpc-sdp/ripple-global/utils/helpers.js'
// import cheerio from 'cheerio'

// Encode double quote before pass it into Vue template prop, otherwise it breaks the template.
const _escapeQuotes = (text) => {
text = text || ''
return text.replace('"', '&quot;')
}

const pluginButton = function () {
// Button
Expand Down Expand Up @@ -84,7 +90,7 @@ const pluginEmbeddedDocument = function () {
}

if (url && fileName && fileSize && fileType) {
const documentlink = `<rpl-document-link name="${fileName}" extension="${fileType}" filesize="${fileSize}" url="${url}" caption="${caption}"></rpl-document-link>`
const documentlink = `<rpl-document-link name="${_escapeQuotes(fileName)}" extension="${fileType}" filesize="${fileSize}" url="${url}" caption="${_escapeQuotes(caption)}"></rpl-document-link>`
return el.replaceWith(documentlink)
}
return el
Expand Down Expand Up @@ -144,15 +150,15 @@ const pluginLinks = function () {
this.find('a').map((i, el) => {
const $a = this.find(el)
const href = $a.attr('href')
const text = htmlUtilities.decodeSpecialCharacters($a.text())
const text = $a.text()

const target = $a.attr('target')
let theme = 'primary'
let a
if (target) {
a = `<rpl-text-link url="${href}" theme="${theme}" target="${target}" text="${text}"></rpl-text-link>`
a = `<rpl-text-link url="${href}" theme="${theme}" target="${target}" text="${_escapeQuotes(text)}"></rpl-text-link>`
} else {
a = `<rpl-text-link url="${href}" theme="${theme}" text="${text}"></rpl-text-link>`
a = `<rpl-text-link url="${href}" theme="${theme}" text="${_escapeQuotes(text)}"></rpl-text-link>`
}

return $a.replaceWith(a)
Expand Down
3 changes: 1 addition & 2 deletions packages/ripple-nuxt-tide/lib/core/anchorlinks.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import htmlUtilities from './html-utilities'
import { getAnchorLinkName } from '@dpc-sdp/ripple-global/utils/helpers.js'

const anchorUtils = {
Expand All @@ -22,7 +21,7 @@ const anchorUtils = {
// Ignore empty headings.
if (this.textExists(item.text)) {
result.push({
text: htmlUtilities.decodeSpecialCharacters(item.text),
text: item.text,
url: '#' + getAnchorLinkName(item.text)
})
}
Expand Down
21 changes: 0 additions & 21 deletions packages/ripple-nuxt-tide/lib/core/html-utilities.js

This file was deleted.

4 changes: 2 additions & 2 deletions packages/ripple-nuxt-tide/lib/core/mapping-filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export default {
return (hasCaption && hasImage) ? fieldCampaign.field_block_image.field_media_caption : null
},
formattedTextDecode: (formattedText) => {
const htmlUtilities = require('@dpc-sdp/ripple-nuxt-tide/lib/core/html-utilities').default
return htmlUtilities.decodeSpecialCharacters(formattedText.processed)
const decodeSpecialCharacters = require('@dpc-sdp/ripple-global/utils/helpers.js').decodeSpecialCharacters
return decodeSpecialCharacters(formattedText.processed)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/* eslint-disable no-irregular-whitespace */
const html = `
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<a href="http://google.com">&lt;&gt;&amp;'"©. ½ € 中文</a>
<h4>Sort out your'><&'"s finances</h4>\n\n<p><a href="https://www.test.dev/test">Here is a irregular white space</a> Another irregular white space.</p>
<blockquote class="quotation">
<p>Berios sim destrum facientota nis ex eost aut prae vendis explam aliquis dolorpo rrorem reptaep elenis net.</p>
Expand All @@ -21,7 +24,7 @@ const html = `
class="field field--name-field-media-image field--type-image field--label-hidden field__item"
>
<img
src="https://nginx-php-content-vic-develop.lagoon.vicsdp.amazee.io/sites/default/files/2018-06/call-to-action.jpg"
src="https://test.dev/sites/default/files/2018-06/call-to-action.jpg"
width="275" height="183" alt="" title="A dummy call to action image (title)">
</div>
</article>
Expand All @@ -35,7 +38,7 @@ const html = `
>
<span class="file file--mime-application-zip file--package-x-generic"
><a
href="https://www.develop.content.vic.gov.au/sites/default/files/2018-12/Screen%20Shot%202018-12-05%20at%2010.17.01%20am.zip"
href="https://www.test.dev/sites/default/files/2018-12/Screen%20Shot%202018-12-05%20at%2010.17.01%20am.zip"
aria-label="test zip File type: Other. Size: 787.53 KB."
class="package-x-generic tide-external-link"
target="_blank"
Expand All @@ -57,7 +60,7 @@ const html = `
<span
class="file file--mime-application-vnd-openxmlformats-officedocument-wordprocessingml-document file--x-office-document"
><a
href="https://www.develop.content.vic.gov.au/sites/default/files/2018-12/180629SSP%20User%20Research%20%26%20Testing%20Playbook%20Final.docx"
href="https://www.test.dev/sites/default/files/2018-12/180629SSP%20User%20Research%20%26%20Testing%20Playbook%20Final.docx"
aria-label="docx File type: Word. Size: 60.17 KB."
class="x-office-document tide-external-link"
target="_blank"
Expand All @@ -79,7 +82,7 @@ const html = `
<span
class="file file--mime-application-vnd-ms-excel file--x-office-spreadsheet"
><a
href="https://www.develop.content.vic.gov.au/sites/default/files/2018-12/list_one.xls"
href="https://www.test.dev/sites/default/files/2018-12/list_one.xls"
aria-label="xls File type: Excel. Size: 93 KB."
class="x-office-spreadsheet tide-external-link"
target="_blank"
Expand All @@ -101,7 +104,7 @@ const html = `
<span
class="file file--mime-application-vnd-openxmlformats-officedocument-presentationml-presentation file--x-office-presentation"
><a
href="https://www.develop.content.vic.gov.au/sites/default/files/2018-12/samplepptx.pptx"
href="https://www.test.dev/sites/default/files/2018-12/samplepptx.pptx"
aria-label="pptx File type: PPT. Size: 404.19 KB."
class="x-office-presentation tide-external-link"
target="_blank"
Expand All @@ -122,7 +125,7 @@ const html = `
>
<span class="file file--mime-text-csv file--text"
><a
href="https://www.develop.content.vic.gov.au/sites/default/files/2018-12/C2ImportCalEventSample.csv"
href="https://www.test.dev/sites/default/files/2018-12/C2ImportCalEventSample.csv"
aria-label="csv File type: Text. Size: 545 bytes."
class="text tide-external-link"
target="_blank"
Expand All @@ -143,7 +146,7 @@ const html = `
>
<span class="file file--mime-application-msword file--x-office-document"
><a
href="https://www.develop.content.vic.gov.au/sites/default/files/2018-12/TestWordDoc.doc"
href="https://www.test.dev/sites/default/files/2018-12/TestWordDoc.doc"
aria-label="doc File type: Word. Size: 19 KB."
class="x-office-document tide-external-link"
target="_blank"
Expand All @@ -165,7 +168,7 @@ const html = `
<span
class="file file--mime-application-vnd-ms-excel file--x-office-spreadsheet"
><a
href="https://www.develop.content.vic.gov.au/sites/default/files/2018-12/tests-example.xls"
href="https://www.test.dev/sites/default/files/2018-12/tests-example.xls"
aria-label="xls File type: Excel. Size: 16 KB."
class="x-office-spreadsheet tide-external-link"
target="_blank"
Expand All @@ -186,7 +189,7 @@ const html = `
>
<span class="file file--mime-text-plain file--text"
><a
href="https://www.develop.content.vic.gov.au/sites/default/files/2018-12/Copy.txt"
href="https://www.test.dev/sites/default/files/2018-12/Copy.txt"
aria-label="Text doc File type: Text. Size: 374 bytes."
class="text tide-external-link"
target="_blank"
Expand All @@ -203,7 +206,7 @@ const html = `
<article class="media media--type-document media--view-mode-embedded">
<div class="field field--name-field-media-file field--type-file field--label-hidden field__item">
<span class="file file--mime-text-calendar file--text">
<a aria-label="ICS as Doc File type: Text. Size: 24.28 KB." class="text" href="https://nginx-php-content-vic-develop.lagoon.vicsdp.amazee.io/sites/default/files/2019-02/AAA10am%20to%201015am%20on%20weekdays%20%28AEDT%29%20_0.ics"><span class="file--title">ICS as Doc</span><span class="file--type">Text</span><span class="file--size">24.28 KB</span></a></span>
<a aria-label="ICS as Doc File type: Text. Size: 24.28 KB." class="text" href="https://test.dev/sites/default/files/2019-02/AAA10am%20to%201015am%20on%20weekdays%20%28AEDT%29%20_0.ics"><span class="file--title">ICS as Doc</span><span class="file--type">Text</span><span class="file--size">24.28 KB</span></a></span>
</div>
</article>
</article>
Expand Down
Loading

0 comments on commit 0af1e83

Please sign in to comment.