summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_shared
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/vue_shared')
-rw-r--r--app/assets/javascripts/vue_shared/components/header_ci_component.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue32
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/constants.js23
-rw-r--r--app/assets/javascripts/vue_shared/translate.js2
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({