summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue')
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue118
1 files changed, 59 insertions, 59 deletions
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue
index 28a16cd846a..092e8ba6c15 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue
@@ -1,64 +1,55 @@
<script>
import { GlIntersectionObserver } from '@gitlab/ui';
-import LineHighlighter from '~/blob/line_highlighter';
-import ChunkLine from './chunk_line.vue';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+import { getPageParamValue, getPageSearchString } from '~/blob/utils';
/*
* We only highlight the chunk that is currently visible to the user.
* By making use of the Intersection Observer API we can determine when a chunk becomes visible and highlight it accordingly.
*
- * Content that is not visible to the user (i.e. not highlighted) do not need to look nice,
- * so by making text transparent and rendering raw (non-highlighted) text,
- * the browser spends less resources on painting content that is not immediately relevant.
- *
- * Why use transparent text as opposed to hiding content entirely?
- * 1. If content is hidden entirely, native find text (⌘ + F) won't work.
- * 2. When URL contains line numbers, the browser needs to be able to jump to the correct line.
+ * Content that is not visible to the user (i.e. not highlighted) does not need to look nice,
+ * so by rendering raw (non-highlighted) text, the browser spends less resources on painting
+ * content that is not immediately relevant.
+ * Why use plaintext as opposed to hiding content entirely?
+ * If content is hidden entirely, native find text (⌘ + F) won't work.
*/
export default {
components: {
- ChunkLine,
GlIntersectionObserver,
},
+ directives: {
+ SafeHtml,
+ },
+ mixins: [glFeatureFlagMixin()],
props: {
- isFirstChunk: {
+ isHighlighted: {
type: Boolean,
- required: false,
- default: false,
+ required: true,
},
chunkIndex: {
type: Number,
required: false,
default: 0,
},
- isHighlighted: {
- type: Boolean,
+ rawContent: {
+ type: String,
required: true,
},
- content: {
+ highlightedContent: {
type: String,
required: true,
},
- startingFrom: {
- type: Number,
- required: false,
- default: 0,
- },
totalLines: {
type: Number,
required: false,
default: 0,
},
- totalChunks: {
+ startingFrom: {
type: Number,
required: false,
default: 0,
},
- language: {
- type: String,
- required: false,
- default: null,
- },
blamePath: {
type: String,
required: true,
@@ -66,37 +57,37 @@ export default {
},
data() {
return {
+ hasAppeared: false,
isLoading: true,
};
},
computed: {
+ shouldHighlight() {
+ return Boolean(this.highlightedContent) && (this.hasAppeared || this.isHighlighted);
+ },
lines() {
return this.content.split('\n');
},
+ pageSearchString() {
+ if (!this.glFeatures.fileLineBlame) return '';
+ const page = getPageParamValue(this.number);
+ return getPageSearchString(this.blamePath, page);
+ },
},
-
created() {
- if (this.isFirstChunk) {
+ if (this.chunkIndex === 0) {
+ // Display first chunk ASAP in order to improve perceived performance
this.isLoading = false;
return;
}
- window.requestIdleCallback(async () => {
+ window.requestIdleCallback(() => {
this.isLoading = false;
- const { hash } = this.$route;
- if (hash && this.totalChunks > 0 && this.totalChunks === this.chunkIndex + 1) {
- // when the last chunk is loaded scroll to the hash
- await this.$nextTick();
- const lineHighlighter = new LineHighlighter({ scrollBehavior: 'auto' });
- lineHighlighter.highlightHash(hash);
- }
});
},
methods: {
handleChunkAppear() {
- if (!this.isHighlighted) {
- this.$emit('appear', this.chunkIndex);
- }
+ this.hasAppeared = true;
},
calculateLineNumber(index) {
return this.startingFrom + index + 1;
@@ -106,28 +97,37 @@ export default {
</script>
<template>
<gl-intersection-observer @appear="handleChunkAppear">
- <div v-if="isHighlighted">
- <chunk-line
- v-for="(line, index) in lines"
- :key="index"
- :number="calculateLineNumber(index)"
- :content="line"
- :language="language"
- :blame-path="blamePath"
- />
- </div>
- <div v-else-if="!isLoading" class="gl-display-flex gl-text-transparent">
- <div class="gl-display-flex gl-flex-direction-column content-visibility-auto">
- <span
+ <div class="gl-display-flex">
+ <div v-if="shouldHighlight" class="gl-display-flex gl-flex-direction-column">
+ <div
v-for="(n, index) in totalLines"
- v-once
- :id="`L${calculateLineNumber(index)}`"
:key="index"
- data-testid="line-number"
- v-text="calculateLineNumber(index)"
- ></span>
+ data-testid="line-numbers"
+ class="gl-p-0! gl-z-index-3 diff-line-num gl-border-r gl-display-flex line-links line-numbers"
+ >
+ <a
+ v-if="glFeatures.fileLineBlame"
+ class="gl-user-select-none gl-shadow-none! file-line-blame"
+ :href="`${blamePath}${pageSearchString}#L${calculateLineNumber(index)}`"
+ ></a>
+ <a
+ :id="`L${calculateLineNumber(index)}`"
+ class="gl-user-select-none gl-shadow-none! file-line-num"
+ :href="`#L${calculateLineNumber(index)}`"
+ :data-line-number="calculateLineNumber(index)"
+ >
+ {{ calculateLineNumber(index) }}
+ </a>
+ </div>
</div>
- <div v-once class="gl-white-space-pre-wrap!" data-testid="content">{{ content }}</div>
+
+ <div v-else-if="!isLoading" class="line-numbers gl-p-0! gl-mr-3 gl-text-transparent">
+ <!-- Placeholder for line numbers while content is not highlighted -->
+ </div>
+
+ <pre
+ class="gl-m-0 gl-p-0! gl-w-full gl-overflow-visible! gl-border-none! code highlight gl-line-height-0"
+ ><code v-if="shouldHighlight" v-once v-safe-html="highlightedContent" data-testid="content"></code><code v-else-if="!isLoading" v-once class="line gl-white-space-pre-wrap! gl-ml-1" data-testid="content" v-text="rawContent"></code></pre>
</div>
</gl-intersection-observer>
</template>