From d4db946c31dbeaf636a2a296596f76e1005af000 Mon Sep 17 00:00:00 2001 From: Alexander Skvortsov <38059171+askvortsov1@users.noreply.github.com> Date: Fri, 26 Feb 2021 16:20:07 -0500 Subject: [PATCH] Update for Editor Drivers Abstraction (#61) --- extensions/mentions/js/package-lock.json | 7 +- extensions/mentions/js/package.json | 1 - .../js/src/forum/addComposerAutocomplete.js | 84 +++++++++++-------- .../mentions/js/src/forum/utils/reply.js | 3 +- 4 files changed, 50 insertions(+), 45 deletions(-) diff --git a/extensions/mentions/js/package-lock.json b/extensions/mentions/js/package-lock.json index 520aed2ba..043b71521 100644 --- a/extensions/mentions/js/package-lock.json +++ b/extensions/mentions/js/package-lock.json @@ -3445,7 +3445,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { "ret": "~0.1.10" @@ -3839,11 +3839,6 @@ } } }, - "textarea-caret": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/textarea-caret/-/textarea-caret-3.1.0.tgz", - "integrity": "sha512-cXAvzO9pP5CGa6NKx0WYHl+8CHKZs8byMkt3PCJBCmq2a34YA9pO1NrQET5pzeqnBjBdToF5No4rrmkDUgQC2Q==" - }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", diff --git a/extensions/mentions/js/package.json b/extensions/mentions/js/package.json index ad8f13743..55e047cf8 100644 --- a/extensions/mentions/js/package.json +++ b/extensions/mentions/js/package.json @@ -3,7 +3,6 @@ "name": "@flarum/mentions", "dependencies": { "flarum-webpack-config": "0.1.0-beta.10", - "textarea-caret": "^3.1.0", "webpack": "^4.43.0", "webpack-cli": "^3.3.11" }, diff --git a/extensions/mentions/js/src/forum/addComposerAutocomplete.js b/extensions/mentions/js/src/forum/addComposerAutocomplete.js index da9f9b48d..53c32d95b 100644 --- a/extensions/mentions/js/src/forum/addComposerAutocomplete.js +++ b/extensions/mentions/js/src/forum/addComposerAutocomplete.js @@ -1,5 +1,3 @@ -import getCaretCoordinates from 'textarea-caret'; - import { extend } from 'flarum/extend'; import TextEditor from 'flarum/components/TextEditor'; import TextEditorButton from 'flarum/components/TextEditorButton'; @@ -14,12 +12,28 @@ import { truncate } from 'flarum/utils/string'; import AutocompleteDropdown from './fragments/AutocompleteDropdown'; export default function addComposerAutocomplete() { - extend(TextEditor.prototype, 'oncreate', function () { - const $container = $('
'); - const dropdown = new AutocompleteDropdown(); - const $textarea = this.$('textarea').wrap('
'); + const $container = $('
'); + const dropdown = new AutocompleteDropdown(); + + extend(TextEditor.prototype, 'oncreate', function (params) { + const $editor = this.$('.TextEditor-editor').wrap('
'); + + this.navigator = new KeyboardNavigatable(); + this.navigator + .when(() => dropdown.active) + .onUp(() => dropdown.navigate(-1)) + .onDown(() => dropdown.navigate(1)) + .onSelect(dropdown.complete.bind(dropdown)) + .onCancel(dropdown.hide.bind(dropdown)) + .bindTo($editor); + + $editor.after($container); + }); + + extend(TextEditor.prototype, 'buildEditorParams', function (params) { const searched = []; - let mentionStart; + let relMentionStart; + let absMentionStart; let typed; let searchTimeout; @@ -30,38 +44,27 @@ export default function addComposerAutocomplete() { const returnedUserIds = new Set(returnedUsers.map(u => u.id())); const applySuggestion = (replacement) => { - app.composer.editor.replaceBeforeCursor(mentionStart - 1, replacement + ' '); + app.composer.editor.replaceBeforeCursor(absMentionStart - 1, replacement + ' '); dropdown.hide(); }; - this.navigator = new KeyboardNavigatable(); - this.navigator - .when(() => dropdown.active) - .onUp(() => dropdown.navigate(-1)) - .onDown(() => dropdown.navigate(1)) - .onSelect(dropdown.complete.bind(dropdown)) - .onCancel(dropdown.hide.bind(dropdown)) - .bindTo($textarea); + params.inputListeners.push(function(e) { + const selection = app.composer.editor.getSelectionRange(); - $textarea - .after($container) - .on('click keyup input', function(e) { - // Up, down, enter, tab, escape, left, right. - if ([9, 13, 27, 40, 38, 37, 39].indexOf(e.which) !== -1) return; + const cursor = selection[0]; - const cursor = this.selectionStart; - - if (this.selectionEnd - cursor > 0) return; + if (selection[1] - cursor > 0) return; // Search backwards from the cursor for an '@' symbol. If we find one, // we will want to show the autocomplete dropdown! - const value = this.value; - mentionStart = 0; - for (let i = cursor - 1; i >= cursor - 30; i--) { - const character = value.substr(i, 1); - if (character === '@') { - mentionStart = i + 1; + const lastChunk = app.composer.editor.getLastNChars(30); + absMentionStart = 0; + for (let i = lastChunk.length - 1; i >= 0; i--) { + const character = lastChunk.substr(i, 1); + if (character === '@' && (i == 0 || /\s/.test(lastChunk.substr(i - 1, 1)))) { + relMentionStart = i + 1; + absMentionStart = cursor - lastChunk.length + i + 1; break; } } @@ -69,8 +72,8 @@ export default function addComposerAutocomplete() { dropdown.hide(); dropdown.active = false; - if (mentionStart) { - typed = value.substring(mentionStart, cursor).toLowerCase(); + if (absMentionStart) { + typed = lastChunk.substring(relMentionStart).toLowerCase(); const makeSuggestion = function(user, replacement, content, className = '') { const username = usernameHelper(user); @@ -100,7 +103,7 @@ export default function addComposerAutocomplete() { user.displayName() ]; - return names.some(value => value.toLowerCase().substr(0, typed.length) === typed); + return names.some(name => name.toLowerCase().substr(0, typed.length) === typed); }; const buildSuggestions = () => { @@ -153,18 +156,25 @@ export default function addComposerAutocomplete() { m.render($container[0], dropdown.render()); dropdown.show(); - const coordinates = getCaretCoordinates(this, mentionStart); + const coordinates = app.composer.editor.getCaretCoordinates(absMentionStart); const width = dropdown.$().outerWidth(); const height = dropdown.$().outerHeight(); const parent = dropdown.$().offsetParent(); let left = coordinates.left; - let top = coordinates.top - this.scrollTop + 15; + let top = coordinates.top + 15; + + // Keep the dropdown inside the editor. if (top + height > parent.height()) { - top = coordinates.top - this.scrollTop - height - 15; + top = coordinates.top - height - 15; } if (left + width > parent.width()) { left = parent.width() - width; } + + // Prevent the dropdown from going off screen on mobile + top = Math.max(-parent.offset().top, top); + left = Math.max(-parent.offset().left, left); + dropdown.show(left, top); } else { dropdown.active = false; @@ -205,7 +215,7 @@ export default function addComposerAutocomplete() { extend(TextEditor.prototype, 'toolbarItems', function(items) { items.add('mention', ( - this.attrs.composer.editor.insertAtCursor('@')} icon="fas fa-at"> + this.attrs.composer.editor.insertAtCursor(' @')} icon="fas fa-at"> {app.translator.trans('flarum-mentions.forum.composer.mention_tooltip')} )); diff --git a/extensions/mentions/js/src/forum/utils/reply.js b/extensions/mentions/js/src/forum/utils/reply.js index 705159728..e9fc5d3a2 100644 --- a/extensions/mentions/js/src/forum/utils/reply.js +++ b/extensions/mentions/js/src/forum/utils/reply.js @@ -20,7 +20,8 @@ function insertMention(post, composer, quote) { Array(precedingNewlines).join('\n') + // Insert up to two newlines, depending on preceding whitespace (quote ? '> ' + mention + quote.trim().replace(/\n/g, '\n> ') + '\n\n' - : mention) + : mention), + false ); }