Commit af036e02 authored by Jacques Erasmus's avatar Jacques Erasmus Committed by Savas Vedova

Ability to select line numbers + fix Code Intelligence

parent d4db3cf9
......@@ -12,31 +12,6 @@ export default {
required: true,
},
},
data() {
return {
currentlyHighlightedLine: null,
};
},
mounted() {
this.scrollToLine();
},
methods: {
scrollToLine(hash = window.location.hash) {
const lineToHighlight = hash && this.$el.querySelector(hash);
if (!lineToHighlight) {
return;
}
if (this.currentlyHighlightedLine) {
this.currentlyHighlightedLine.classList.remove('hll');
}
lineToHighlight.classList.add('hll');
this.currentlyHighlightedLine = lineToHighlight;
lineToHighlight.scrollIntoView({ behavior: 'smooth', block: 'center' });
},
},
};
</script>
<template>
......@@ -46,9 +21,9 @@ export default {
:id="`L${line}`"
:key="line"
class="diff-line-num"
:href="`#L${line}`"
:href="`#LC${line}`"
:data-line-number="line"
@click="scrollToLine(`#L${line}`)"
@click="$emit('select-line', `#LC${line}`)"
>
<gl-icon :size="12" name="link" />
{{ line }}
......
<script>
import { GlSafeHtmlDirective } from '@gitlab/ui';
import LineNumbers from '~/vue_shared/components/line_numbers.vue';
import { sanitize } from '~/lib/dompurify';
const LINE_SELECT_CLASS_NAME = 'hll';
export default {
components: {
......@@ -46,7 +49,12 @@ export default {
}
}
return highlightedContent;
return this.wrapLines(highlightedContent);
},
},
watch: {
highlightedContent() {
this.$nextTick(() => this.selectLine());
},
},
async mounted() {
......@@ -73,16 +81,39 @@ export default {
return languageDefinition;
},
wrapLines(content) {
return (
content &&
content
.split('\n')
.map((line, i) => `<span id="LC${i + 1}" class="line">${line}</span>`)
.join('\r\n')
);
},
selectLine(hash = sanitize(window.location.hash)) {
const lineToSelect = hash && this.$el.querySelector(hash);
if (!lineToSelect) {
return;
}
if (this.$options.currentlySelectedLine) {
this.$options.currentlySelectedLine.classList.remove(LINE_SELECT_CLASS_NAME);
}
lineToSelect.classList.add(LINE_SELECT_CLASS_NAME);
this.$options.currentlySelectedLine = lineToSelect;
lineToSelect.scrollIntoView({ behavior: 'smooth', block: 'center' });
},
},
userColorScheme: window.gon.user_color_scheme,
currentlySelectedLine: null,
};
</script>
<template>
<div class="file-content code" :class="$options.userColorScheme">
<line-numbers :lines="lineNumbers" />
<pre
class="code gl-pl-3!"
><code v-safe-html="highlightedContent" class="gl-white-space-pre-wrap!"></code>
<line-numbers :lines="lineNumbers" @select-line="selectLine" />
<pre class="code"><code v-safe-html="highlightedContent"></code>
</pre>
</div>
</template>
......@@ -13,7 +13,6 @@ describe('Line Numbers component', () => {
const findGlIcon = () => wrapper.findComponent(GlIcon);
const findLineNumbers = () => wrapper.findAllComponents(GlLink);
const findFirstLineNumber = () => findLineNumbers().at(0);
const findSecondLineNumber = () => findLineNumbers().at(1);
beforeEach(() => createComponent());
......@@ -24,7 +23,7 @@ describe('Line Numbers component', () => {
expect(findLineNumbers().length).toBe(lines);
expect(findFirstLineNumber().attributes()).toMatchObject({
id: 'L1',
href: '#L1',
href: '#LC1',
});
});
......@@ -37,35 +36,13 @@ describe('Line Numbers component', () => {
});
describe('clicking a line number', () => {
let firstLineNumber;
let firstLineNumberElement;
beforeEach(() => {
firstLineNumber = findFirstLineNumber();
firstLineNumberElement = firstLineNumber.element;
jest.spyOn(firstLineNumberElement, 'scrollIntoView');
jest.spyOn(firstLineNumberElement.classList, 'add');
jest.spyOn(firstLineNumberElement.classList, 'remove');
firstLineNumber.vm.$emit('click');
});
it('adds the highlight (hll) class', () => {
expect(firstLineNumberElement.classList.add).toHaveBeenCalledWith('hll');
jest.spyOn(wrapper.vm, '$emit');
findFirstLineNumber().vm.$emit('click');
});
it('removes the highlight (hll) class from a previously highlighted line', () => {
findSecondLineNumber().vm.$emit('click');
expect(firstLineNumberElement.classList.remove).toHaveBeenCalledWith('hll');
});
it('scrolls the line into view', () => {
expect(firstLineNumberElement.scrollIntoView).toHaveBeenCalledWith({
behavior: 'smooth',
block: 'center',
});
it('emits a select-line event', () => {
expect(wrapper.vm.$emit).toHaveBeenCalledWith('select-line', '#LC1');
});
});
});
......@@ -9,7 +9,7 @@ jest.mock('highlight.js/lib/core');
describe('Source Viewer component', () => {
let wrapper;
const content = `// Some source code`;
const highlightedContent = `<span data-testid='test-highlighted'>${content}</span>`;
const highlightedContent = `<span data-testid='test-highlighted' id='LC1'>${content}</span><span id='LC2'></span>`;
const language = 'javascript';
hljs.highlight.mockImplementation(() => ({ value: highlightedContent }));
......@@ -22,6 +22,7 @@ describe('Source Viewer component', () => {
const findLineNumbers = () => wrapper.findComponent(LineNumbers);
const findHighlightedContent = () => wrapper.findByTestId('test-highlighted');
const findFirstLine = () => wrapper.find('#LC1');
beforeEach(() => createComponent());
......@@ -56,4 +57,37 @@ describe('Source Viewer component', () => {
expect(findHighlightedContent().exists()).toBe(true);
});
});
describe('selecting a line', () => {
let firstLine;
let firstLineElement;
beforeEach(() => {
firstLine = findFirstLine();
firstLineElement = firstLine.element;
jest.spyOn(firstLineElement, 'scrollIntoView');
jest.spyOn(firstLineElement.classList, 'add');
jest.spyOn(firstLineElement.classList, 'remove');
findLineNumbers().vm.$emit('select-line', '#LC1');
});
it('adds the highlight (hll) class', () => {
expect(firstLineElement.classList.add).toHaveBeenCalledWith('hll');
});
it('removes the highlight (hll) class from a previously highlighted line', () => {
findLineNumbers().vm.$emit('select-line', '#LC2');
expect(firstLineElement.classList.remove).toHaveBeenCalledWith('hll');
});
it('scrolls the line into view', () => {
expect(firstLineElement.scrollIntoView).toHaveBeenCalledWith({
behavior: 'smooth',
block: 'center',
});
});
});
});
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