Commit 5a44c3e6 authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Merge branch 'improve-blob-line-selection' into 'master'

Blob refactor: Improve blob line selection

See merge request gitlab-org/gitlab!78545
parents 762d9a60 537ece9a
import Vue from 'vue'; import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import VueRouter from 'vue-router';
import TableOfContents from '~/blob/components/table_contents.vue'; import TableOfContents from '~/blob/components/table_contents.vue';
import PipelineTourSuccessModal from '~/blob/pipeline_tour_success_modal.vue'; import PipelineTourSuccessModal from '~/blob/pipeline_tour_success_modal.vue';
import { BlobViewer, initAuxiliaryViewer } from '~/blob/viewer/index'; import { BlobViewer, initAuxiliaryViewer } from '~/blob/viewer/index';
...@@ -12,11 +13,14 @@ import BlobContentViewer from '~/repository/components/blob_content_viewer.vue'; ...@@ -12,11 +13,14 @@ import BlobContentViewer from '~/repository/components/blob_content_viewer.vue';
import '~/sourcegraph/load'; import '~/sourcegraph/load';
Vue.use(VueApollo); Vue.use(VueApollo);
Vue.use(VueRouter);
const apolloProvider = new VueApollo({ const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(), defaultClient: createDefaultClient(),
}); });
const router = new VueRouter({ mode: 'history' });
const viewBlobEl = document.querySelector('#js-view-blob-app'); const viewBlobEl = document.querySelector('#js-view-blob-app');
if (viewBlobEl) { if (viewBlobEl) {
...@@ -25,6 +29,7 @@ if (viewBlobEl) { ...@@ -25,6 +29,7 @@ if (viewBlobEl) {
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new Vue({ new Vue({
el: viewBlobEl, el: viewBlobEl,
router,
apolloProvider, apolloProvider,
provide: { provide: {
targetBranch, targetBranch,
......
...@@ -20,10 +20,9 @@ export default { ...@@ -20,10 +20,9 @@ export default {
v-for="line in lines" v-for="line in lines"
:id="`L${line}`" :id="`L${line}`"
:key="line" :key="line"
class="diff-line-num" class="diff-line-num gl-shadow-none!"
:href="`#LC${line}`" :to="`#LC${line}`"
:data-line-number="line" :data-line-number="line"
@click="$emit('select-line', `#LC${line}`)"
> >
<gl-icon :size="12" name="link" /> <gl-icon :size="12" name="link" />
{{ line }} {{ line }}
......
...@@ -56,6 +56,9 @@ export default { ...@@ -56,6 +56,9 @@ export default {
highlightedContent() { highlightedContent() {
this.$nextTick(() => this.selectLine()); this.$nextTick(() => this.selectLine());
}, },
$route() {
this.selectLine();
},
}, },
async mounted() { async mounted() {
this.hljs = await this.loadHighlightJS(); this.hljs = await this.loadHighlightJS();
...@@ -90,7 +93,8 @@ export default { ...@@ -90,7 +93,8 @@ export default {
.join('\r\n') .join('\r\n')
); );
}, },
selectLine(hash = sanitize(window.location.hash)) { selectLine() {
const hash = sanitize(this.$route.hash);
const lineToSelect = hash && this.$el.querySelector(hash); const lineToSelect = hash && this.$el.querySelector(hash);
if (!lineToSelect) { if (!lineToSelect) {
...@@ -112,7 +116,7 @@ export default { ...@@ -112,7 +116,7 @@ export default {
</script> </script>
<template> <template>
<div class="file-content code js-syntax-highlight" :class="$options.userColorScheme"> <div class="file-content code js-syntax-highlight" :class="$options.userColorScheme">
<line-numbers :lines="lineNumbers" @select-line="selectLine" /> <line-numbers :lines="lineNumbers" />
<pre class="code"><code v-safe-html="highlightedContent"></code> <pre class="code"><code v-safe-html="highlightedContent"></code>
</pre> </pre>
</div> </div>
......
import Vue from 'vue'; import Vue from 'vue';
import VueRouter from 'vue-router';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
...@@ -16,6 +17,8 @@ import { ...@@ -16,6 +17,8 @@ import {
} from 'jest/repository/mock_data'; } from 'jest/repository/mock_data';
jest.mock('~/lib/utils/common_utils'); jest.mock('~/lib/utils/common_utils');
Vue.use(VueRouter);
const router = new VueRouter();
let wrapper; let wrapper;
let mockResolver; let mockResolver;
...@@ -53,6 +56,7 @@ const createComponent = async (mockData = {}) => { ...@@ -53,6 +56,7 @@ const createComponent = async (mockData = {}) => {
const fakeApollo = createMockApollo([[blobInfoQuery, mockResolver]]); const fakeApollo = createMockApollo([[blobInfoQuery, mockResolver]]);
wrapper = mountExtended(BlobContentViewer, { wrapper = mountExtended(BlobContentViewer, {
router,
apolloProvider: fakeApollo, apolloProvider: fakeApollo,
propsData: { propsData: {
...propsMock, ...propsMock,
......
...@@ -23,7 +23,7 @@ describe('Line Numbers component', () => { ...@@ -23,7 +23,7 @@ describe('Line Numbers component', () => {
expect(findLineNumbers().length).toBe(lines); expect(findLineNumbers().length).toBe(lines);
expect(findFirstLineNumber().attributes()).toMatchObject({ expect(findFirstLineNumber().attributes()).toMatchObject({
id: 'L1', id: 'L1',
href: '#LC1', to: '#LC1',
}); });
}); });
...@@ -34,15 +34,4 @@ describe('Line Numbers component', () => { ...@@ -34,15 +34,4 @@ describe('Line Numbers component', () => {
}); });
}); });
}); });
describe('clicking a line number', () => {
beforeEach(() => {
jest.spyOn(wrapper.vm, '$emit');
findFirstLineNumber().vm.$emit('click');
});
it('emits a select-line event', () => {
expect(wrapper.vm.$emit).toHaveBeenCalledWith('select-line', '#LC1');
});
});
}); });
import hljs from 'highlight.js/lib/core'; import hljs from 'highlight.js/lib/core';
import Vue, { nextTick } from 'vue';
import VueRouter from 'vue-router';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import SourceViewer from '~/vue_shared/components/source_viewer.vue'; import SourceViewer from '~/vue_shared/components/source_viewer.vue';
import LineNumbers from '~/vue_shared/components/line_numbers.vue'; import LineNumbers from '~/vue_shared/components/line_numbers.vue';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
jest.mock('highlight.js/lib/core'); jest.mock('highlight.js/lib/core');
Vue.use(VueRouter);
const router = new VueRouter();
describe('Source Viewer component', () => { describe('Source Viewer component', () => {
let wrapper; let wrapper;
...@@ -16,7 +20,10 @@ describe('Source Viewer component', () => { ...@@ -16,7 +20,10 @@ describe('Source Viewer component', () => {
hljs.highlightAuto.mockImplementation(() => ({ value: highlightedContent })); hljs.highlightAuto.mockImplementation(() => ({ value: highlightedContent }));
const createComponent = async (props = {}) => { const createComponent = async (props = {}) => {
wrapper = shallowMountExtended(SourceViewer, { propsData: { content, language, ...props } }); wrapper = shallowMountExtended(SourceViewer, {
router,
propsData: { content, language, ...props },
});
await waitForPromises(); await waitForPromises();
}; };
...@@ -69,16 +76,18 @@ describe('Source Viewer component', () => { ...@@ -69,16 +76,18 @@ describe('Source Viewer component', () => {
jest.spyOn(firstLineElement, 'scrollIntoView'); jest.spyOn(firstLineElement, 'scrollIntoView');
jest.spyOn(firstLineElement.classList, 'add'); jest.spyOn(firstLineElement.classList, 'add');
jest.spyOn(firstLineElement.classList, 'remove'); jest.spyOn(firstLineElement.classList, 'remove');
findLineNumbers().vm.$emit('select-line', '#LC1');
}); });
it('adds the highlight (hll) class', () => { it('adds the highlight (hll) class', async () => {
wrapper.vm.$router.push('#LC1');
await nextTick();
expect(firstLineElement.classList.add).toHaveBeenCalledWith('hll'); expect(firstLineElement.classList.add).toHaveBeenCalledWith('hll');
}); });
it('removes the highlight (hll) class from a previously highlighted line', () => { it('removes the highlight (hll) class from a previously highlighted line', async () => {
findLineNumbers().vm.$emit('select-line', '#LC2'); wrapper.vm.$router.push('#LC2');
await nextTick();
expect(firstLineElement.classList.remove).toHaveBeenCalledWith('hll'); expect(firstLineElement.classList.remove).toHaveBeenCalledWith('hll');
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment