Apply Mentions everywhere (#595)

* variables and mentions

* fix lint

* add missing changes

* fix tests

* update quilly, fix bugs

* fix lint

* apply fixes

* apply fixes

* Fix MentionParser

* Apply Mentions everywhere

* Fix MentionParserTest

* Small refactoring

* Fixing quill import issues

* Polished email integration, added customer sender mail

* Add missing changes

* improve migration command

---------

Co-authored-by: Frank <csskfaves@gmail.com>
Co-authored-by: Julien Nahum <julien@nahum.net>
This commit is contained in:
Chirag Chhatrala
2024-10-22 14:04:29 +05:30
committed by GitHub
parent 2fdf2a439b
commit dad5c825b1
50 changed files with 1903 additions and 874 deletions

View File

@@ -0,0 +1,130 @@
import { reactive } from 'vue'
import Quill from 'quill'
const Inline = Quill.import('blots/inline')
export default function registerMentionExtension(Quill) {
class MentionBlot extends Inline {
static blotName = 'mention'
static tagName = 'SPAN'
static create(data) {
let node = super.create()
MentionBlot.setAttributes(node, data)
return node
}
static setAttributes(node, data) {
node.setAttribute('contenteditable', 'false')
node.setAttribute('mention', 'true')
if (data && typeof data === 'object') {
node.setAttribute('mention-field-id', data.field?.nf_id || '')
node.setAttribute('mention-field-name', data.field?.name || '')
node.setAttribute('mention-fallback', data.fallback || '')
node.textContent = data.field?.name || ''
} else {
// Handle case where data is not an object (e.g., during undo)
node.textContent = data || ''
}
}
static formats(domNode) {
return {
'mention-field-id': domNode.getAttribute('mention-field-id') || '',
'mention-field-name': domNode.getAttribute('mention-field-name') || '',
'mention-fallback': domNode.getAttribute('mention-fallback') || ''
}
}
format(name, value) {
if (name === 'mention' && value) {
MentionBlot.setAttributes(this.domNode, value)
} else {
super.format(name, value)
}
}
formats() {
let formats = super.formats()
formats['mention'] = MentionBlot.formats(this.domNode)
return formats
}
static value(domNode) {
return {
field: {
nf_id: domNode.getAttribute('mention-field-id') || '',
name: domNode.getAttribute('mention-field-name') || ''
},
fallback: domNode.getAttribute('mention-fallback') || ''
}
}
// Override attach to ensure contenteditable is always set
attach() {
super.attach()
this.domNode.setAttribute('contenteditable', 'false')
}
length() {
return 1
}
}
Quill.register(MentionBlot)
const mentionState = reactive({
open: false,
onInsert: null,
onCancel: null,
})
class MentionModule {
constructor(quill, options) {
this.quill = quill
this.options = options
this.setupMentions()
}
setupMentions() {
const toolbar = this.quill.getModule('toolbar')
if (toolbar) {
toolbar.addHandler('mention', () => {
const range = this.quill.getSelection()
if (range) {
mentionState.open = true
mentionState.onInsert = (mention) => {
this.insertMention(mention, range.index)
}
mentionState.onCancel = () => {
mentionState.open = false
}
}
})
}
}
insertMention(mention, index) {
mentionState.open = false
// Insert the mention
this.quill.insertEmbed(index, 'mention', mention, Quill.sources.USER)
// Calculate the length of the inserted mention
const mentionLength = this.quill.getLength() - index
nextTick(() => {
// Focus the editor
this.quill.focus()
// Set the selection after the mention
this.quill.setSelection(index + mentionLength, 0, Quill.sources.SILENT)
})
}
}
Quill.register('modules/mention', MentionModule)
return mentionState
}

2
client/lib/utils.js vendored
View File

@@ -88,7 +88,7 @@ export const getHost = function () {
* @returns {*}
*/
export const getDomain = function (url) {
if (url.includes("localhost")) return "localhost"
if (!url || url.includes("localhost")) return "localhost"
try {
if (!url.startsWith("http")) url = "https://" + url
return new URL(url).hostname