Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for @mentions #284

Closed
mitar opened this issue Aug 4, 2016 · 13 comments
Closed

Support for @mentions #284

mitar opened this issue Aug 4, 2016 · 13 comments

Comments

@mitar
Copy link
Contributor

mitar commented Aug 4, 2016

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.)

@bettysteger
Copy link

bettysteger commented Aug 4, 2016

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)

@mitar
Copy link
Contributor Author

mitar commented Aug 4, 2016

Do you have a demo with it and Trix somewhere?

@bettysteger
Copy link

No sorry, not at the moment.. I can create a jsfiddle when I have time! ;)

@javan
Copy link
Contributor

javan commented Aug 4, 2016

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 #270 (comment).

@javan javan closed this as completed Aug 4, 2016
@mitar
Copy link
Contributor Author

mitar commented Sep 18, 2016

I also have issues with enter. Is the solution above really the cleanest?

@mitar
Copy link
Contributor Author

mitar commented Sep 18, 2016

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

@lawso017
Copy link

Here's another approach using selectize.js as the container for managing @mentions:

https://gist.github.com/lawso017/44df47968be36222b874b8c4d94b779b

@mitar
Copy link
Contributor Author

mitar commented Sep 27, 2016

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. :-)

@hailiangwangutd
Copy link

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() {};
  }

@lkallday45
Copy link

Just to add to @hailiangwangutd and @lpsBetty solutions, you will have to include jquery prior the Tribute script. It's working for me.

@Novtopro
Copy link

    // 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
      }
    }

@eloyesp
Copy link

eloyesp commented Jun 10, 2019

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', 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.

@mtomov
Copy link

mtomov commented Mar 19, 2020

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', 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.

Thanks!

Also added this line:

this.tribute.range.pasteHtml = function(html, startPos, endPos) {}

to fix an non-replacing issue in chrome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants