diff options
Diffstat (limited to 'app/assets/javascripts/vue_shared')
4 files changed, 57 insertions, 4 deletions
diff --git a/app/assets/javascripts/vue_shared/components/header_ci_component.vue b/app/assets/javascripts/vue_shared/components/header_ci_component.vue index 9bff469b670..2622bdfb8cb 100644 --- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue +++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue @@ -8,8 +8,8 @@ import { GlTooltip, } from '@gitlab/ui'; import { isGid, getIdFromGraphQLId } from '~/graphql_shared/utils'; -import { glEmojiTag } from '../../emoji'; -import { __, sprintf } from '../../locale'; +import { glEmojiTag } from '~/emoji'; +import { __, sprintf } from '~/locale'; import CiIconBadge from './ci_badge_link.vue'; import TimeagoTooltip from './time_ago_tooltip.vue'; diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue index ab989ae6f9e..1b8e4bcfec6 100644 --- a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue +++ b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue @@ -1,5 +1,7 @@ <script> import { GlLink, GlSafeHtmlDirective } from '@gitlab/ui'; +import { setAttributes } from '~/lib/utils/dom_utils'; +import { BIDI_CHARS, BIDI_CHARS_CLASS_LIST, BIDI_CHAR_TOOLTIP } from '../constants'; export default { components: { @@ -22,6 +24,34 @@ export default { required: true, }, }, + computed: { + formattedContent() { + let { content } = this; + + BIDI_CHARS.forEach((bidiChar) => { + if (content.includes(bidiChar)) { + content = content.replace(bidiChar, this.wrapBidiChar(bidiChar)); + } + }); + + return content; + }, + }, + methods: { + wrapBidiChar(bidiChar) { + const span = document.createElement('span'); + + setAttributes(span, { + class: BIDI_CHARS_CLASS_LIST, + title: BIDI_CHAR_TOOLTIP, + 'data-testid': 'bidi-wrapper', + }); + + span.innerText = bidiChar; + + return span.outerHTML; + }, + }, }; </script> <template> @@ -39,6 +69,6 @@ export default { <pre class="code highlight gl-p-0! gl-w-full gl-overflow-visible! gl-ml-11!" - ><code><span :id="`LC${number}`" v-safe-html="content" :lang="language" class="line" data-testid="content"></span></code></pre> + ><code><span :id="`LC${number}`" v-safe-html="formattedContent" :lang="language" class="line" data-testid="content"></span></code></pre> </div> </template> diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/constants.js b/app/assets/javascripts/vue_shared/components/source_viewer/constants.js index b5ce214e577..bed6dd4d5c6 100644 --- a/app/assets/javascripts/vue_shared/components/source_viewer/constants.js +++ b/app/assets/javascripts/vue_shared/components/source_viewer/constants.js @@ -1,3 +1,5 @@ +import { __ } from '~/locale'; + // Language map from Rouge::Lexer to highlight.js // Rouge::Lexer - We use it on the BE to determine the language of a source file (https://github.com/rouge-ruby/rouge/blob/master/docs/Languages.md). // Highlight.js - We use it on the FE to highlight the syntax of a source file (https://github.com/highlightjs/highlight.js/tree/main/src/languages). @@ -111,3 +113,24 @@ export const ROUGE_TO_HLJS_LANGUAGE_MAP = { }; export const LINES_PER_CHUNK = 70; + +export const BIDI_CHARS = [ + '\u202A', // Left-to-Right Embedding (Try treating following text as left-to-right) + '\u202B', // Right-to-Left Embedding (Try treating following text as right-to-left) + '\u202D', // Left-to-Right Override (Force treating following text as left-to-right) + '\u202E', // Right-to-Left Override (Force treating following text as right-to-left) + '\u2066', // Left-to-Right Isolate (Force treating following text as left-to-right without affecting adjacent text) + '\u2067', // Right-to-Left Isolate (Force treating following text as right-to-left without affecting adjacent text) + '\u2068', // First Strong Isolate (Force treating following text in direction indicated by the next character) + '\u202C', // Pop Directional Formatting (Terminate nearest LRE, RLE, LRO, or RLO) + '\u2069', // Pop Directional Isolate (Terminate nearest LRI or RLI) + '\u061C', // Arabic Letter Mark (Right-to-left zero-width Arabic character) + '\u200F', // Right-to-Left Mark (Right-to-left zero-width character non-Arabic character) + '\u200E', // Left-to-Right Mark (Left-to-right zero-width character) +]; + +export const BIDI_CHARS_CLASS_LIST = 'unicode-bidi has-tooltip'; + +export const BIDI_CHAR_TOOLTIP = __( + 'Potentially unwanted character detected: Unicode BiDi Control', +); diff --git a/app/assets/javascripts/vue_shared/translate.js b/app/assets/javascripts/vue_shared/translate.js index 616848639f1..bc1f8865261 100644 --- a/app/assets/javascripts/vue_shared/translate.js +++ b/app/assets/javascripts/vue_shared/translate.js @@ -1,4 +1,4 @@ -import { __, n__, s__, sprintf } from '../locale'; +import { __, n__, s__, sprintf } from '~/locale'; export default (Vue) => { Vue.mixin({ |
