Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/editor/extensions/source_editor_extension_base.js')
-rw-r--r--app/assets/javascripts/editor/extensions/source_editor_extension_base.js93
1 files changed, 93 insertions, 0 deletions
diff --git a/app/assets/javascripts/editor/extensions/source_editor_extension_base.js b/app/assets/javascripts/editor/extensions/source_editor_extension_base.js
new file mode 100644
index 00000000000..5fa01f03f7e
--- /dev/null
+++ b/app/assets/javascripts/editor/extensions/source_editor_extension_base.js
@@ -0,0 +1,93 @@
+import { Range } from 'monaco-editor';
+import { waitForCSSLoaded } from '~/helpers/startup_css_helper';
+import { ERROR_INSTANCE_REQUIRED_FOR_EXTENSION, EDITOR_TYPE_CODE } from '../constants';
+
+const hashRegexp = new RegExp('#?L', 'g');
+
+const createAnchor = (href) => {
+ const fragment = new DocumentFragment();
+ const el = document.createElement('a');
+ el.classList.add('link-anchor');
+ el.href = href;
+ fragment.appendChild(el);
+ el.addEventListener('contextmenu', (e) => {
+ e.stopPropagation();
+ });
+ return fragment;
+};
+
+export class SourceEditorExtension {
+ constructor({ instance, ...options } = {}) {
+ if (instance) {
+ Object.assign(instance, options);
+ SourceEditorExtension.highlightLines(instance);
+ if (instance.getEditorType && instance.getEditorType() === EDITOR_TYPE_CODE) {
+ SourceEditorExtension.setupLineLinking(instance);
+ }
+ SourceEditorExtension.deferRerender(instance);
+ } else if (Object.entries(options).length) {
+ throw new Error(ERROR_INSTANCE_REQUIRED_FOR_EXTENSION);
+ }
+ }
+
+ static deferRerender(instance) {
+ waitForCSSLoaded(() => {
+ instance.layout();
+ });
+ }
+
+ static highlightLines(instance) {
+ const { hash } = window.location;
+ if (!hash) {
+ return;
+ }
+ const [start, end] = hash.replace(hashRegexp, '').split('-');
+ let startLine = start ? parseInt(start, 10) : null;
+ let endLine = end ? parseInt(end, 10) : startLine;
+ if (endLine < startLine) {
+ [startLine, endLine] = [endLine, startLine];
+ }
+ if (startLine) {
+ window.requestAnimationFrame(() => {
+ instance.revealLineInCenter(startLine);
+ Object.assign(instance, {
+ lineDecorations: instance.deltaDecorations(
+ [],
+ [
+ {
+ range: new Range(startLine, 1, endLine, 1),
+ options: { isWholeLine: true, className: 'active-line-text' },
+ },
+ ],
+ ),
+ });
+ });
+ }
+ }
+
+ static onMouseMoveHandler(e) {
+ const target = e.target.element;
+ if (target.classList.contains('line-numbers')) {
+ const lineNum = e.target.position.lineNumber;
+ const hrefAttr = `#L${lineNum}`;
+ let el = target.querySelector('a');
+ if (!el) {
+ el = createAnchor(hrefAttr);
+ target.appendChild(el);
+ }
+ }
+ }
+
+ static setupLineLinking(instance) {
+ instance.onMouseMove(SourceEditorExtension.onMouseMoveHandler);
+ instance.onMouseDown((e) => {
+ const isCorrectAnchor = e.target.element.classList.contains('link-anchor');
+ if (!isCorrectAnchor) {
+ return;
+ }
+ if (instance.lineDecorations) {
+ instance.deltaDecorations(instance.lineDecorations, []);
+ }
+ });
+ }
+}