Skip to content

Instantly share code, notes, and snippets.

@lawso017
Last active July 6, 2022 10:13
Show Gist options
  • Save lawso017/44df47968be36222b874b8c4d94b779b to your computer and use it in GitHub Desktop.
Save lawso017/44df47968be36222b874b8c4d94b779b to your computer and use it in GitHub Desktop.
@mentions with trix-editor and selectize.js
window.addEventListener "trix-initialize", (e) =>
Utility.TrixMentions.prepare($(e.target))
# Filter for use with https://github.com/jch/html-pipeline
# to extract mentioned user_ids
module HTML
class Pipeline
class TrixMentionFilter < Filter
attr_reader :mentioned_user_ids
def initialize(doc, context = nil, result = nil)
super doc, context, result
@mentioned_user_ids = []
end
def call
process_attachments! do |attachment|
@mentioned_user_ids << attachment["user-id"].to_i
end
doc
end
def process_attachments!
doc.css("[data-trix-attachment]").each do |attachment_node|
attachment = JSON.parse(attachment_node.attribute('data-trix-attachment'))
next unless attachment["attachment-type"] == "trix-mention"
yield attachment
end
end
end
end
end
window.Utility ||= {}
class Utility.TrixMentions
MENTIONS_PATH = "mentions-path"
MENTIONS_DIV_ID = "#trix-mentions-"
MENTIONS_INPUT_ID = MENTIONS_DIV_ID + "input-"
@prepare: ($trix) ->
mentionsDivForTrix = ($trix) ->
$(MENTIONS_DIV_ID + $trix.attr('trix-id'))
mentionsInputForTrix = ($trix) ->
$(MENTIONS_INPUT_ID + $trix.attr('trix-id'))
mentionsSelectizeForTrix = ($trix) ->
mentionsInputForTrix($trix).next('.selectize-control')
mentionsSelectizeDropdownForTrix = ($trix) ->
mentionsInputForTrix($trix).next('.selectize-dropdown')
createMentionsDivForTrix = ($trix) ->
$trix.after("<trix-mentions id='trix-mentions-"+ $trix.attr('trix-id') + "'><input id='trix-mentions-input-" + $trix.attr('trix-id') + "'></input></trix-mentions>")
initializeMentionsSelectize = ($trix) ->
$.getJSON $trix.data(MENTIONS_PATH), (result) ->
mentionsInputForTrix($trix).selectize
create: false
valueField: 'id'
labelField: 'name'
searchField: 'name'
sortField: 'name'
options: result.data
selectOnTab: true
onInitialize: ->
@.disable()
mentionsSelectizeForTrix($trix).css('left', -1000)
onItemAdd: (value, $item) ->
embed = "<span class='trix-mention'>@" + $item.text() + "</span>"
attachment = new Trix.Attachment
content: embed
'attachment-type': 'trix-mention'
'user-id': $item.data('value')
$trix[0].editor.setSelectedRange([$trix.data('last-position') - 1, $trix.data('last-position')])
$trix[0].editor.deleteInDirection('forward')
$trix[0].editor.insertAttachment attachment
mentionsDivForTrix($trix).hide()
onBlur: ->
mentionsDivForTrix($trix).hide()
@.disable()
mentionsSelectizeForTrix($trix).css('left', -1000)
$trix.focus()
if @.items.length == 0
$trix[0].editor.setSelectedRange([$trix.data('last-position') - 1, $trix.data('last-position')])
$trix[0].editor.deleteInDirection('forward')
onDropdownClose: ->
mentionsDivForTrix($trix).hide()
onDropdownOpen: ($dropdown) ->
rect = $trix[0].editor.getClientRectAtPosition($trix[0].editor.getPosition())
if rect != undefined
$dropdown.css('top', 34)
if rect.left + 200 > $trix.offset().left + $trix.width()
$dropdown.css('left', $trix.offset().left + $trix.width() - (rect.left + 210))
onType: (str) ->
rect = $trix[0].editor.getClientRectAtPosition($trix[0].editor.getPosition())
if rect.left + 200 > $trix.offset().left + $trix.width()
mentionsSelectizeDropdownForTrix($trix).css('left', $trix.offset().left + $trix.width() - (rect.left + 210))
openMentionsSelectize = ($trix, editor) ->
$trix.data 'last-position', editor.getPosition()
mentionsInput = mentionsInputForTrix($trix)
mentionsSelectize = mentionsSelectizeForTrix($trix)
rect = editor.getClientRectAtPosition(editor.getPosition())
mentionsSelectize.css('left', rect.left - 10)
mentionsSelectize.css('top', rect.top - 4)
mentionsInput[0].selectize.clear()
mentionsInput[0].selectize.enable()
mentionsDivForTrix($trix).show()
mentionsInput[0].selectize.focus()
if $trix.data(MENTIONS_PATH).length > 0
createMentionsDivForTrix($trix)
initializeMentionsSelectize($trix)
$trix.on 'trix-change', ->
editor = @.editor
char = editor.getDocument().toString().charAt(editor.getPosition() - 1)
openMentionsSelectize($(@), editor) if char == '@'
[data-trix-attachment] {
display: inline-block;
}
span.trix-mention + figcaption {
display: none;
}
trix-mentions {
.selectize-control {
position: fixed
}
.selectize-input {
border: none !important;
background: none !important;
box-shadow: none !important;
}
.selectize-control, .selectize-dropdown {
width: 200px !important;
z-index: 9999;
}
}
@lawso017
Copy link
Author

@blimey85, the MENTIONS_PATH constant shouldn't need to be changed in your implementation. It's just defined as a constant to prevent typos in the code... we use the defined value "mentions-path" to identify the data attribute containing the path in the control.

In your case, you just need to ensure that your trix element has the data attribute:

data-mentions-path="/user/mentions?r"

defined.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment