mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-01-20 16:50:28 -05:00
Leave list/quote expanison with double enter
When editing a list or similar syntax elements, pressing enter starts a
new line with the line introducer (e.g. `- ` for a plain list).
But currently it's uncomfortable when someone wants to leave the list.
Pressing enter again simply adds more and more lines with the prefix.
With this change the list is terminated if enter is pressed on a line
which contains the introducer but nothing else. This behavior is known
from other markdown editors like the on used by GitLab or GitHub.
Additionally I changed the regex for detecting a prefix.
- Why: With the change you can add a single whitespace at the end if you
want to keep an "empty" line. So if you want to write:
```
- First
-
- Third
```
You just need to add a whitespace in the second line to prevent that
the prefix will be removed.
- Changes in detail:
- ordered bullet list prefix detection:
nothing changed
- todo list and unordered list prefix detection:
have been split up:
- todo list: Changed that only 1 to 4 whitespaces can be between the
list char (`-`,`*`,`+`) and the checkbox (`[ ]`,`[x]`) - Why? If
more then 4 spaces are between the list char and the checkbox,
this is no longer detected as a prefix for a todo item based on
the markdown standard. Due to the amount of spaces it is instead
parsed as code.
- unordered list: The prefix now needs to have exactly one space
after the list char (`-`,`*`,`+`). More spaces will not be taken
into account for detecting the prefix.
- quote prefix detection:
nothing changed
The current e2e-tests where simplified and duplicated tests where
removed. Test cases for the new functionality where added.
(cherry picked from commit 7ea62c5ce4
)
This commit is contained in:
parent
627634a76e
commit
348e0e1fac
2 changed files with 43 additions and 30 deletions
|
@ -109,7 +109,7 @@ test('markdown indentation', async ({page}) => {
|
|||
});
|
||||
|
||||
test('markdown list continuation', async ({page}) => {
|
||||
const initText = `* first\n* second\n* third\n* last`;
|
||||
const initText = `* first\n* second`;
|
||||
|
||||
const response = await page.goto('/user2/repo1/issues/new');
|
||||
expect(response?.status()).toBe(200);
|
||||
|
@ -120,24 +120,19 @@ test('markdown list continuation', async ({page}) => {
|
|||
await textarea.fill(initText);
|
||||
|
||||
// Test continuation of ' * ' prefix
|
||||
await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.indexOf('cond'), it.value.indexOf('cond')));
|
||||
await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.indexOf('rst'), it.value.indexOf('rst')));
|
||||
await indent.click();
|
||||
await textarea.press('End');
|
||||
await textarea.press('Enter');
|
||||
await textarea.pressSequentially('middle');
|
||||
await expect(textarea).toHaveValue(`* first\n* second\n* middle\n* third\n* last`);
|
||||
|
||||
// Test continuation of ' * ' prefix
|
||||
await indent.click();
|
||||
await textarea.press('Enter');
|
||||
await textarea.pressSequentially('muddle');
|
||||
await expect(textarea).toHaveValue(`* first\n* second\n${tab}* middle\n${tab}* muddle\n* third\n* last`);
|
||||
await expect(textarea).toHaveValue(`${tab}* first\n${tab}* muddle\n* second`);
|
||||
|
||||
// Test breaking in the middle of a line
|
||||
await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.lastIndexOf('ddle'), it.value.lastIndexOf('ddle')));
|
||||
await textarea.pressSequentially('tate');
|
||||
await textarea.press('Enter');
|
||||
await textarea.pressSequentially('me');
|
||||
await expect(textarea).toHaveValue(`* first\n* second\n${tab}* middle\n${tab}* mutate\n${tab}* meddle\n* third\n* last`);
|
||||
await expect(textarea).toHaveValue(`${tab}* first\n${tab}* mutate\n${tab}* meddle\n* second`);
|
||||
|
||||
// Test not triggering when Shift held
|
||||
await textarea.fill(initText);
|
||||
|
@ -145,28 +140,29 @@ test('markdown list continuation', async ({page}) => {
|
|||
await textarea.press('Shift+Enter');
|
||||
await textarea.press('Enter');
|
||||
await textarea.pressSequentially('...but not least');
|
||||
await expect(textarea).toHaveValue(`* first\n* second\n* third\n* last\n\n...but not least`);
|
||||
await expect(textarea).toHaveValue(`* first\n* second\n\n...but not least`);
|
||||
|
||||
// Test continuation of ordered list
|
||||
await textarea.fill(`1. one\n2. two`);
|
||||
await textarea.fill(`1. one`);
|
||||
await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.length, it.value.length));
|
||||
await textarea.press('Enter');
|
||||
await textarea.pressSequentially(' ');
|
||||
await textarea.press('Enter');
|
||||
await textarea.pressSequentially('three');
|
||||
await expect(textarea).toHaveValue(`1. one\n2. two\n3. three`);
|
||||
await textarea.press('Enter');
|
||||
await textarea.press('Enter');
|
||||
await expect(textarea).toHaveValue(`1. one\n2. \n3. three\n\n`);
|
||||
|
||||
// Test continuation of alternative ordered list syntax
|
||||
await textarea.fill(`1) one\n2) two`);
|
||||
await textarea.fill(`1) one`);
|
||||
await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.length, it.value.length));
|
||||
await textarea.press('Enter');
|
||||
await textarea.pressSequentially(' ');
|
||||
await textarea.press('Enter');
|
||||
await textarea.pressSequentially('three');
|
||||
await expect(textarea).toHaveValue(`1) one\n2) two\n3) three`);
|
||||
|
||||
// Test continuation of blockquote
|
||||
await textarea.fill(`> knowledge is power`);
|
||||
await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.length, it.value.length));
|
||||
await textarea.press('Enter');
|
||||
await textarea.pressSequentially('france is bacon');
|
||||
await expect(textarea).toHaveValue(`> knowledge is power\n> france is bacon`);
|
||||
await textarea.press('Enter');
|
||||
await expect(textarea).toHaveValue(`1) one\n2) \n3) three\n\n`);
|
||||
|
||||
// Test continuation of checklists
|
||||
await textarea.fill(`- [ ]have a problem\n- [x]create a solution`);
|
||||
|
@ -189,7 +185,6 @@ test('markdown list continuation', async ({page}) => {
|
|||
'> ',
|
||||
'> > ',
|
||||
'- [ ] ',
|
||||
'- [ ]', // This does seem to render, so allow.
|
||||
'* [ ] ',
|
||||
'+ [ ] ',
|
||||
];
|
||||
|
@ -197,8 +192,12 @@ test('markdown list continuation', async ({page}) => {
|
|||
await textarea.fill(`${prefix}one`);
|
||||
await textarea.evaluate((it:HTMLTextAreaElement) => it.setSelectionRange(it.value.length, it.value.length));
|
||||
await textarea.press('Enter');
|
||||
await textarea.pressSequentially(' ');
|
||||
await textarea.press('Enter');
|
||||
await textarea.pressSequentially('two');
|
||||
await expect(textarea).toHaveValue(`${prefix}one\n${prefix}two`);
|
||||
await textarea.press('Enter');
|
||||
await textarea.press('Enter');
|
||||
await expect(textarea).toHaveValue(`${prefix}one\n${prefix} \n${prefix}two\n\n`);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -409,13 +409,27 @@ class ComboMarkdownEditor {
|
|||
// Find the beginning of the current line.
|
||||
const lineStart = Math.max(0, value.lastIndexOf('\n', start - 1) + 1);
|
||||
// Find the end and extract the line.
|
||||
const lineEnd = value.indexOf('\n', start);
|
||||
const line = value.slice(lineStart, lineEnd === -1 ? value.length : lineEnd);
|
||||
const nextLF = value.indexOf('\n', start);
|
||||
const lineEnd = nextLF === -1 ? value.length : nextLF;
|
||||
const line = value.slice(lineStart, lineEnd);
|
||||
// Match any whitespace at the start + any repeatable prefix + exactly one space after.
|
||||
const prefix = line.match(/^\s*((\d+)[.)]\s|[-*+]\s+(\[[ x]\]\s?)?|(>\s+)+)?/);
|
||||
const prefix = line.match(/^\s*((\d+)[.)]\s|[-*+]\s{1,4}\[[ x]\]\s?|[-*+]\s|(>\s?)+)?/);
|
||||
|
||||
// Defer to browser if we can't do anything more useful, or if the cursor is inside the prefix.
|
||||
if (!prefix || !prefix[0].length || lineStart + prefix[0].length > start) return false;
|
||||
if (!prefix) return false;
|
||||
const prefixLength = prefix[0].length;
|
||||
if (!prefixLength || lineStart + prefixLength > start) return false;
|
||||
// If the prefix is just indentation (which should always be an even number of spaces or tabs), check if a single whitespace is added to the end of the line.
|
||||
// If this is the case do not leave the indentation and continue with the prefix.
|
||||
if ((prefixLength % 2 === 1 && /^ +$/.test(prefix[0])) || /^\t+ $/.test(prefix[0])) {
|
||||
prefix[0] = prefix[0].slice(0, prefixLength - 1);
|
||||
} else if (prefixLength === lineEnd - lineStart) {
|
||||
this.textarea.setSelectionRange(lineStart, lineEnd);
|
||||
if (!document.execCommand('insertText', false, '\n')) {
|
||||
this.textarea.setRangeText('\n');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Insert newline + prefix.
|
||||
let text = `\n${prefix[0]}`;
|
||||
|
|
Loading…
Add table
Reference in a new issue