mirror of
https://github.com/flarum/core.git
synced 2025-07-27 11:40:24 +02:00
Update for Editor Drivers Abstraction (#61)
This commit is contained in:
committed by
GitHub
parent
b06f6470e7
commit
d4db946c31
7
extensions/mentions/js/package-lock.json
generated
7
extensions/mentions/js/package-lock.json
generated
@@ -3445,7 +3445,7 @@
|
|||||||
},
|
},
|
||||||
"safe-regex": {
|
"safe-regex": {
|
||||||
"version": "1.1.0",
|
"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=",
|
"integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ret": "~0.1.10"
|
"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": {
|
"through2": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
|
||||||
|
@@ -3,7 +3,6 @@
|
|||||||
"name": "@flarum/mentions",
|
"name": "@flarum/mentions",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"flarum-webpack-config": "0.1.0-beta.10",
|
"flarum-webpack-config": "0.1.0-beta.10",
|
||||||
"textarea-caret": "^3.1.0",
|
|
||||||
"webpack": "^4.43.0",
|
"webpack": "^4.43.0",
|
||||||
"webpack-cli": "^3.3.11"
|
"webpack-cli": "^3.3.11"
|
||||||
},
|
},
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
import getCaretCoordinates from 'textarea-caret';
|
|
||||||
|
|
||||||
import { extend } from 'flarum/extend';
|
import { extend } from 'flarum/extend';
|
||||||
import TextEditor from 'flarum/components/TextEditor';
|
import TextEditor from 'flarum/components/TextEditor';
|
||||||
import TextEditorButton from 'flarum/components/TextEditorButton';
|
import TextEditorButton from 'flarum/components/TextEditorButton';
|
||||||
@@ -14,12 +12,28 @@ import { truncate } from 'flarum/utils/string';
|
|||||||
import AutocompleteDropdown from './fragments/AutocompleteDropdown';
|
import AutocompleteDropdown from './fragments/AutocompleteDropdown';
|
||||||
|
|
||||||
export default function addComposerAutocomplete() {
|
export default function addComposerAutocomplete() {
|
||||||
extend(TextEditor.prototype, 'oncreate', function () {
|
|
||||||
const $container = $('<div class="ComposerBody-mentionsDropdownContainer"></div>');
|
const $container = $('<div class="ComposerBody-mentionsDropdownContainer"></div>');
|
||||||
const dropdown = new AutocompleteDropdown();
|
const dropdown = new AutocompleteDropdown();
|
||||||
const $textarea = this.$('textarea').wrap('<div class="ComposerBody-mentionsWrapper"></div>');
|
|
||||||
|
extend(TextEditor.prototype, 'oncreate', function (params) {
|
||||||
|
const $editor = this.$('.TextEditor-editor').wrap('<div class="ComposerBody-mentionsWrapper"></div>');
|
||||||
|
|
||||||
|
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 = [];
|
const searched = [];
|
||||||
let mentionStart;
|
let relMentionStart;
|
||||||
|
let absMentionStart;
|
||||||
let typed;
|
let typed;
|
||||||
let searchTimeout;
|
let searchTimeout;
|
||||||
|
|
||||||
@@ -30,38 +44,27 @@ export default function addComposerAutocomplete() {
|
|||||||
const returnedUserIds = new Set(returnedUsers.map(u => u.id()));
|
const returnedUserIds = new Set(returnedUsers.map(u => u.id()));
|
||||||
|
|
||||||
const applySuggestion = (replacement) => {
|
const applySuggestion = (replacement) => {
|
||||||
app.composer.editor.replaceBeforeCursor(mentionStart - 1, replacement + ' ');
|
app.composer.editor.replaceBeforeCursor(absMentionStart - 1, replacement + ' ');
|
||||||
|
|
||||||
dropdown.hide();
|
dropdown.hide();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.navigator = new KeyboardNavigatable();
|
params.inputListeners.push(function(e) {
|
||||||
this.navigator
|
const selection = app.composer.editor.getSelectionRange();
|
||||||
.when(() => dropdown.active)
|
|
||||||
.onUp(() => dropdown.navigate(-1))
|
|
||||||
.onDown(() => dropdown.navigate(1))
|
|
||||||
.onSelect(dropdown.complete.bind(dropdown))
|
|
||||||
.onCancel(dropdown.hide.bind(dropdown))
|
|
||||||
.bindTo($textarea);
|
|
||||||
|
|
||||||
$textarea
|
const cursor = selection[0];
|
||||||
.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 = this.selectionStart;
|
if (selection[1] - cursor > 0) return;
|
||||||
|
|
||||||
if (this.selectionEnd - cursor > 0) return;
|
|
||||||
|
|
||||||
// Search backwards from the cursor for an '@' symbol. If we find one,
|
// Search backwards from the cursor for an '@' symbol. If we find one,
|
||||||
// we will want to show the autocomplete dropdown!
|
// we will want to show the autocomplete dropdown!
|
||||||
const value = this.value;
|
const lastChunk = app.composer.editor.getLastNChars(30);
|
||||||
mentionStart = 0;
|
absMentionStart = 0;
|
||||||
for (let i = cursor - 1; i >= cursor - 30; i--) {
|
for (let i = lastChunk.length - 1; i >= 0; i--) {
|
||||||
const character = value.substr(i, 1);
|
const character = lastChunk.substr(i, 1);
|
||||||
if (character === '@') {
|
if (character === '@' && (i == 0 || /\s/.test(lastChunk.substr(i - 1, 1)))) {
|
||||||
mentionStart = i + 1;
|
relMentionStart = i + 1;
|
||||||
|
absMentionStart = cursor - lastChunk.length + i + 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,8 +72,8 @@ export default function addComposerAutocomplete() {
|
|||||||
dropdown.hide();
|
dropdown.hide();
|
||||||
dropdown.active = false;
|
dropdown.active = false;
|
||||||
|
|
||||||
if (mentionStart) {
|
if (absMentionStart) {
|
||||||
typed = value.substring(mentionStart, cursor).toLowerCase();
|
typed = lastChunk.substring(relMentionStart).toLowerCase();
|
||||||
|
|
||||||
const makeSuggestion = function(user, replacement, content, className = '') {
|
const makeSuggestion = function(user, replacement, content, className = '') {
|
||||||
const username = usernameHelper(user);
|
const username = usernameHelper(user);
|
||||||
@@ -100,7 +103,7 @@ export default function addComposerAutocomplete() {
|
|||||||
user.displayName()
|
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 = () => {
|
const buildSuggestions = () => {
|
||||||
@@ -153,18 +156,25 @@ export default function addComposerAutocomplete() {
|
|||||||
m.render($container[0], dropdown.render());
|
m.render($container[0], dropdown.render());
|
||||||
|
|
||||||
dropdown.show();
|
dropdown.show();
|
||||||
const coordinates = getCaretCoordinates(this, mentionStart);
|
const coordinates = app.composer.editor.getCaretCoordinates(absMentionStart);
|
||||||
const width = dropdown.$().outerWidth();
|
const width = dropdown.$().outerWidth();
|
||||||
const height = dropdown.$().outerHeight();
|
const height = dropdown.$().outerHeight();
|
||||||
const parent = dropdown.$().offsetParent();
|
const parent = dropdown.$().offsetParent();
|
||||||
let left = coordinates.left;
|
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()) {
|
if (top + height > parent.height()) {
|
||||||
top = coordinates.top - this.scrollTop - height - 15;
|
top = coordinates.top - height - 15;
|
||||||
}
|
}
|
||||||
if (left + width > parent.width()) {
|
if (left + width > parent.width()) {
|
||||||
left = parent.width() - 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);
|
dropdown.show(left, top);
|
||||||
} else {
|
} else {
|
||||||
dropdown.active = false;
|
dropdown.active = false;
|
||||||
|
@@ -20,7 +20,8 @@ function insertMention(post, composer, quote) {
|
|||||||
Array(precedingNewlines).join('\n') + // Insert up to two newlines, depending on preceding whitespace
|
Array(precedingNewlines).join('\n') + // Insert up to two newlines, depending on preceding whitespace
|
||||||
(quote
|
(quote
|
||||||
? '> ' + mention + quote.trim().replace(/\n/g, '\n> ') + '\n\n'
|
? '> ' + mention + quote.trim().replace(/\n/g, '\n> ') + '\n\n'
|
||||||
: mention)
|
: mention),
|
||||||
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user