summaryrefslogtreecommitdiff
path: root/app/assets/javascripts
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-10-24 06:07:07 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-10-24 06:07:07 +0000
commit12287a65b735d784cda3555d1b261e50b461b29e (patch)
treee7539b1b3672986a4f41b544f913ee120d623d44 /app/assets/javascripts
parent24ed154fa81265f47bcfbecfcb331f82a5faad0d (diff)
downloadgitlab-ce-12287a65b735d784cda3555d1b261e50b461b29e.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r--app/assets/javascripts/blob/blob_utils.js5
-rw-r--r--app/assets/javascripts/blob/viewer/index.js58
-rw-r--r--app/assets/javascripts/blob_edit/edit_blob.js20
3 files changed, 61 insertions, 22 deletions
diff --git a/app/assets/javascripts/blob/blob_utils.js b/app/assets/javascripts/blob/blob_utils.js
new file mode 100644
index 00000000000..27fcc7f7b79
--- /dev/null
+++ b/app/assets/javascripts/blob/blob_utils.js
@@ -0,0 +1,5 @@
+// capture anything starting with http:// or https://
+// up until a disallowed character or whitespace
+export const blobLinkRegex = /https?:\/\/[^"<>\\^`{|}\s]+/g;
+
+export default { blobLinkRegex };
diff --git a/app/assets/javascripts/blob/viewer/index.js b/app/assets/javascripts/blob/viewer/index.js
index 07e4dde41d9..f032c2f216b 100644
--- a/app/assets/javascripts/blob/viewer/index.js
+++ b/app/assets/javascripts/blob/viewer/index.js
@@ -4,6 +4,10 @@ import Flash from '../../flash';
import { handleLocationHash } from '../../lib/utils/common_utils';
import axios from '../../lib/utils/axios_utils';
import { __ } from '~/locale';
+import { blobLinkRegex } from '~/blob/blob_utils';
+
+const SIMPLE_VIEWER_NAME = 'simple';
+const RICH_VIEWER_NAME = 'rich';
export default class BlobViewer {
constructor() {
@@ -21,7 +25,7 @@ export default class BlobViewer {
}
static initRichViewer() {
- const viewer = document.querySelector('.blob-viewer[data-type="rich"]');
+ const viewer = document.querySelector(`.blob-viewer[data-type="${RICH_VIEWER_NAME}"]`);
if (!viewer || !viewer.dataset.richType) return;
const initViewer = promise =>
@@ -61,8 +65,12 @@ export default class BlobViewer {
this.switcherBtns = document.querySelectorAll('.js-blob-viewer-switch-btn');
this.copySourceBtn = document.querySelector('.js-copy-blob-source-btn');
- this.simpleViewer = this.$fileHolder[0].querySelector('.blob-viewer[data-type="simple"]');
- this.richViewer = this.$fileHolder[0].querySelector('.blob-viewer[data-type="rich"]');
+ this.simpleViewer = this.$fileHolder[0].querySelector(
+ `.blob-viewer[data-type="${SIMPLE_VIEWER_NAME}"]`,
+ );
+ this.richViewer = this.$fileHolder[0].querySelector(
+ `.blob-viewer[data-type="${RICH_VIEWER_NAME}"]`,
+ );
this.initBindings();
@@ -71,10 +79,10 @@ export default class BlobViewer {
switchToInitialViewer() {
const initialViewer = this.$fileHolder[0].querySelector('.blob-viewer:not(.hidden)');
- let initialViewerName = initialViewer.getAttribute('data-type');
+ let initialViewerName = initialViewer.dataset.type;
if (this.switcher && window.location.hash.indexOf('#L') === 0) {
- initialViewerName = 'simple';
+ initialViewerName = SIMPLE_VIEWER_NAME;
}
this.switchToViewer(initialViewerName);
@@ -91,35 +99,41 @@ export default class BlobViewer {
this.copySourceBtn.addEventListener('click', () => {
if (this.copySourceBtn.classList.contains('disabled')) return this.copySourceBtn.blur();
- return this.switchToViewer('simple');
+ return this.switchToViewer(SIMPLE_VIEWER_NAME);
});
}
}
+ 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) {
const target = e.currentTarget;
e.preventDefault();
- this.switchToViewer(target.getAttribute('data-viewer'));
+ this.switchToViewer(target.dataset.viewer);
}
toggleCopyButtonState() {
if (!this.copySourceBtn) return;
- if (this.simpleViewer.getAttribute('data-loaded')) {
- this.copySourceBtn.setAttribute('title', __('Copy file contents'));
+ if (this.simpleViewer.dataset.loaded) {
+ this.copySourceBtn.dataset.title = __('Copy file contents');
this.copySourceBtn.classList.remove('disabled');
} else if (this.activeViewer === this.simpleViewer) {
- this.copySourceBtn.setAttribute(
- 'title',
- __('Wait for the file to load to copy its contents'),
- );
+ this.copySourceBtn.dataset.title = __('Wait for the file to load to copy its contents');
this.copySourceBtn.classList.add('disabled');
} else {
- this.copySourceBtn.setAttribute(
- 'title',
- __('Switch to the source to copy the file contents'),
- );
+ this.copySourceBtn.dataset.title = __('Switch to the source to copy the file contents');
this.copySourceBtn.classList.add('disabled');
}
@@ -159,6 +173,8 @@ export default class BlobViewer {
this.$fileHolder.trigger('highlight:line');
handleLocationHash();
+ if (name === SIMPLE_VIEWER_NAME) BlobViewer.linkifyURLs(viewer);
+
this.toggleCopyButtonState();
})
.catch(() => new Flash(__('Error loading viewer')));
@@ -166,17 +182,17 @@ export default class BlobViewer {
static loadViewer(viewerParam) {
const viewer = viewerParam;
- const url = viewer.getAttribute('data-url');
+ const { url, loaded, loading } = viewer.dataset;
- if (!url || viewer.getAttribute('data-loaded') || viewer.getAttribute('data-loading')) {
+ if (!url || loaded || loading) {
return Promise.resolve(viewer);
}
- viewer.setAttribute('data-loading', 'true');
+ viewer.dataset.loading = true;
return axios.get(url).then(({ data }) => {
viewer.innerHTML = data.html;
- viewer.setAttribute('data-loaded', 'true');
+ viewer.dataset.loaded = true;
return viewer;
});
diff --git a/app/assets/javascripts/blob_edit/edit_blob.js b/app/assets/javascripts/blob_edit/edit_blob.js
index 011898a5e7a..8561f650e8f 100644
--- a/app/assets/javascripts/blob_edit/edit_blob.js
+++ b/app/assets/javascripts/blob_edit/edit_blob.js
@@ -4,7 +4,8 @@ import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import createFlash from '~/flash';
import { __ } from '~/locale';
-import TemplateSelectorMediator from '../blob/file_template_mediator';
+import { blobLinkRegex } from '~/blob/blob_utils';
+import TemplateSelectorMediator from '~/blob/file_template_mediator';
import getModeByFileExtension from '~/lib/utils/ace_utils';
import { addEditorMarkdownListeners } from '~/lib/utils/text_markdown';
@@ -17,6 +18,7 @@ export default class EditBlob {
this.initModePanesAndLinks();
this.initSoftWrap();
this.initFileSelectors();
+ this.initBlobContentLinkClickability();
}
configureAceEditor() {
@@ -89,6 +91,22 @@ export default class EditBlob {
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() {
this.isSoftWrapped = false;
this.$toggleButton = $('.soft-wrap-toggle');