It would be great to allow @mentions in some way. Probably through pluggable list of keywords and content to display in the drop-down list.
cc @jshirley, @lpsBetty, @jwilsjustin
(Opening a new issue because the previous one #45 was closed in favor of #31, which was then also closed.)
I have got it working with https://github.com/yuku-t/jquery-textcomplete
you just need to do 1 thing to prevent that trix makes a line break on ENTER instead of inserting the mention:
var editor = $element[0].editor;
var events = angular.copy(editor.composition.delegate.inputController.events);
// Prevent line break by Trix if user selects a mention.
$element.on('textComplete:show', function() {
editor.composition.delegate.inputController.events.keypress = angular.noop;
editor.composition.delegate.inputController.events.keydown = angular.noop;
});
$element.on('textComplete:hide', function() {
editor.composition.delegate.inputController.events.keypress = events.keypress;
editor.composition.delegate.inputController.events.keydown = events.keydown;
});
(I am using angular and created an angular component)
Do you have a demo with it and Trix somewhere?
No sorry, not at the moment.. I can create a jsfiddle when I have time! ;)
We don't plan to add built in support @mentions or autocomplete, but it would make a nice plugin. I described Basecamp 3's implementation at a high level in https://github.com/basecamp/trix/issues/270#issuecomment-233347093.
I also have issues with enter. Is the solution above really the cleanest?
I found it easier to patch Trix.InputController::keys.return which is the only keystroke I really care (I would want that return selects current user, and not make a new line, while a dialog for selecting users is shown).
I have something like:
originalReturn = Trix.InputController::keys.return
Trix.InputController::keys.return = (event) ->
return if isDialogShown()
originalReturn.call @, event
Here's another approach using selectize.js as the container for managing @mentions:
https://gist.github.com/lawso017/44df47968be36222b874b8c4d94b779b
And one with Meteor, Blaze, and custom pop-up dialog: https://github.com/peer/mind/blob/master/packages/peermind/base/editor.coffee
It works pretty well once you figure out all the details. :-)
Thanks to @lpsBetty, got it run by Tribute: https://github.com/zurb/tribute
var tribute = new Tribute({
values: [
{key: 'Phil Heartman', value: 'pheartman'},
{key: 'Gordon Ramsey', value: 'gramsey'}]
});
tribute.attach($('trix-editor'));
var editor = $('trix-editor')[0].editor;
if (editor != null) {
editor.composition.delegate.inputController.events.keypress = function() {};
editor.composition.delegate.inputController.events.keydown = function() {};
}
Just to add to @hailiangwangutd and @lpsBetty solutions, you will have to include jquery prior the Tribute script. It's working for me.
// Patch Tribute
this.tribute.attach(this.element)
this.tribute.range.pasteHtml = function(html, startPos, endPos) {
editor.deleteInDirection("backward")
let attachment = new Trix.Attachment({ content: html })
editor.insertAttachment(attachment)
}
this.tribute.events.getKeyCode = function(instance, el, event) {
if (event.isComposing) return
let tribute = instance.tribute
let info = tribute.range.getTriggerInfo(false, false, true, tribute.allowSpaces)
if (info) {
return info.mentionTriggerChar.charCodeAt(0)
} else {
return false
}
}
Just to add another implementation here:
~~~ coffeescript
document.addEventListener 'trix-initialize', (event) ->
element = event.target
editor = element.editor
tribute.attach element
replaced = (event) ->
# delete the matching text and the at sign
match_size = (event.detail.item.string.match(//g) || []).length + 1
editor.deleteInDirection("backward") for [0...match_size]
# add the mention as an attachment
mention = event.detail.item.original
attachment = new Trix.Attachment
user_id: mention.id,
content: "<span class='mention'>@#{ mention.value }</span>",
editor.insertAttachment attachment
editor.insertString " " # add an empty space to continue
element.addEventListener 'tribute-replaced', replaced
~~~
The main challenge is working without hooks, as both tribute and trix give a pretty small interface to play with.
It doesn't solve the enter or tab issue (tab does change the indentation when working on a list).
It would be awesome to have a hook on input to preventDefault if tributte.isActive, but there are not.
Just to add another implementation here:
document.addEventListener 'trix-initialize', (event) -> element = event.target editor = element.editor tribute.attach element replaced = (event) -> # delete the matching text and the at sign match_size = (event.detail.item.string.match(/<span>/g) || []).length + 1 editor.deleteInDirection("backward") for [0...match_size] # add the mention as an attachment mention = event.detail.item.original attachment = new Trix.Attachment user_id: mention.id, content: "<span class='mention'>@#{ mention.value }</span>", editor.insertAttachment attachment editor.insertString " " # add an empty space to continue element.addEventListener 'tribute-replaced', replacedThe main challenge is working without hooks, as both tribute and trix give a pretty small interface to play with.
It doesn't solve the enter or tab issue (tab does change the indentation when working on a list).
It would be awesome to have a hook on
inputtopreventDefaultiftributte.isActive, but there are not.
Thanks!
Also added this line:
this.tribute.range.pasteHtml = function(html, startPos, endPos) {}
to fix an non-replacing issue in chrome.
Most helpful comment
Thanks to @lpsBetty, got it run by Tribute: https://github.com/zurb/tribute