Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove semi colons from html links #12404

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
} from '@/components/visualizations/TableVisualization/tableVizToolbar'
import { Ast } from '@/util/ast'
import { Pattern } from '@/util/ast/match'
import { LINKABLE_URL_REGEX } from '@/util/link'
import { useVisualizationConfig } from '@/util/visualizationBuiltins'
import type {
CellClassParams,
Expand All @@ -20,7 +19,7 @@ import type {
} from 'ag-grid-enterprise'
import { computed, onMounted, ref, shallowRef, watchEffect, type Ref } from 'vue'
import { TableVisualisationTooltip } from './TableVisualization/TableVisualisationTooltip'
import { getCellValueType, isNumericType } from './TableVisualization/tableVizUtils'
import { formatText, getCellValueType, isNumericType } from './TableVisualization/tableVizUtils'

export const name = 'Table'
export const icon = 'table'
Expand Down Expand Up @@ -193,54 +192,6 @@ function formatNumber(params: ICellRendererParams) {
return needsGrouping ? numberFormatGroupped.format(value) : numberFormat.format(value)
}

function formatText(params: ICellRendererParams) {
const htmlEscaped = params.value
.replaceAll('&', '&')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')

if (textFormatterSelected.value === 'off') {
const replaceLinks = replaceLinksWithTag(htmlEscaped)
return replaceLinks.replace(/^\s+|\s+$/g, '&nbsp;')
}

const partialMappings = {
'\r': '<span style="color: #df8800">␍</span> <br>',
'\n': '<span style="color: #df8800;">␊</span> <br>',
'\t': '<span style="color: #df8800; white-space: break-spaces;">&#8594; |</span>',
}
const fullMappings = {
'\r': '<span style="color: #df8800">␍</span> <br>',
'\n': '<span style="color: #df8800">␊</span> <br>',
'\t': '<span style="color: #df8800; white-space: break-spaces;">&#8594; |</span>',
}

const replaceSpaces =
textFormatterSelected.value === 'full' ?
htmlEscaped.replaceAll(' ', '<span style="color: #df8800">&#183;</span>')
: htmlEscaped.replace(/ \s+|^ +| +$/g, function (match: string) {
return `<span style="color: #df8800">${match.replaceAll(' ', '&#183;')}</span>`
})

const replaceLinks = replaceLinksWithTag(replaceSpaces)

const replaceReturns = replaceLinks.replace(
/\r\n/g,
'<span style="color: #df8800">␍␊</span> <br>',
)

const renderOtherWhitespace = (match: string) => {
return textFormatterSelected.value === 'full' && match != ' ' ?
'<span style="color: #df8800">&#9744;</span>'
: match
}
const newString = replaceReturns.replace(/[\s]/g, function (match: string) {
const mapping = textFormatterSelected.value === 'full' ? fullMappings : partialMappings
return mapping[match as keyof typeof mapping] || renderOtherWhitespace(match)
})
return `<span > ${newString} <span>`
}

function setRowLimit(newRowLimit: number) {
if (newRowLimit !== rowLimit.value) {
rowLimit.value = newRowLimit
Expand All @@ -252,13 +203,6 @@ function setRowLimit(newRowLimit: number) {
}
}

function replaceLinksWithTag(str: string) {
return str.replace(
LINKABLE_URL_REGEX,
(url: string) => `<a href="${url}" target="_blank" class="link">${url}</a>`,
)
}

function escapeHTML(str: string) {
const mapping: Record<string, string> = {
'&': '&amp;',
Expand Down Expand Up @@ -286,7 +230,8 @@ function cellRenderer(params: ICellRendererParams) {
else if (params.value === undefined) return ''
else if (params.value === '') return '<span style="color:grey; font-style: italic;">Empty</span>'
else if (typeof params.value === 'number') return formatNumber(params)
else if (typeof params.value === 'string') return formatText(params)
else if (typeof params.value === 'string')
return formatText(params.value, textFormatterSelected.value)
else if (Array.isArray(params.value)) return `[Vector ${params.value.length} items]`
else if (typeof params.value === 'object') {
const valueType = params.value?.type
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { LINKABLE_URL_REGEX } from '@/util/link'
import { TextFormatOptions } from '../TableVisualization.vue'

export const getCellValueType = (item: string) => {
switch (true) {
case isInteger(item):
Expand Down Expand Up @@ -35,3 +38,55 @@ export const isNumericType = (valueType: string) => {
const isNumber = ['Integer', 'Float', 'Decimal', 'Byte']
return isNumber.indexOf(valueType) != -1
}

const replaceLinksWithTag = (str: string) => {
return str.replace(
LINKABLE_URL_REGEX,
(url: string) => `<a href="${url}" target="_blank" class="link">${url}</a>`,
)
}

export const formatText = (input: string, textFormatterSelected: TextFormatOptions) => {
const htmlEscaped = input.replaceAll('<', '&lt;').replaceAll('>', '&gt;')

if (textFormatterSelected === 'off') {
const replaceLinks = replaceLinksWithTag(htmlEscaped)
return replaceLinks.replace(/^\s+|\s+$/g, '&nbsp;')
}

const partialMappings = {
'\r': '<span style="color: #df8800">␍</span> <br>',
'\n': '<span style="color: #df8800;">␊</span> <br>',
'\t': '<span style="color: #df8800; white-space: break-spaces;">&#8594; |</span>',
}
const fullMappings = {
'\r': '<span style="color: #df8800">␍</span> <br>',
'\n': '<span style="color: #df8800">␊</span> <br>',
'\t': '<span style="color: #df8800; white-space: break-spaces;">&#8594; |</span>',
}

const replaceSpaces =
textFormatterSelected === 'full' ?
htmlEscaped.replaceAll(' ', '<span style="color: #df8800">&#183;</span>')
: htmlEscaped.replace(/ \s+|^ +| +$/g, function (match: string) {
return `<span style="color: #df8800">${match.replaceAll(' ', '&#183;')}</span>`
})

const replaceLinks = replaceLinksWithTag(replaceSpaces)

const replaceReturns = replaceLinks.replace(
/\r\n/g,
'<span style="color: #df8800">␍␊</span> <br>',
)

const renderOtherWhitespace = (match: string) => {
return textFormatterSelected === 'full' && match != ' ' ?
'<span style="color: #df8800">&#9744;</span>'
: match
}
const newString = replaceReturns.replace(/[\s]/g, function (match: string) {
const mapping = textFormatterSelected === 'full' ? fullMappings : partialMappings
return mapping[match as keyof typeof mapping] || renderOtherWhitespace(match)
})
return `<span > ${newString} <span>`
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect, test } from 'vitest'
import { getCellValueType, isNumericType } from '../TableVisualization/tableVizUtils'
import { formatText, getCellValueType, isNumericType } from '../TableVisualization/tableVizUtils'

test('getCellValueType (Text)', () => {
expect(getCellValueType('Alan')).toEqual('Char')
Expand Down Expand Up @@ -40,3 +40,15 @@ test('isNumericType (Numeric Type)', () => {
test('isNumericType (Char Type)', () => {
expect(isNumericType('Char')).toEqual(false)
})

test('formatText (text with link, full formatting)', () => {
expect(formatText('https://www.google.com/search?q=rock&roll', 'full')).toEqual(
'<span > <a href="https://www.google.com/search?q=rock&roll" target="_blank" class="link">https://www.google.com/search?q=rock&roll</a> <span>',
)
})

test('formatText (text, full formatting)', () => {
expect(formatText('rock & roll', 'full')).toEqual(
'<span > rock<span style="color: #df8800">&#183;</span>&<span style="color: #df8800">&#183;</span>roll <span>',
)
})
Loading