mirror of
https://github.com/flarum/core.git
synced 2025-08-04 15:37:51 +02:00
chore(mentions,emoji): tie autocomplete to editor instance (#3913)
This commit is contained in:
@@ -7,8 +7,6 @@ import getEmojiIconCode from './helpers/getEmojiIconCode';
|
|||||||
import cdn from './cdn';
|
import cdn from './cdn';
|
||||||
|
|
||||||
export default function addComposerAutocomplete() {
|
export default function addComposerAutocomplete() {
|
||||||
const $container = $('<div class="ComposerBody-emojiDropdownContainer"></div>');
|
|
||||||
const dropdown = new AutocompleteDropdown();
|
|
||||||
let emojiMap = null;
|
let emojiMap = null;
|
||||||
|
|
||||||
extend('flarum/common/components/TextEditor', 'oninit', function () {
|
extend('flarum/common/components/TextEditor', 'oninit', function () {
|
||||||
@@ -16,18 +14,19 @@ export default function addComposerAutocomplete() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
extend('flarum/common/components/TextEditor', 'onbuild', function () {
|
extend('flarum/common/components/TextEditor', 'onbuild', function () {
|
||||||
|
this.emojiDropdown = new AutocompleteDropdown();
|
||||||
const $editor = this.$('.TextEditor-editor').wrap('<div class="ComposerBody-emojiWrapper"></div>');
|
const $editor = this.$('.TextEditor-editor').wrap('<div class="ComposerBody-emojiWrapper"></div>');
|
||||||
|
|
||||||
this.navigator = new KeyboardNavigatable();
|
this.navigator = new KeyboardNavigatable();
|
||||||
this.navigator
|
this.navigator
|
||||||
.when(() => dropdown.active)
|
.when(() => this.emojiDropdown.active)
|
||||||
.onUp(() => dropdown.navigate(-1))
|
.onUp(() => this.emojiDropdown.navigate(-1))
|
||||||
.onDown(() => dropdown.navigate(1))
|
.onDown(() => this.emojiDropdown.navigate(1))
|
||||||
.onSelect(dropdown.complete.bind(dropdown))
|
.onSelect(this.emojiDropdown.complete.bind(this.emojiDropdown))
|
||||||
.onCancel(dropdown.hide.bind(dropdown))
|
.onCancel(this.emojiDropdown.hide.bind(this.emojiDropdown))
|
||||||
.bindTo($editor);
|
.bindTo($editor);
|
||||||
|
|
||||||
$editor.after($container);
|
$editor.after($('<div class="ComposerBody-emojiDropdownContainer"></div>'));
|
||||||
});
|
});
|
||||||
|
|
||||||
extend('flarum/common/components/TextEditor', 'buildEditorParams', function (params) {
|
extend('flarum/common/components/TextEditor', 'buildEditorParams', function (params) {
|
||||||
@@ -40,7 +39,7 @@ export default function addComposerAutocomplete() {
|
|||||||
const applySuggestion = (replacement) => {
|
const applySuggestion = (replacement) => {
|
||||||
this.attrs.composer.editor.replaceBeforeCursor(absEmojiStart - 1, replacement + ' ');
|
this.attrs.composer.editor.replaceBeforeCursor(absEmojiStart - 1, replacement + ' ');
|
||||||
|
|
||||||
dropdown.hide();
|
this.emojiDropdown.hide();
|
||||||
};
|
};
|
||||||
|
|
||||||
params.inputListeners.push(() => {
|
params.inputListeners.push(() => {
|
||||||
@@ -68,8 +67,8 @@ export default function addComposerAutocomplete() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dropdown.hide();
|
this.emojiDropdown.hide();
|
||||||
dropdown.active = false;
|
this.emojiDropdown.active = false;
|
||||||
|
|
||||||
if (absEmojiStart) {
|
if (absEmojiStart) {
|
||||||
typed = lastChunk.substring(relEmojiStart).toLowerCase();
|
typed = lastChunk.substring(relEmojiStart).toLowerCase();
|
||||||
@@ -80,7 +79,7 @@ export default function addComposerAutocomplete() {
|
|||||||
key={emoji}
|
key={emoji}
|
||||||
onclick={() => applySuggestion(emoji)}
|
onclick={() => applySuggestion(emoji)}
|
||||||
onmouseenter={function () {
|
onmouseenter={function () {
|
||||||
dropdown.setIndex($(this).parent().index() - 1);
|
this.emojiDropdown.setIndex($(this).parent().index() - 1);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img alt={emoji} className="emoji" draggable="false" loading="lazy" src={`${cdn}72x72/${code}.png`} />
|
<img alt={emoji} className="emoji" draggable="false" loading="lazy" src={`${cdn}72x72/${code}.png`} />
|
||||||
@@ -133,14 +132,14 @@ export default function addComposerAutocomplete() {
|
|||||||
.map(makeSuggestion);
|
.map(makeSuggestion);
|
||||||
|
|
||||||
if (suggestions.length) {
|
if (suggestions.length) {
|
||||||
dropdown.items = suggestions;
|
this.emojiDropdown.items = suggestions;
|
||||||
m.render($container[0], dropdown.render());
|
m.render(this.$('.ComposerBody-emojiDropdownContainer')[0], this.emojiDropdown.render());
|
||||||
|
|
||||||
dropdown.show();
|
this.emojiDropdown.show();
|
||||||
const coordinates = this.attrs.composer.editor.getCaretCoordinates(absEmojiStart);
|
const coordinates = this.attrs.composer.editor.getCaretCoordinates(absEmojiStart);
|
||||||
const width = dropdown.$().outerWidth();
|
const width = this.emojiDropdown.$().outerWidth();
|
||||||
const height = dropdown.$().outerHeight();
|
const height = this.emojiDropdown.$().outerHeight();
|
||||||
const parent = dropdown.$().offsetParent();
|
const parent = this.emojiDropdown.$().offsetParent();
|
||||||
let left = coordinates.left;
|
let left = coordinates.left;
|
||||||
let top = coordinates.top + 15;
|
let top = coordinates.top + 15;
|
||||||
|
|
||||||
@@ -156,15 +155,15 @@ export default function addComposerAutocomplete() {
|
|||||||
top = Math.max(-(parent.offset().top - $(document).scrollTop()), top);
|
top = Math.max(-(parent.offset().top - $(document).scrollTop()), top);
|
||||||
left = Math.max(-parent.offset().left, left);
|
left = Math.max(-parent.offset().left, left);
|
||||||
|
|
||||||
dropdown.show(left, top);
|
this.emojiDropdown.show(left, top);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
buildSuggestions();
|
buildSuggestions();
|
||||||
|
|
||||||
dropdown.setIndex(0);
|
this.emojiDropdown.setIndex(0);
|
||||||
dropdown.$().scrollTop(0);
|
this.emojiDropdown.$().scrollTop(0);
|
||||||
dropdown.active = true;
|
this.emojiDropdown.active = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -7,22 +7,20 @@ import AutocompleteDropdown from './fragments/AutocompleteDropdown';
|
|||||||
import MentionableModels from './mentionables/MentionableModels';
|
import MentionableModels from './mentionables/MentionableModels';
|
||||||
|
|
||||||
export default function addComposerAutocomplete() {
|
export default function addComposerAutocomplete() {
|
||||||
const $container = $('<div class="ComposerBody-mentionsDropdownContainer"></div>');
|
|
||||||
const dropdown = new AutocompleteDropdown();
|
|
||||||
|
|
||||||
extend('flarum/common/components/TextEditor', 'onbuild', function () {
|
extend('flarum/common/components/TextEditor', 'onbuild', function () {
|
||||||
|
this.mentionsDropdown = new AutocompleteDropdown();
|
||||||
const $editor = this.$('.TextEditor-editor').wrap('<div class="ComposerBody-mentionsWrapper"></div>');
|
const $editor = this.$('.TextEditor-editor').wrap('<div class="ComposerBody-mentionsWrapper"></div>');
|
||||||
|
|
||||||
this.navigator = new KeyboardNavigatable();
|
this.navigator = new KeyboardNavigatable();
|
||||||
this.navigator
|
this.navigator
|
||||||
.when(() => dropdown.active)
|
.when(() => this.mentionsDropdown.active)
|
||||||
.onUp(() => dropdown.navigate(-1))
|
.onUp(() => this.mentionsDropdown.navigate(-1))
|
||||||
.onDown(() => dropdown.navigate(1))
|
.onDown(() => this.mentionsDropdown.navigate(1))
|
||||||
.onSelect(dropdown.complete.bind(dropdown))
|
.onSelect(this.mentionsDropdown.complete.bind(this.mentionsDropdown))
|
||||||
.onCancel(dropdown.hide.bind(dropdown))
|
.onCancel(this.mentionsDropdown.hide.bind(this.mentionsDropdown))
|
||||||
.bindTo($editor);
|
.bindTo($editor);
|
||||||
|
|
||||||
$editor.after($container);
|
$editor.after($('<div class="ComposerBody-mentionsDropdownContainer"></div>'));
|
||||||
});
|
});
|
||||||
|
|
||||||
extend('flarum/common/components/TextEditor', 'buildEditorParams', function (params) {
|
extend('flarum/common/components/TextEditor', 'buildEditorParams', function (params) {
|
||||||
@@ -32,12 +30,12 @@ export default function addComposerAutocomplete() {
|
|||||||
|
|
||||||
let mentionables = new MentionableModels({
|
let mentionables = new MentionableModels({
|
||||||
onmouseenter: function () {
|
onmouseenter: function () {
|
||||||
dropdown.setIndex($(this).parent().index());
|
this.mentionsDropdown.setIndex($(this).parent().index());
|
||||||
},
|
},
|
||||||
onclick: (replacement) => {
|
onclick: (replacement) => {
|
||||||
this.attrs.composer.editor.replaceBeforeCursor(absMentionStart - 1, replacement + ' ');
|
this.attrs.composer.editor.replaceBeforeCursor(absMentionStart - 1, replacement + ' ');
|
||||||
|
|
||||||
dropdown.hide();
|
this.mentionsDropdown.hide();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -66,8 +64,8 @@ export default function addComposerAutocomplete() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dropdown.hide();
|
this.mentionsDropdown.hide();
|
||||||
dropdown.active = false;
|
this.mentionsDropdown.active = false;
|
||||||
|
|
||||||
if (absMentionStart) {
|
if (absMentionStart) {
|
||||||
const typed = lastChunk.substring(relMentionStart).toLowerCase();
|
const typed = lastChunk.substring(relMentionStart).toLowerCase();
|
||||||
@@ -83,14 +81,14 @@ export default function addComposerAutocomplete() {
|
|||||||
const suggestions = mentionables.buildSuggestions();
|
const suggestions = mentionables.buildSuggestions();
|
||||||
|
|
||||||
if (suggestions.length) {
|
if (suggestions.length) {
|
||||||
dropdown.items = suggestions;
|
this.mentionsDropdown.items = suggestions;
|
||||||
m.render($container[0], dropdown.render());
|
m.render(this.$('.ComposerBody-mentionsDropdownContainer')[0], this.mentionsDropdown.render());
|
||||||
|
|
||||||
dropdown.show();
|
this.mentionsDropdown.show();
|
||||||
const coordinates = this.attrs.composer.editor.getCaretCoordinates(absMentionStart);
|
const coordinates = this.attrs.composer.editor.getCaretCoordinates(absMentionStart);
|
||||||
const width = dropdown.$().outerWidth();
|
const width = this.mentionsDropdown.$().outerWidth();
|
||||||
const height = dropdown.$().outerHeight();
|
const height = this.mentionsDropdown.$().outerHeight();
|
||||||
const parent = dropdown.$().offsetParent();
|
const parent = this.mentionsDropdown.$().offsetParent();
|
||||||
let left = coordinates.left;
|
let left = coordinates.left;
|
||||||
let top = coordinates.top + 15;
|
let top = coordinates.top + 15;
|
||||||
|
|
||||||
@@ -106,19 +104,19 @@ export default function addComposerAutocomplete() {
|
|||||||
top = Math.max(-(parent.offset().top - $(document).scrollTop()), top);
|
top = Math.max(-(parent.offset().top - $(document).scrollTop()), top);
|
||||||
left = Math.max(-parent.offset().left, left);
|
left = Math.max(-parent.offset().left, left);
|
||||||
|
|
||||||
dropdown.show(left, top);
|
this.mentionsDropdown.show(left, top);
|
||||||
} else {
|
} else {
|
||||||
dropdown.active = false;
|
this.mentionsDropdown.active = false;
|
||||||
dropdown.hide();
|
this.mentionsDropdown.hide();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
dropdown.active = true;
|
this.mentionsDropdown.active = true;
|
||||||
|
|
||||||
buildSuggestions();
|
buildSuggestions();
|
||||||
|
|
||||||
dropdown.setIndex(0);
|
this.mentionsDropdown.setIndex(0);
|
||||||
dropdown.$().scrollTop(0);
|
this.mentionsDropdown.$().scrollTop(0);
|
||||||
|
|
||||||
mentionables.search()?.then(buildSuggestions);
|
mentionables.search()?.then(buildSuggestions);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user