debian-mirror-gitlab/app/assets/javascripts/lib/utils/text_markdown.js

196 lines
5.5 KiB
JavaScript
Raw Normal View History

2018-12-13 13:39:08 +05:30
/* eslint-disable func-names, no-var, no-param-reassign, one-var, operator-assignment, no-else-return, prefer-template, prefer-arrow-callback, consistent-return, no-unused-vars */
2018-05-09 12:01:36 +05:30
import $ from 'jquery';
import { insertText } from '~/lib/utils/common_utils';
2018-03-17 18:26:18 +05:30
2018-12-13 13:39:08 +05:30
const LINK_TAG_PATTERN = '[{text}](url)';
2018-05-09 12:01:36 +05:30
function selectedText(text, textarea) {
2018-03-17 18:26:18 +05:30
return text.substring(textarea.selectionStart, textarea.selectionEnd);
2018-05-09 12:01:36 +05:30
}
2018-03-17 18:26:18 +05:30
2018-05-09 12:01:36 +05:30
function lineBefore(text, textarea) {
2018-03-17 18:26:18 +05:30
var split;
2018-12-13 13:39:08 +05:30
split = text
.substring(0, textarea.selectionStart)
.trim()
.split('\n');
2018-03-17 18:26:18 +05:30
return split[split.length - 1];
2018-05-09 12:01:36 +05:30
}
2018-03-17 18:26:18 +05:30
2018-05-09 12:01:36 +05:30
function lineAfter(text, textarea) {
2018-12-13 13:39:08 +05:30
return text
.substring(textarea.selectionEnd)
.trim()
.split('\n')[0];
2018-05-09 12:01:36 +05:30
}
2018-03-17 18:26:18 +05:30
2018-05-09 12:01:36 +05:30
function blockTagText(text, textArea, blockTag, selected) {
const before = lineBefore(text, textArea);
const after = lineAfter(text, textArea);
if (before === blockTag && after === blockTag) {
2018-03-17 18:26:18 +05:30
// To remove the block tag we have to select the line before & after
if (blockTag != null) {
textArea.selectionStart = textArea.selectionStart - (blockTag.length + 1);
textArea.selectionEnd = textArea.selectionEnd + (blockTag.length + 1);
}
return selected;
} else {
2018-12-13 13:39:08 +05:30
return blockTag + '\n' + selected + '\n' + blockTag;
2018-03-17 18:26:18 +05:30
}
2018-05-09 12:01:36 +05:30
}
2019-01-03 12:48:30 +05:30
function moveCursor({ textArea, tag, wrapped, removedLastNewLine, select }) {
2018-05-09 12:01:36 +05:30
var pos;
if (!textArea.setSelectionRange) {
return;
}
2018-12-05 23:21:45 +05:30
if (select && select.length > 0) {
// calculate the part of the text to be selected
const startPosition = textArea.selectionStart - (tag.length - tag.indexOf(select));
const endPosition = startPosition + select.length;
return textArea.setSelectionRange(startPosition, endPosition);
}
2018-05-09 12:01:36 +05:30
if (textArea.selectionStart === textArea.selectionEnd) {
2019-01-03 12:48:30 +05:30
if (wrapped) {
2018-05-09 12:01:36 +05:30
pos = textArea.selectionStart - tag.length;
} else {
pos = textArea.selectionStart;
}
if (removedLastNewLine) {
pos -= 1;
}
return textArea.setSelectionRange(pos, pos);
}
}
2018-03-17 18:26:18 +05:30
2019-01-03 12:48:30 +05:30
export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select }) {
2018-12-13 13:39:08 +05:30
var textToInsert,
2019-01-03 12:48:30 +05:30
inserted,
2018-12-13 13:39:08 +05:30
selectedSplit,
startChar,
removedLastNewLine,
removedFirstNewLine,
currentLineEmpty,
lastNewLine;
2018-03-17 18:26:18 +05:30
removedLastNewLine = false;
removedFirstNewLine = false;
currentLineEmpty = false;
2018-12-13 13:39:08 +05:30
// check for link pattern and selected text is an URL
// if so fill in the url part instead of the text part of the pattern.
if (tag === LINK_TAG_PATTERN) {
if (URL) {
try {
const ignoredUrl = new URL(selected);
// valid url
tag = '[text]({text})';
select = 'text';
} catch (e) {
// ignore - no valid url
}
}
}
2018-03-17 18:26:18 +05:30
// Remove the first newline
if (selected.indexOf('\n') === 0) {
removedFirstNewLine = true;
selected = selected.replace(/\n+/, '');
}
// Remove the last newline
if (textArea.selectionEnd - textArea.selectionStart > selected.replace(/\n$/, '').length) {
removedLastNewLine = true;
selected = selected.replace(/\n$/, '');
}
selectedSplit = selected.split('\n');
if (!wrap) {
lastNewLine = textArea.value.substr(0, textArea.selectionStart).lastIndexOf('\n');
// Check whether the current line is empty or consists only of spaces(=handle as empty)
if (/^\s*$/.test(textArea.value.substring(lastNewLine, textArea.selectionStart))) {
currentLineEmpty = true;
}
}
startChar = !wrap && !currentLineEmpty && textArea.selectionStart > 0 ? '\n' : '';
2018-12-05 23:21:45 +05:30
const textPlaceholder = '{text}';
2018-03-17 18:26:18 +05:30
if (selectedSplit.length > 1 && (!wrap || (blockTag != null && blockTag !== ''))) {
if (blockTag != null && blockTag !== '') {
2018-05-09 12:01:36 +05:30
textToInsert = blockTagText(text, textArea, blockTag, selected);
2018-03-17 18:26:18 +05:30
} else {
2018-12-13 13:39:08 +05:30
textToInsert = selectedSplit
.map(function(val) {
if (tag.indexOf(textPlaceholder) > -1) {
return tag.replace(textPlaceholder, val);
}
if (val.indexOf(tag) === 0) {
return '' + val.replace(tag, '');
} else {
return '' + tag + val;
}
})
.join('\n');
2018-03-17 18:26:18 +05:30
}
2018-12-05 23:21:45 +05:30
} else if (tag.indexOf(textPlaceholder) > -1) {
textToInsert = tag.replace(textPlaceholder, selected);
2018-03-17 18:26:18 +05:30
} else {
2018-12-13 13:39:08 +05:30
textToInsert = '' + startChar + tag + selected + (wrap ? tag : ' ');
2018-03-17 18:26:18 +05:30
}
if (removedFirstNewLine) {
2018-05-09 12:01:36 +05:30
textToInsert = '\n' + textToInsert;
2018-03-17 18:26:18 +05:30
}
if (removedLastNewLine) {
2018-05-09 12:01:36 +05:30
textToInsert += '\n';
2018-03-17 18:26:18 +05:30
}
2018-05-09 12:01:36 +05:30
insertText(textArea, textToInsert);
2018-12-13 13:39:08 +05:30
return moveCursor({
textArea,
tag: tag.replace(textPlaceholder, selected),
2019-01-03 12:48:30 +05:30
wrap,
2018-12-13 13:39:08 +05:30
removedLastNewLine,
select,
});
2018-05-09 12:01:36 +05:30
}
2018-03-17 18:26:18 +05:30
2019-01-03 12:48:30 +05:30
function updateText({ textArea, tag, blockTag, wrap, select }) {
2018-03-17 18:26:18 +05:30
var $textArea, selected, text;
$textArea = $(textArea);
textArea = $textArea.get(0);
text = $textArea.val();
2019-01-03 12:48:30 +05:30
selected = selectedText(text, textArea);
2018-03-17 18:26:18 +05:30
$textArea.focus();
2019-01-03 12:48:30 +05:30
return insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select });
}
function replaceRange(s, start, end, substitute) {
return s.substring(0, start) + substitute + s.substring(end);
2018-05-09 12:01:36 +05:30
}
export function addMarkdownListeners(form) {
2018-12-13 13:39:08 +05:30
return $('.js-md', form)
.off('click')
.on('click', function() {
const $this = $(this);
return updateText({
textArea: $this.closest('.md-area').find('textarea'),
tag: $this.data('mdTag'),
blockTag: $this.data('mdBlock'),
wrap: !$this.data('mdPrepend'),
select: $this.data('mdSelect'),
});
});
2018-05-09 12:01:36 +05:30
}
2018-03-17 18:26:18 +05:30
2018-05-09 12:01:36 +05:30
export function removeMarkdownListeners(form) {
2018-03-17 18:26:18 +05:30
return $('.js-md', form).off('click');
2018-05-09 12:01:36 +05:30
}