Commit 57f016b4 authored by Martin Wortschack's avatar Martin Wortschack

Merge branch 'revert-9ec74689' into 'master'

Revert "Merge branch 'mfluharty-clickable-links-in-file-view' into 'master'"

See merge request gitlab-org/gitlab!19887
parents 919608cd 399b49e8
// capture anything starting with http:// or https://
// up until a disallowed character or whitespace
export const blobLinkRegex = /https?:\/\/[^"<>\\^`{|}\s]+/g;
export default { blobLinkRegex };
...@@ -4,10 +4,6 @@ import Flash from '../../flash'; ...@@ -4,10 +4,6 @@ import Flash from '../../flash';
import { handleLocationHash } from '../../lib/utils/common_utils'; import { handleLocationHash } from '../../lib/utils/common_utils';
import axios from '../../lib/utils/axios_utils'; import axios from '../../lib/utils/axios_utils';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { blobLinkRegex } from '~/blob/blob_utils';
const SIMPLE_VIEWER_NAME = 'simple';
const RICH_VIEWER_NAME = 'rich';
export default class BlobViewer { export default class BlobViewer {
constructor() { constructor() {
...@@ -25,7 +21,7 @@ export default class BlobViewer { ...@@ -25,7 +21,7 @@ export default class BlobViewer {
} }
static initRichViewer() { static initRichViewer() {
const viewer = document.querySelector(`.blob-viewer[data-type="${RICH_VIEWER_NAME}"]`); const viewer = document.querySelector('.blob-viewer[data-type="rich"]');
if (!viewer || !viewer.dataset.richType) return; if (!viewer || !viewer.dataset.richType) return;
const initViewer = promise => const initViewer = promise =>
...@@ -65,12 +61,8 @@ export default class BlobViewer { ...@@ -65,12 +61,8 @@ export default class BlobViewer {
this.switcherBtns = document.querySelectorAll('.js-blob-viewer-switch-btn'); this.switcherBtns = document.querySelectorAll('.js-blob-viewer-switch-btn');
this.copySourceBtn = document.querySelector('.js-copy-blob-source-btn'); this.copySourceBtn = document.querySelector('.js-copy-blob-source-btn');
this.simpleViewer = this.$fileHolder[0].querySelector( this.simpleViewer = this.$fileHolder[0].querySelector('.blob-viewer[data-type="simple"]');
`.blob-viewer[data-type="${SIMPLE_VIEWER_NAME}"]`, this.richViewer = this.$fileHolder[0].querySelector('.blob-viewer[data-type="rich"]');
);
this.richViewer = this.$fileHolder[0].querySelector(
`.blob-viewer[data-type="${RICH_VIEWER_NAME}"]`,
);
this.initBindings(); this.initBindings();
...@@ -79,10 +71,10 @@ export default class BlobViewer { ...@@ -79,10 +71,10 @@ export default class BlobViewer {
switchToInitialViewer() { switchToInitialViewer() {
const initialViewer = this.$fileHolder[0].querySelector('.blob-viewer:not(.hidden)'); const initialViewer = this.$fileHolder[0].querySelector('.blob-viewer:not(.hidden)');
let initialViewerName = initialViewer.dataset.type; let initialViewerName = initialViewer.getAttribute('data-type');
if (this.switcher && window.location.hash.indexOf('#L') === 0) { if (this.switcher && window.location.hash.indexOf('#L') === 0) {
initialViewerName = SIMPLE_VIEWER_NAME; initialViewerName = 'simple';
} }
this.switchToViewer(initialViewerName); this.switchToViewer(initialViewerName);
...@@ -99,41 +91,35 @@ export default class BlobViewer { ...@@ -99,41 +91,35 @@ export default class BlobViewer {
this.copySourceBtn.addEventListener('click', () => { this.copySourceBtn.addEventListener('click', () => {
if (this.copySourceBtn.classList.contains('disabled')) return this.copySourceBtn.blur(); if (this.copySourceBtn.classList.contains('disabled')) return this.copySourceBtn.blur();
return this.switchToViewer(SIMPLE_VIEWER_NAME); return this.switchToViewer('simple');
}); });
} }
} }
static linkifyURLs(viewer) {
if (viewer.dataset.linkified) return;
document.querySelectorAll('.js-blob-content .code .line').forEach(line => {
// eslint-disable-next-line no-param-reassign
line.innerHTML = line.innerHTML.replace(blobLinkRegex, '<a href="$&">$&</a>');
});
// eslint-disable-next-line no-param-reassign
viewer.dataset.linkified = true;
}
switchViewHandler(e) { switchViewHandler(e) {
const target = e.currentTarget; const target = e.currentTarget;
e.preventDefault(); e.preventDefault();
this.switchToViewer(target.dataset.viewer); this.switchToViewer(target.getAttribute('data-viewer'));
} }
toggleCopyButtonState() { toggleCopyButtonState() {
if (!this.copySourceBtn) return; if (!this.copySourceBtn) return;
if (this.simpleViewer.dataset.loaded) { if (this.simpleViewer.getAttribute('data-loaded')) {
this.copySourceBtn.dataset.title = __('Copy file contents'); this.copySourceBtn.setAttribute('title', __('Copy file contents'));
this.copySourceBtn.classList.remove('disabled'); this.copySourceBtn.classList.remove('disabled');
} else if (this.activeViewer === this.simpleViewer) { } else if (this.activeViewer === this.simpleViewer) {
this.copySourceBtn.dataset.title = __('Wait for the file to load to copy its contents'); this.copySourceBtn.setAttribute(
'title',
__('Wait for the file to load to copy its contents'),
);
this.copySourceBtn.classList.add('disabled'); this.copySourceBtn.classList.add('disabled');
} else { } else {
this.copySourceBtn.dataset.title = __('Switch to the source to copy the file contents'); this.copySourceBtn.setAttribute(
'title',
__('Switch to the source to copy the file contents'),
);
this.copySourceBtn.classList.add('disabled'); this.copySourceBtn.classList.add('disabled');
} }
...@@ -173,8 +159,6 @@ export default class BlobViewer { ...@@ -173,8 +159,6 @@ export default class BlobViewer {
this.$fileHolder.trigger('highlight:line'); this.$fileHolder.trigger('highlight:line');
handleLocationHash(); handleLocationHash();
if (name === SIMPLE_VIEWER_NAME) BlobViewer.linkifyURLs(viewer);
this.toggleCopyButtonState(); this.toggleCopyButtonState();
}) })
.catch(() => new Flash(__('Error loading viewer'))); .catch(() => new Flash(__('Error loading viewer')));
...@@ -182,17 +166,17 @@ export default class BlobViewer { ...@@ -182,17 +166,17 @@ export default class BlobViewer {
static loadViewer(viewerParam) { static loadViewer(viewerParam) {
const viewer = viewerParam; const viewer = viewerParam;
const { url, loaded, loading } = viewer.dataset; const url = viewer.getAttribute('data-url');
if (!url || loaded || loading) { if (!url || viewer.getAttribute('data-loaded') || viewer.getAttribute('data-loading')) {
return Promise.resolve(viewer); return Promise.resolve(viewer);
} }
viewer.dataset.loading = true; viewer.setAttribute('data-loading', 'true');
return axios.get(url).then(({ data }) => { return axios.get(url).then(({ data }) => {
viewer.innerHTML = data.html; viewer.innerHTML = data.html;
viewer.dataset.loaded = true; viewer.setAttribute('data-loaded', 'true');
return viewer; return viewer;
}); });
......
...@@ -4,8 +4,7 @@ import $ from 'jquery'; ...@@ -4,8 +4,7 @@ import $ from 'jquery';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { blobLinkRegex } from '~/blob/blob_utils'; import TemplateSelectorMediator from '../blob/file_template_mediator';
import TemplateSelectorMediator from '~/blob/file_template_mediator';
import getModeByFileExtension from '~/lib/utils/ace_utils'; import getModeByFileExtension from '~/lib/utils/ace_utils';
import { addEditorMarkdownListeners } from '~/lib/utils/text_markdown'; import { addEditorMarkdownListeners } from '~/lib/utils/text_markdown';
...@@ -18,7 +17,6 @@ export default class EditBlob { ...@@ -18,7 +17,6 @@ export default class EditBlob {
this.initModePanesAndLinks(); this.initModePanesAndLinks();
this.initSoftWrap(); this.initSoftWrap();
this.initFileSelectors(); this.initFileSelectors();
this.initBlobContentLinkClickability();
} }
configureAceEditor() { configureAceEditor() {
...@@ -91,22 +89,6 @@ export default class EditBlob { ...@@ -91,22 +89,6 @@ export default class EditBlob {
return this.editor.focus(); return this.editor.focus();
} }
initBlobContentLinkClickability() {
this.editor.renderer.on('afterRender', () => {
document.querySelectorAll('.ace_text-layer .ace_line > *').forEach(token => {
if (token.dataset.linkified || !token.textContent.includes('http')) return;
// eslint-disable-next-line no-param-reassign
token.innerHTML = token.innerHTML.replace(
blobLinkRegex,
'<a target="_blank" href="$&">$&</a>',
);
// eslint-disable-next-line no-param-reassign
token.dataset.linkified = true;
});
});
}
initSoftWrap() { initSoftWrap() {
this.isSoftWrapped = false; this.isSoftWrapped = false;
this.$toggleButton = $('.soft-wrap-toggle'); this.$toggleButton = $('.soft-wrap-toggle');
......
...@@ -258,17 +258,6 @@ ...@@ -258,17 +258,6 @@
} }
} }
} }
.file-editor {
.ace_underline {
text-decoration: none;
}
.ace_line a {
pointer-events: auto;
color: inherit;
}
}
} }
span.idiff { span.idiff {
......
...@@ -29,12 +29,3 @@ ...@@ -29,12 +29,3 @@
color: $link; color: $link;
} }
} }
// Links to URLs, emails, or dependencies
.code .line a {
color: inherit;
&:hover {
text-decoration: underline;
}
}
...@@ -193,6 +193,11 @@ $dark-il: #de935f; ...@@ -193,6 +193,11 @@ $dark-il: #de935f;
color: $dark-highlight-color !important; color: $dark-highlight-color !important;
} }
// Links to URLs, emails, or dependencies
.line a {
color: $dark-na;
}
.hll { background-color: $dark-hll-bg; } .hll { background-color: $dark-hll-bg; }
.c { color: $dark-c; } /* Comment */ .c { color: $dark-c; } /* Comment */
.err { color: $dark-err; } /* Error */ .err { color: $dark-err; } /* Error */
......
...@@ -193,6 +193,11 @@ $monokai-gi: #a6e22e; ...@@ -193,6 +193,11 @@ $monokai-gi: #a6e22e;
color: $black !important; color: $black !important;
} }
// Links to URLs, emails, or dependencies
.line a {
color: $monokai-k;
}
.hll { background-color: $monokai-hll; } .hll { background-color: $monokai-hll; }
.c { color: $monokai-c; } /* Comment */ .c { color: $monokai-c; } /* Comment */
.err { color: $monokai-err-color; background-color: $monokai-err-bg; } /* Error */ .err { color: $monokai-err-color; background-color: $monokai-err-bg; } /* Error */
......
...@@ -143,6 +143,12 @@ ...@@ -143,6 +143,12 @@
background-color: $white-normal; background-color: $white-normal;
} }
// Links to URLs, emails, or dependencies
.line a {
color: $gl-text-color;
text-decoration: underline;
}
.hll { background-color: $white-light; } .hll { background-color: $white-light; }
.gd { .gd {
......
...@@ -196,6 +196,11 @@ $solarized-dark-il: #2aa198; ...@@ -196,6 +196,11 @@ $solarized-dark-il: #2aa198;
background-color: $solarized-dark-highlight !important; background-color: $solarized-dark-highlight !important;
} }
// Links to URLs, emails, or dependencies
.line a {
color: $solarized-dark-kd;
}
/* Solarized Dark /* Solarized Dark
For use with Jekyll and Pygments For use with Jekyll and Pygments
......
...@@ -204,6 +204,11 @@ $solarized-light-il: #2aa198; ...@@ -204,6 +204,11 @@ $solarized-light-il: #2aa198;
background-color: $solarized-light-highlight !important; background-color: $solarized-light-highlight !important;
} }
// Links to URLs, emails, or dependencies
.line a {
color: $solarized-light-kd;
}
/* Solarized Light /* Solarized Light
For use with Jekyll and Pygments For use with Jekyll and Pygments
......
...@@ -209,6 +209,11 @@ span.highlight_word { ...@@ -209,6 +209,11 @@ span.highlight_word {
background-color: $white-highlight !important; background-color: $white-highlight !important;
} }
// Links to URLs, emails, or dependencies
.line a {
color: $white-nb;
}
.hll { background-color: $white-hll-bg; } .hll { background-color: $white-hll-bg; }
.c { color: $white-c; .c { color: $white-c;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
%a.diff-line-num{ href: "#{link}#L#{i}", id: "L#{i}", 'data-line-number' => i } %a.diff-line-num{ href: "#{link}#L#{i}", id: "L#{i}", 'data-line-number' => i }
= link_icon = link_icon
= i = i
.blob-content.js-blob-content{ data: { blob_id: blob.id } } .blob-content{ data: { blob_id: blob.id } }
%pre.code.highlight %pre.code.highlight
%code %code
= blob.present.highlight = blob.present.highlight
---
title: Make URLs in blob viewer and blob editor into clickable links
merge_request: 18305
author:
type: added
...@@ -62,13 +62,6 @@ describe 'Editing file blob', :js do ...@@ -62,13 +62,6 @@ describe 'Editing file blob', :js do
expect(page).to have_content 'NextFeature' expect(page).to have_content 'NextFeature'
end end
it 'renders a URL in the content of file as a link' do
project.repository.create_file(user, 'file.yml', '# go to https://gitlab.com', message: 'testing', branch_name: branch)
visit project_edit_blob_path(project, tree_join(branch, 'file.yml'))
expect(page).to have_selector('.ace_content .ace_line a')
end
context 'from blob file path' do context 'from blob file path' do
before do before do
visit project_blob_path(project, tree_join(branch, file_path)) visit project_blob_path(project, tree_join(branch, file_path))
......
...@@ -11,13 +11,6 @@ describe('Blob viewer', () => { ...@@ -11,13 +11,6 @@ describe('Blob viewer', () => {
preloadFixtures('snippets/show.html'); preloadFixtures('snippets/show.html');
const asyncClick = () =>
new Promise(resolve => {
document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click();
setTimeout(resolve);
});
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
...@@ -73,12 +66,19 @@ describe('Blob viewer', () => { ...@@ -73,12 +66,19 @@ describe('Blob viewer', () => {
}); });
it('doesnt reload file if already loaded', done => { it('doesnt reload file if already loaded', done => {
const asyncClick = () =>
new Promise(resolve => {
document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click();
setTimeout(resolve);
});
asyncClick() asyncClick()
.then(() => asyncClick()) .then(() => asyncClick())
.then(() => { .then(() => {
expect(document.querySelector('.blob-viewer[data-type="simple"]').dataset.loaded).toBe( expect(
'true', document.querySelector('.blob-viewer[data-type="simple"]').getAttribute('data-loaded'),
); ).toBe('true');
done(); done();
}) })
...@@ -100,7 +100,9 @@ describe('Blob viewer', () => { ...@@ -100,7 +100,9 @@ describe('Blob viewer', () => {
}); });
it('has tooltip when disabled', () => { it('has tooltip when disabled', () => {
expect(copyButton.dataset.title).toBe('Switch to the source to copy the file contents'); expect(copyButton.getAttribute('data-original-title')).toBe(
'Switch to the source to copy the file contents',
);
}); });
it('is blurred when clicked and disabled', () => { it('is blurred when clicked and disabled', () => {
...@@ -134,7 +136,7 @@ describe('Blob viewer', () => { ...@@ -134,7 +136,7 @@ describe('Blob viewer', () => {
document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click(); document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click();
setTimeout(() => { setTimeout(() => {
expect(copyButton.dataset.title).toBe('Copy file contents'); expect(copyButton.getAttribute('data-original-title')).toBe('Copy file contents');
done(); done();
}); });
...@@ -175,27 +177,4 @@ describe('Blob viewer', () => { ...@@ -175,27 +177,4 @@ describe('Blob viewer', () => {
expect(axios.get.calls.count()).toBe(1); expect(axios.get.calls.count()).toBe(1);
}); });
}); });
describe('a URL inside the blob content', () => {
beforeEach(() => {
mock.onGet('http://test.host/snippets/1.json?viewer=simple').reply(200, {
html:
'<div class="js-blob-content"><pre class="code"><code><span class="line" lang="yaml"><span class="c1">To install gitlab-shell you also need a Go compiler version 1.8 or newer. https://golang.org/dl/</span></span></code></pre></div>',
});
});
it('is rendered as a link in simple view', done => {
asyncClick()
.then(() => {
expect(document.querySelector('.blob-viewer[data-type="simple"]').innerHTML).toContain(
'<a href="https://golang.org/dl/">https://golang.org/dl/</a>',
);
done();
})
.catch(() => {
fail();
done();
});
});
});
}); });
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