quill-mention
Advanced tools
Comparing version 2.2.7 to 3.0.0
@@ -271,3 +271,8 @@ 'use strict'; | ||
this.values = []; | ||
this.suspendMouseEnter = false; | ||
this.suspendMouseEnter = false; //this token is an object that may contains one key "abandoned", set to | ||
//true when the previous source call should be ignored in favor or a | ||
//more recent execution. This token will be null unless a source call | ||
//is in progress. | ||
this.existingSourceExecutionToken = null; | ||
this.quill = quill; | ||
@@ -279,2 +284,5 @@ this.options = { | ||
}, | ||
renderLoading: function renderLoading() { | ||
return null; | ||
}, | ||
onSelect: function onSelect(item, insertItem) { | ||
@@ -292,5 +300,6 @@ insertItem(item); | ||
fixMentionsToQuill: false, | ||
positioningStrategy: "normal", | ||
defaultMenuOrientation: "bottom", | ||
blotName: "mention", | ||
dataAttributes: ["id", "value", "denotationChar", "link", "target"], | ||
dataAttributes: ["id", "value", "denotationChar", "link", "target", "disabled"], | ||
linkTarget: "_blank", | ||
@@ -312,4 +321,5 @@ onOpen: function onOpen() { | ||
dataAttributes: Array.isArray(options.dataAttributes) ? this.options.dataAttributes.concat(options.dataAttributes) : this.options.dataAttributes | ||
}); | ||
}); //create mention container | ||
this.mentionContainer = document.createElement("div"); | ||
@@ -327,3 +337,2 @@ this.mentionContainer.className = this.options.mentionContainerClass ? this.options.mentionContainerClass : ""; | ||
this.mentionContainer.appendChild(this.mentionList); | ||
this.quill.container.appendChild(this.mentionContainer); | ||
quill.on("text-change", this.onTextChange.bind(this)); | ||
@@ -353,3 +362,3 @@ quill.on("selection-change", this.onSelectionChange.bind(this)); | ||
value: function selectHandler() { | ||
if (this.isOpen) { | ||
if (this.isOpen && !this.existingSourceExecutionToken) { | ||
this.selectItem(); | ||
@@ -365,2 +374,6 @@ return false; | ||
if (this.isOpen) { | ||
if (this.existingSourceExecutionToken) { | ||
this.existingSourceExecutionToken.abandoned = true; | ||
} | ||
this.hideMentionList(); | ||
@@ -375,3 +388,3 @@ return false; | ||
value: function upHandler() { | ||
if (this.isOpen) { | ||
if (this.isOpen && !this.existingSourceExecutionToken) { | ||
this.prevItem(); | ||
@@ -386,3 +399,3 @@ return false; | ||
value: function downHandler() { | ||
if (this.isOpen) { | ||
if (this.isOpen && !this.existingSourceExecutionToken) { | ||
this.nextItem(); | ||
@@ -397,4 +410,11 @@ return false; | ||
value: function showMentionList() { | ||
if (this.options.positioningStrategy === "fixed") { | ||
document.body.appendChild(this.mentionContainer); | ||
} else { | ||
this.quill.container.appendChild(this.mentionContainer); | ||
} | ||
this.mentionContainer.style.visibility = "hidden"; | ||
this.mentionContainer.style.display = ""; | ||
this.mentionContainer.scrollTop = 0; | ||
this.setMentionContainerPosition(); | ||
@@ -407,2 +427,3 @@ this.setIsOpen(true); | ||
this.mentionContainer.style.display = "none"; | ||
this.mentionContainer.remove(); | ||
this.setIsOpen(false); | ||
@@ -419,2 +440,6 @@ } | ||
if (this.itemIndex === -1 || this.mentionList.childNodes[this.itemIndex].dataset.disabled === "true") { | ||
return; | ||
} | ||
this.mentionList.childNodes[this.itemIndex].classList.add("selected"); | ||
@@ -424,3 +449,3 @@ | ||
var itemHeight = this.mentionList.childNodes[this.itemIndex].offsetHeight; | ||
var itemPos = this.itemIndex * itemHeight; | ||
var itemPos = this.mentionList.childNodes[this.itemIndex].offsetTop; | ||
var containerTop = this.mentionContainer.scrollTop; | ||
@@ -461,3 +486,12 @@ var containerBottom = containerTop + this.mentionContainer.offsetHeight; | ||
if (this.itemIndex === -1) { | ||
return; | ||
} | ||
var data = this.getItemData(); | ||
if (data.disabled) { | ||
return; | ||
} | ||
this.options.onSelect(data, function (asyncData) { | ||
@@ -470,3 +504,3 @@ _this.insertItem(asyncData); | ||
key: "insertItem", | ||
value: function insertItem(data) { | ||
value: function insertItem(data, programmaticInsert) { | ||
var render = data; | ||
@@ -482,12 +516,19 @@ | ||
var prevMentionCharPos = this.mentionCharPos; | ||
this.quill.deleteText(this.mentionCharPos, this.cursorPos - this.mentionCharPos, Quill.sources.USER); | ||
this.quill.insertEmbed(prevMentionCharPos, this.options.blotName, render, Quill.sources.USER); | ||
var insertAtPos; | ||
if (!programmaticInsert) { | ||
insertAtPos = this.mentionCharPos; | ||
this.quill.deleteText(this.mentionCharPos, this.cursorPos - this.mentionCharPos, Quill.sources.USER); | ||
} else { | ||
insertAtPos = this.cursorPos; | ||
} | ||
this.quill.insertEmbed(insertAtPos, this.options.blotName, render, Quill.sources.USER); | ||
if (this.options.spaceAfterInsert) { | ||
this.quill.insertText(prevMentionCharPos + 1, " ", Quill.sources.USER); // setSelection here sets cursor position | ||
this.quill.insertText(insertAtPos + 1, " ", Quill.sources.USER); // setSelection here sets cursor position | ||
this.quill.setSelection(prevMentionCharPos + 2, Quill.sources.USER); | ||
this.quill.setSelection(insertAtPos + 2, Quill.sources.USER); | ||
} else { | ||
this.quill.setSelection(prevMentionCharPos + 1, Quill.sources.USER); | ||
this.quill.setSelection(insertAtPos + 1, Quill.sources.USER); | ||
} | ||
@@ -512,4 +553,18 @@ | ||
}, { | ||
key: "onDisabledItemMouseEnter", | ||
value: function onDisabledItemMouseEnter(e) { | ||
if (this.suspendMouseEnter) { | ||
return; | ||
} | ||
this.itemIndex = -1; | ||
this.highlightItem(false); | ||
} | ||
}, { | ||
key: "onItemClick", | ||
value: function onItemClick(e) { | ||
if (e.button !== 0) { | ||
return; | ||
} | ||
e.preventDefault(); | ||
@@ -522,7 +577,45 @@ e.stopImmediatePropagation(); | ||
}, { | ||
key: "onItemMouseDown", | ||
value: function onItemMouseDown(e) { | ||
e.preventDefault(); | ||
e.stopImmediatePropagation(); | ||
} | ||
}, { | ||
key: "renderLoading", | ||
value: function renderLoading() { | ||
var renderedLoading = this.options.renderLoading(); | ||
if (!renderedLoading) { | ||
return; | ||
} | ||
if (this.mentionContainer.getElementsByClassName("ql-mention-loading").length > 0) { | ||
this.showMentionList(); | ||
return; | ||
} | ||
this.mentionList.innerHTML = ""; | ||
var loadingDiv = document.createElement("div"); | ||
loadingDiv.className = "ql-mention-loading"; | ||
loadingDiv.innerHTML = this.options.renderLoading(); | ||
this.mentionContainer.append(loadingDiv); | ||
this.showMentionList(); | ||
} | ||
}, { | ||
key: "removeLoading", | ||
value: function removeLoading() { | ||
var loadingDiv = this.mentionContainer.getElementsByClassName("ql-mention-loading"); | ||
if (loadingDiv.length > 0) { | ||
loadingDiv[0].remove(); | ||
} | ||
} | ||
}, { | ||
key: "renderList", | ||
value: function renderList(mentionChar, data, searchTerm) { | ||
if (data && data.length > 0) { | ||
this.removeLoading(); | ||
this.values = data; | ||
this.mentionList.innerHTML = ""; | ||
var initialSelection = -1; | ||
@@ -532,11 +625,25 @@ for (var i = 0; i < data.length; i += 1) { | ||
li.className = this.options.listItemClass ? this.options.listItemClass : ""; | ||
if (data[i].disabled) { | ||
li.className += " disabled"; | ||
} else if (initialSelection === -1) { | ||
initialSelection = i; | ||
} | ||
li.dataset.index = i; | ||
li.innerHTML = this.options.renderItem(data[i], searchTerm); | ||
li.onmouseenter = this.onItemMouseEnter.bind(this); | ||
if (!data[i].disabled) { | ||
li.onmouseenter = this.onItemMouseEnter.bind(this); | ||
li.onmouseup = this.onItemClick.bind(this); | ||
li.onmousedown = this.onItemMouseDown.bind(this); | ||
} else { | ||
li.onmouseenter = this.onDisabledItemMouseEnter.bind(this); | ||
} | ||
li.dataset.denotationChar = mentionChar; | ||
li.onclick = this.onItemClick.bind(this); | ||
this.mentionList.appendChild(attachDataValues(li, data[i], this.options.dataAttributes)); | ||
} | ||
this.itemIndex = 0; | ||
this.itemIndex = initialSelection; | ||
this.highlightItem(); | ||
@@ -551,3 +658,18 @@ this.showMentionList(); | ||
value: function nextItem() { | ||
this.itemIndex = (this.itemIndex + 1) % this.values.length; | ||
var increment = 0; | ||
var newIndex; | ||
do { | ||
increment++; | ||
newIndex = (this.itemIndex + increment) % this.values.length; | ||
var disabled = this.mentionList.childNodes[newIndex].dataset.disabled === "true"; | ||
if (increment === this.values.length + 1) { | ||
//we've wrapped around w/o finding an enabled item | ||
newIndex = -1; | ||
break; | ||
} | ||
} while (disabled); | ||
this.itemIndex = newIndex; | ||
this.suspendMouseEnter = true; | ||
@@ -559,3 +681,18 @@ this.highlightItem(); | ||
value: function prevItem() { | ||
this.itemIndex = (this.itemIndex + this.values.length - 1) % this.values.length; | ||
var decrement = 0; | ||
var newIndex; | ||
do { | ||
decrement++; | ||
newIndex = (this.itemIndex + this.values.length - decrement) % this.values.length; | ||
var disabled = this.mentionList.childNodes[newIndex].dataset.disabled === "true"; | ||
if (decrement === this.values.length + 1) { | ||
//we've wrapped around w/o finding an enabled item | ||
newIndex = -1; | ||
break; | ||
} | ||
} while (disabled); | ||
this.itemIndex = newIndex; | ||
this.suspendMouseEnter = true; | ||
@@ -597,2 +734,11 @@ this.highlightItem(); | ||
value: function setMentionContainerPosition() { | ||
if (this.options.positioningStrategy === "fixed") { | ||
this.setMentionContainerPosition_Fixed(); | ||
} else { | ||
this.setMentionContainerPosition_Normal(); | ||
} | ||
} | ||
}, { | ||
key: "setMentionContainerPosition_Normal", | ||
value: function setMentionContainerPosition_Normal() { | ||
var _this2 = this; | ||
@@ -679,2 +825,83 @@ | ||
}, { | ||
key: "setMentionContainerPosition_Fixed", | ||
value: function setMentionContainerPosition_Fixed() { | ||
var _this3 = this; | ||
this.mentionContainer.style.position = "fixed"; | ||
this.mentionContainer.style.height = null; | ||
var containerPos = this.quill.container.getBoundingClientRect(); | ||
var mentionCharPos = this.quill.getBounds(this.mentionCharPos); | ||
var mentionCharPosAbsolute = { | ||
left: containerPos.left + mentionCharPos.left, | ||
top: containerPos.top + mentionCharPos.top, | ||
width: 0, | ||
height: mentionCharPos.height | ||
}; //Which rectangle should it be relative to | ||
var relativeToPos = this.options.fixMentionsToQuill ? containerPos : mentionCharPosAbsolute; | ||
var topPos = this.options.offsetTop; | ||
var leftPos = this.options.offsetLeft; // handle horizontal positioning | ||
if (this.options.fixMentionsToQuill) { | ||
var rightPos = relativeToPos.right; | ||
this.mentionContainer.style.right = "".concat(rightPos, "px"); | ||
} else { | ||
leftPos += relativeToPos.left; //if its off the righ edge, push it back | ||
if (leftPos + this.mentionContainer.offsetWidth > document.documentElement.clientWidth) { | ||
leftPos -= leftPos + this.mentionContainer.offsetWidth - document.documentElement.clientWidth; | ||
} | ||
} | ||
var availableSpaceTop = relativeToPos.top; | ||
var availableSpaceBottom = document.documentElement.clientHeight - (relativeToPos.top + relativeToPos.height); | ||
var fitsBottom = this.mentionContainer.offsetHeight <= availableSpaceBottom; | ||
var fitsTop = this.mentionContainer.offsetHeight <= availableSpaceTop; | ||
var placement; | ||
if (this.options.defaultMenuOrientation === "top" && fitsTop) { | ||
placement = "top"; | ||
} else if (this.options.defaultMenuOrientation === "bottom" && fitsBottom) { | ||
placement = "bottom"; | ||
} else { | ||
//it doesnt fit either so put it where there's the most space | ||
placement = availableSpaceBottom > availableSpaceTop ? "bottom" : "top"; | ||
} | ||
if (placement === "bottom") { | ||
topPos = relativeToPos.top + relativeToPos.height; | ||
if (!fitsBottom) { | ||
//shrink it to fit | ||
//3 is a bit of a fudge factor so it doesnt touch the edge of the screen | ||
this.mentionContainer.style.height = availableSpaceBottom - 3 + "px"; | ||
} | ||
this.options.mentionContainerClass.split(" ").forEach(function (className) { | ||
_this3.mentionContainer.classList.add("".concat(className, "-bottom")); | ||
_this3.mentionContainer.classList.remove("".concat(className, "-top")); | ||
}); | ||
} else { | ||
topPos = relativeToPos.top - this.mentionContainer.offsetHeight; | ||
if (!fitsTop) { | ||
//shrink it to fit | ||
//3 is a bit of a fudge factor so it doesnt touch the edge of the screen | ||
this.mentionContainer.style.height = availableSpaceTop - 3 + "px"; | ||
topPos = 3; | ||
} | ||
this.options.mentionContainerClass.split(" ").forEach(function (className) { | ||
_this3.mentionContainer.classList.add("".concat(className, "-top")); | ||
_this3.mentionContainer.classList.remove("".concat(className, "-bottom")); | ||
}); | ||
} | ||
this.mentionContainer.style.top = "".concat(topPos, "px"); | ||
this.mentionContainer.style.left = "".concat(leftPos, "px"); | ||
this.mentionContainer.style.visibility = "visible"; | ||
} | ||
}, { | ||
key: "getTextBeforeCursor", | ||
@@ -689,2 +916,4 @@ value: function getTextBeforeCursor() { | ||
value: function onSomethingChange() { | ||
var _this4 = this; | ||
var range = this.quill.getSelection(); | ||
@@ -704,4 +933,21 @@ if (range == null) return; | ||
if (textAfter.length >= this.options.minChars && hasValidChars(textAfter, this.options.allowedChars)) { | ||
this.options.source(textAfter, this.renderList.bind(this, mentionChar), mentionChar); | ||
if (textAfter.length >= this.options.minChars && hasValidChars(textAfter, this.getAllowedCharsRegex(mentionChar))) { | ||
if (this.existingSourceExecutionToken) { | ||
this.existingSourceExecutionToken.abandoned = true; | ||
} | ||
this.renderLoading(); | ||
var sourceRequestToken = { | ||
abandoned: false | ||
}; | ||
this.existingSourceExecutionToken = sourceRequestToken; | ||
this.options.source(textAfter, function (data, searchTerm) { | ||
if (sourceRequestToken.abandoned) { | ||
return; | ||
} | ||
_this4.existingSourceExecutionToken = null; | ||
_this4.renderList(mentionChar, data, searchTerm); | ||
}, mentionChar); | ||
} else { | ||
@@ -715,2 +961,11 @@ this.hideMentionList(); | ||
}, { | ||
key: "getAllowedCharsRegex", | ||
value: function getAllowedCharsRegex(denotationChar) { | ||
if (this.options.allowedChars instanceof RegExp) { | ||
return this.options.allowedChars; | ||
} else { | ||
return this.options.allowedChars(denotationChar); | ||
} | ||
} | ||
}, { | ||
key: "onTextChange", | ||
@@ -731,2 +986,10 @@ value: function onTextChange(delta, oldDelta, source) { | ||
} | ||
}, { | ||
key: "openMenu", | ||
value: function openMenu(denotationChar) { | ||
var selection = this.quill.getSelection(true); | ||
this.quill.insertText(selection.index, denotationChar); | ||
this.quill.blur(); | ||
this.quill.focus(); | ||
} | ||
}]); | ||
@@ -733,0 +996,0 @@ |
@@ -267,3 +267,8 @@ import Quill from 'quill'; | ||
this.values = []; | ||
this.suspendMouseEnter = false; | ||
this.suspendMouseEnter = false; //this token is an object that may contains one key "abandoned", set to | ||
//true when the previous source call should be ignored in favor or a | ||
//more recent execution. This token will be null unless a source call | ||
//is in progress. | ||
this.existingSourceExecutionToken = null; | ||
this.quill = quill; | ||
@@ -275,2 +280,5 @@ this.options = { | ||
}, | ||
renderLoading: function renderLoading() { | ||
return null; | ||
}, | ||
onSelect: function onSelect(item, insertItem) { | ||
@@ -288,5 +296,6 @@ insertItem(item); | ||
fixMentionsToQuill: false, | ||
positioningStrategy: "normal", | ||
defaultMenuOrientation: "bottom", | ||
blotName: "mention", | ||
dataAttributes: ["id", "value", "denotationChar", "link", "target"], | ||
dataAttributes: ["id", "value", "denotationChar", "link", "target", "disabled"], | ||
linkTarget: "_blank", | ||
@@ -308,4 +317,5 @@ onOpen: function onOpen() { | ||
dataAttributes: Array.isArray(options.dataAttributes) ? this.options.dataAttributes.concat(options.dataAttributes) : this.options.dataAttributes | ||
}); | ||
}); //create mention container | ||
this.mentionContainer = document.createElement("div"); | ||
@@ -323,3 +333,2 @@ this.mentionContainer.className = this.options.mentionContainerClass ? this.options.mentionContainerClass : ""; | ||
this.mentionContainer.appendChild(this.mentionList); | ||
this.quill.container.appendChild(this.mentionContainer); | ||
quill.on("text-change", this.onTextChange.bind(this)); | ||
@@ -349,3 +358,3 @@ quill.on("selection-change", this.onSelectionChange.bind(this)); | ||
value: function selectHandler() { | ||
if (this.isOpen) { | ||
if (this.isOpen && !this.existingSourceExecutionToken) { | ||
this.selectItem(); | ||
@@ -361,2 +370,6 @@ return false; | ||
if (this.isOpen) { | ||
if (this.existingSourceExecutionToken) { | ||
this.existingSourceExecutionToken.abandoned = true; | ||
} | ||
this.hideMentionList(); | ||
@@ -371,3 +384,3 @@ return false; | ||
value: function upHandler() { | ||
if (this.isOpen) { | ||
if (this.isOpen && !this.existingSourceExecutionToken) { | ||
this.prevItem(); | ||
@@ -382,3 +395,3 @@ return false; | ||
value: function downHandler() { | ||
if (this.isOpen) { | ||
if (this.isOpen && !this.existingSourceExecutionToken) { | ||
this.nextItem(); | ||
@@ -393,4 +406,11 @@ return false; | ||
value: function showMentionList() { | ||
if (this.options.positioningStrategy === "fixed") { | ||
document.body.appendChild(this.mentionContainer); | ||
} else { | ||
this.quill.container.appendChild(this.mentionContainer); | ||
} | ||
this.mentionContainer.style.visibility = "hidden"; | ||
this.mentionContainer.style.display = ""; | ||
this.mentionContainer.scrollTop = 0; | ||
this.setMentionContainerPosition(); | ||
@@ -403,2 +423,3 @@ this.setIsOpen(true); | ||
this.mentionContainer.style.display = "none"; | ||
this.mentionContainer.remove(); | ||
this.setIsOpen(false); | ||
@@ -415,2 +436,6 @@ } | ||
if (this.itemIndex === -1 || this.mentionList.childNodes[this.itemIndex].dataset.disabled === "true") { | ||
return; | ||
} | ||
this.mentionList.childNodes[this.itemIndex].classList.add("selected"); | ||
@@ -420,3 +445,3 @@ | ||
var itemHeight = this.mentionList.childNodes[this.itemIndex].offsetHeight; | ||
var itemPos = this.itemIndex * itemHeight; | ||
var itemPos = this.mentionList.childNodes[this.itemIndex].offsetTop; | ||
var containerTop = this.mentionContainer.scrollTop; | ||
@@ -457,3 +482,12 @@ var containerBottom = containerTop + this.mentionContainer.offsetHeight; | ||
if (this.itemIndex === -1) { | ||
return; | ||
} | ||
var data = this.getItemData(); | ||
if (data.disabled) { | ||
return; | ||
} | ||
this.options.onSelect(data, function (asyncData) { | ||
@@ -466,3 +500,3 @@ _this.insertItem(asyncData); | ||
key: "insertItem", | ||
value: function insertItem(data) { | ||
value: function insertItem(data, programmaticInsert) { | ||
var render = data; | ||
@@ -478,12 +512,19 @@ | ||
var prevMentionCharPos = this.mentionCharPos; | ||
this.quill.deleteText(this.mentionCharPos, this.cursorPos - this.mentionCharPos, Quill.sources.USER); | ||
this.quill.insertEmbed(prevMentionCharPos, this.options.blotName, render, Quill.sources.USER); | ||
var insertAtPos; | ||
if (!programmaticInsert) { | ||
insertAtPos = this.mentionCharPos; | ||
this.quill.deleteText(this.mentionCharPos, this.cursorPos - this.mentionCharPos, Quill.sources.USER); | ||
} else { | ||
insertAtPos = this.cursorPos; | ||
} | ||
this.quill.insertEmbed(insertAtPos, this.options.blotName, render, Quill.sources.USER); | ||
if (this.options.spaceAfterInsert) { | ||
this.quill.insertText(prevMentionCharPos + 1, " ", Quill.sources.USER); // setSelection here sets cursor position | ||
this.quill.insertText(insertAtPos + 1, " ", Quill.sources.USER); // setSelection here sets cursor position | ||
this.quill.setSelection(prevMentionCharPos + 2, Quill.sources.USER); | ||
this.quill.setSelection(insertAtPos + 2, Quill.sources.USER); | ||
} else { | ||
this.quill.setSelection(prevMentionCharPos + 1, Quill.sources.USER); | ||
this.quill.setSelection(insertAtPos + 1, Quill.sources.USER); | ||
} | ||
@@ -508,4 +549,18 @@ | ||
}, { | ||
key: "onDisabledItemMouseEnter", | ||
value: function onDisabledItemMouseEnter(e) { | ||
if (this.suspendMouseEnter) { | ||
return; | ||
} | ||
this.itemIndex = -1; | ||
this.highlightItem(false); | ||
} | ||
}, { | ||
key: "onItemClick", | ||
value: function onItemClick(e) { | ||
if (e.button !== 0) { | ||
return; | ||
} | ||
e.preventDefault(); | ||
@@ -518,7 +573,45 @@ e.stopImmediatePropagation(); | ||
}, { | ||
key: "onItemMouseDown", | ||
value: function onItemMouseDown(e) { | ||
e.preventDefault(); | ||
e.stopImmediatePropagation(); | ||
} | ||
}, { | ||
key: "renderLoading", | ||
value: function renderLoading() { | ||
var renderedLoading = this.options.renderLoading(); | ||
if (!renderedLoading) { | ||
return; | ||
} | ||
if (this.mentionContainer.getElementsByClassName("ql-mention-loading").length > 0) { | ||
this.showMentionList(); | ||
return; | ||
} | ||
this.mentionList.innerHTML = ""; | ||
var loadingDiv = document.createElement("div"); | ||
loadingDiv.className = "ql-mention-loading"; | ||
loadingDiv.innerHTML = this.options.renderLoading(); | ||
this.mentionContainer.append(loadingDiv); | ||
this.showMentionList(); | ||
} | ||
}, { | ||
key: "removeLoading", | ||
value: function removeLoading() { | ||
var loadingDiv = this.mentionContainer.getElementsByClassName("ql-mention-loading"); | ||
if (loadingDiv.length > 0) { | ||
loadingDiv[0].remove(); | ||
} | ||
} | ||
}, { | ||
key: "renderList", | ||
value: function renderList(mentionChar, data, searchTerm) { | ||
if (data && data.length > 0) { | ||
this.removeLoading(); | ||
this.values = data; | ||
this.mentionList.innerHTML = ""; | ||
var initialSelection = -1; | ||
@@ -528,11 +621,25 @@ for (var i = 0; i < data.length; i += 1) { | ||
li.className = this.options.listItemClass ? this.options.listItemClass : ""; | ||
if (data[i].disabled) { | ||
li.className += " disabled"; | ||
} else if (initialSelection === -1) { | ||
initialSelection = i; | ||
} | ||
li.dataset.index = i; | ||
li.innerHTML = this.options.renderItem(data[i], searchTerm); | ||
li.onmouseenter = this.onItemMouseEnter.bind(this); | ||
if (!data[i].disabled) { | ||
li.onmouseenter = this.onItemMouseEnter.bind(this); | ||
li.onmouseup = this.onItemClick.bind(this); | ||
li.onmousedown = this.onItemMouseDown.bind(this); | ||
} else { | ||
li.onmouseenter = this.onDisabledItemMouseEnter.bind(this); | ||
} | ||
li.dataset.denotationChar = mentionChar; | ||
li.onclick = this.onItemClick.bind(this); | ||
this.mentionList.appendChild(attachDataValues(li, data[i], this.options.dataAttributes)); | ||
} | ||
this.itemIndex = 0; | ||
this.itemIndex = initialSelection; | ||
this.highlightItem(); | ||
@@ -547,3 +654,18 @@ this.showMentionList(); | ||
value: function nextItem() { | ||
this.itemIndex = (this.itemIndex + 1) % this.values.length; | ||
var increment = 0; | ||
var newIndex; | ||
do { | ||
increment++; | ||
newIndex = (this.itemIndex + increment) % this.values.length; | ||
var disabled = this.mentionList.childNodes[newIndex].dataset.disabled === "true"; | ||
if (increment === this.values.length + 1) { | ||
//we've wrapped around w/o finding an enabled item | ||
newIndex = -1; | ||
break; | ||
} | ||
} while (disabled); | ||
this.itemIndex = newIndex; | ||
this.suspendMouseEnter = true; | ||
@@ -555,3 +677,18 @@ this.highlightItem(); | ||
value: function prevItem() { | ||
this.itemIndex = (this.itemIndex + this.values.length - 1) % this.values.length; | ||
var decrement = 0; | ||
var newIndex; | ||
do { | ||
decrement++; | ||
newIndex = (this.itemIndex + this.values.length - decrement) % this.values.length; | ||
var disabled = this.mentionList.childNodes[newIndex].dataset.disabled === "true"; | ||
if (decrement === this.values.length + 1) { | ||
//we've wrapped around w/o finding an enabled item | ||
newIndex = -1; | ||
break; | ||
} | ||
} while (disabled); | ||
this.itemIndex = newIndex; | ||
this.suspendMouseEnter = true; | ||
@@ -593,2 +730,11 @@ this.highlightItem(); | ||
value: function setMentionContainerPosition() { | ||
if (this.options.positioningStrategy === "fixed") { | ||
this.setMentionContainerPosition_Fixed(); | ||
} else { | ||
this.setMentionContainerPosition_Normal(); | ||
} | ||
} | ||
}, { | ||
key: "setMentionContainerPosition_Normal", | ||
value: function setMentionContainerPosition_Normal() { | ||
var _this2 = this; | ||
@@ -675,2 +821,83 @@ | ||
}, { | ||
key: "setMentionContainerPosition_Fixed", | ||
value: function setMentionContainerPosition_Fixed() { | ||
var _this3 = this; | ||
this.mentionContainer.style.position = "fixed"; | ||
this.mentionContainer.style.height = null; | ||
var containerPos = this.quill.container.getBoundingClientRect(); | ||
var mentionCharPos = this.quill.getBounds(this.mentionCharPos); | ||
var mentionCharPosAbsolute = { | ||
left: containerPos.left + mentionCharPos.left, | ||
top: containerPos.top + mentionCharPos.top, | ||
width: 0, | ||
height: mentionCharPos.height | ||
}; //Which rectangle should it be relative to | ||
var relativeToPos = this.options.fixMentionsToQuill ? containerPos : mentionCharPosAbsolute; | ||
var topPos = this.options.offsetTop; | ||
var leftPos = this.options.offsetLeft; // handle horizontal positioning | ||
if (this.options.fixMentionsToQuill) { | ||
var rightPos = relativeToPos.right; | ||
this.mentionContainer.style.right = "".concat(rightPos, "px"); | ||
} else { | ||
leftPos += relativeToPos.left; //if its off the righ edge, push it back | ||
if (leftPos + this.mentionContainer.offsetWidth > document.documentElement.clientWidth) { | ||
leftPos -= leftPos + this.mentionContainer.offsetWidth - document.documentElement.clientWidth; | ||
} | ||
} | ||
var availableSpaceTop = relativeToPos.top; | ||
var availableSpaceBottom = document.documentElement.clientHeight - (relativeToPos.top + relativeToPos.height); | ||
var fitsBottom = this.mentionContainer.offsetHeight <= availableSpaceBottom; | ||
var fitsTop = this.mentionContainer.offsetHeight <= availableSpaceTop; | ||
var placement; | ||
if (this.options.defaultMenuOrientation === "top" && fitsTop) { | ||
placement = "top"; | ||
} else if (this.options.defaultMenuOrientation === "bottom" && fitsBottom) { | ||
placement = "bottom"; | ||
} else { | ||
//it doesnt fit either so put it where there's the most space | ||
placement = availableSpaceBottom > availableSpaceTop ? "bottom" : "top"; | ||
} | ||
if (placement === "bottom") { | ||
topPos = relativeToPos.top + relativeToPos.height; | ||
if (!fitsBottom) { | ||
//shrink it to fit | ||
//3 is a bit of a fudge factor so it doesnt touch the edge of the screen | ||
this.mentionContainer.style.height = availableSpaceBottom - 3 + "px"; | ||
} | ||
this.options.mentionContainerClass.split(" ").forEach(function (className) { | ||
_this3.mentionContainer.classList.add("".concat(className, "-bottom")); | ||
_this3.mentionContainer.classList.remove("".concat(className, "-top")); | ||
}); | ||
} else { | ||
topPos = relativeToPos.top - this.mentionContainer.offsetHeight; | ||
if (!fitsTop) { | ||
//shrink it to fit | ||
//3 is a bit of a fudge factor so it doesnt touch the edge of the screen | ||
this.mentionContainer.style.height = availableSpaceTop - 3 + "px"; | ||
topPos = 3; | ||
} | ||
this.options.mentionContainerClass.split(" ").forEach(function (className) { | ||
_this3.mentionContainer.classList.add("".concat(className, "-top")); | ||
_this3.mentionContainer.classList.remove("".concat(className, "-bottom")); | ||
}); | ||
} | ||
this.mentionContainer.style.top = "".concat(topPos, "px"); | ||
this.mentionContainer.style.left = "".concat(leftPos, "px"); | ||
this.mentionContainer.style.visibility = "visible"; | ||
} | ||
}, { | ||
key: "getTextBeforeCursor", | ||
@@ -685,2 +912,4 @@ value: function getTextBeforeCursor() { | ||
value: function onSomethingChange() { | ||
var _this4 = this; | ||
var range = this.quill.getSelection(); | ||
@@ -700,4 +929,21 @@ if (range == null) return; | ||
if (textAfter.length >= this.options.minChars && hasValidChars(textAfter, this.options.allowedChars)) { | ||
this.options.source(textAfter, this.renderList.bind(this, mentionChar), mentionChar); | ||
if (textAfter.length >= this.options.minChars && hasValidChars(textAfter, this.getAllowedCharsRegex(mentionChar))) { | ||
if (this.existingSourceExecutionToken) { | ||
this.existingSourceExecutionToken.abandoned = true; | ||
} | ||
this.renderLoading(); | ||
var sourceRequestToken = { | ||
abandoned: false | ||
}; | ||
this.existingSourceExecutionToken = sourceRequestToken; | ||
this.options.source(textAfter, function (data, searchTerm) { | ||
if (sourceRequestToken.abandoned) { | ||
return; | ||
} | ||
_this4.existingSourceExecutionToken = null; | ||
_this4.renderList(mentionChar, data, searchTerm); | ||
}, mentionChar); | ||
} else { | ||
@@ -711,2 +957,11 @@ this.hideMentionList(); | ||
}, { | ||
key: "getAllowedCharsRegex", | ||
value: function getAllowedCharsRegex(denotationChar) { | ||
if (this.options.allowedChars instanceof RegExp) { | ||
return this.options.allowedChars; | ||
} else { | ||
return this.options.allowedChars(denotationChar); | ||
} | ||
} | ||
}, { | ||
key: "onTextChange", | ||
@@ -727,2 +982,10 @@ value: function onTextChange(delta, oldDelta, source) { | ||
} | ||
}, { | ||
key: "openMenu", | ||
value: function openMenu(denotationChar) { | ||
var selection = this.quill.getSelection(true); | ||
this.quill.insertText(selection.index, denotationChar); | ||
this.quill.blur(); | ||
this.quill.focus(); | ||
} | ||
}]); | ||
@@ -729,0 +992,0 @@ |
@@ -1,1 +0,1 @@ | ||
var quillMention=function(t){"use strict";function e(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function n(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function i(t,e,i){return e&&n(t.prototype,e),i&&n(t,i),t}function o(){return(o=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(t[i]=n[i])}return t}).apply(this,arguments)}function s(t){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function r(t,e){return(r=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function a(t,e){return!e||"object"!=typeof e&&"function"!=typeof e?function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t):e}function h(t){var e=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],(function(){}))),!0}catch(t){return!1}}();return function(){var n,i=s(t);if(e){var o=s(this).constructor;n=Reflect.construct(i,arguments,o)}else n=i.apply(this,arguments);return a(this,n)}}function l(t,e,n){return(l="undefined"!=typeof Reflect&&Reflect.get?Reflect.get:function(t,e,n){var i=function(t,e){for(;!Object.prototype.hasOwnProperty.call(t,e)&&null!==(t=s(t)););return t}(t,e);if(i){var o=Object.getOwnPropertyDescriptor(i,e);return o.get?o.get.call(n):o.value}})(t,e,n||t)}t=t&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t;var u=9,c=13,d=27,f=38,m=40;function p(t,e,n){var i=t;return Object.keys(e).forEach((function(t){n.indexOf(t)>-1?i.dataset[t]=e[t]:delete i.dataset[t]})),i}var C=function(t){!function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&r(t,e)}(o,t);var n=h(o);function o(){return e(this,o),n.apply(this,arguments)}return i(o,null,[{key:"create",value:function(t){var e=l(s(o),"create",this).call(this),n=document.createElement("span");return n.className="ql-mention-denotation-char",n.innerHTML=t.denotationChar,e.appendChild(n),e.innerHTML+=t.value,o.setDataValues(e,t)}},{key:"setDataValues",value:function(t,e){var n=t;return Object.keys(e).forEach((function(t){n.dataset[t]=e[t]})),n}},{key:"value",value:function(t){return t.dataset}}]),o}(t.import("blots/embed"));C.blotName="mention",C.tagName="span",C.className="mention",t.register(C);var v=function(){function n(t,i){e(this,n),this.isOpen=!1,this.itemIndex=0,this.mentionCharPos=null,this.cursorPos=null,this.values=[],this.suspendMouseEnter=!1,this.quill=t,this.options={source:null,renderItem:function(t){return"".concat(t.value)},onSelect:function(t,e){e(t)},mentionDenotationChars:["@"],showDenotationChar:!0,allowedChars:/^[a-zA-Z0-9_]*$/,minChars:0,maxChars:31,offsetTop:2,offsetLeft:0,isolateCharacter:!1,fixMentionsToQuill:!1,defaultMenuOrientation:"bottom",blotName:"mention",dataAttributes:["id","value","denotationChar","link","target"],linkTarget:"_blank",onOpen:function(){return!0},onClose:function(){return!0},listItemClass:"ql-mention-list-item",mentionContainerClass:"ql-mention-list-container",mentionListClass:"ql-mention-list",spaceAfterInsert:!0},o(this.options,i,{dataAttributes:Array.isArray(i.dataAttributes)?this.options.dataAttributes.concat(i.dataAttributes):this.options.dataAttributes}),this.mentionContainer=document.createElement("div"),this.mentionContainer.className=this.options.mentionContainerClass?this.options.mentionContainerClass:"",this.mentionContainer.style.cssText="display: none; position: absolute;",this.mentionContainer.onmousemove=this.onContainerMouseMove.bind(this),this.options.fixMentionsToQuill&&(this.mentionContainer.style.width="auto"),this.mentionList=document.createElement("ul"),this.mentionList.className=this.options.mentionListClass?this.options.mentionListClass:"",this.mentionContainer.appendChild(this.mentionList),this.quill.container.appendChild(this.mentionContainer),t.on("text-change",this.onTextChange.bind(this)),t.on("selection-change",this.onSelectionChange.bind(this)),t.keyboard.addBinding({key:u},this.selectHandler.bind(this)),t.keyboard.bindings[u].unshift(t.keyboard.bindings[u].pop()),t.keyboard.addBinding({key:c},this.selectHandler.bind(this)),t.keyboard.bindings[c].unshift(t.keyboard.bindings[c].pop()),t.keyboard.addBinding({key:d},this.escapeHandler.bind(this)),t.keyboard.addBinding({key:f},this.upHandler.bind(this)),t.keyboard.addBinding({key:m},this.downHandler.bind(this))}return i(n,[{key:"selectHandler",value:function(){return!this.isOpen||(this.selectItem(),!1)}},{key:"escapeHandler",value:function(){return!this.isOpen||(this.hideMentionList(),!1)}},{key:"upHandler",value:function(){return!this.isOpen||(this.prevItem(),!1)}},{key:"downHandler",value:function(){return!this.isOpen||(this.nextItem(),!1)}},{key:"showMentionList",value:function(){this.mentionContainer.style.visibility="hidden",this.mentionContainer.style.display="",this.setMentionContainerPosition(),this.setIsOpen(!0)}},{key:"hideMentionList",value:function(){this.mentionContainer.style.display="none",this.setIsOpen(!1)}},{key:"highlightItem",value:function(){for(var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0],e=0;e<this.mentionList.childNodes.length;e+=1)this.mentionList.childNodes[e].classList.remove("selected");if(this.mentionList.childNodes[this.itemIndex].classList.add("selected"),t){var n=this.mentionList.childNodes[this.itemIndex].offsetHeight,i=this.itemIndex*n,o=this.mentionContainer.scrollTop,s=o+this.mentionContainer.offsetHeight;i<o?this.mentionContainer.scrollTop=i:i>s-n&&(this.mentionContainer.scrollTop+=i-s+n)}}},{key:"getItemData",value:function(){var t=this.mentionList.childNodes[this.itemIndex].dataset.link,e=void 0!==t,n=this.mentionList.childNodes[this.itemIndex].dataset.target;return e&&(this.mentionList.childNodes[this.itemIndex].dataset.value='<a href="'.concat(t,'" target=').concat(n||this.options.linkTarget,">").concat(this.mentionList.childNodes[this.itemIndex].dataset.value)),this.mentionList.childNodes[this.itemIndex].dataset}},{key:"onContainerMouseMove",value:function(){this.suspendMouseEnter=!1}},{key:"selectItem",value:function(){var t=this,e=this.getItemData();this.options.onSelect(e,(function(e){t.insertItem(e)})),this.hideMentionList()}},{key:"insertItem",value:function(e){var n=e;if(null!==n){this.options.showDenotationChar||(n.denotationChar="");var i=this.mentionCharPos;this.quill.deleteText(this.mentionCharPos,this.cursorPos-this.mentionCharPos,t.sources.USER),this.quill.insertEmbed(i,this.options.blotName,n,t.sources.USER),this.options.spaceAfterInsert?(this.quill.insertText(i+1," ",t.sources.USER),this.quill.setSelection(i+2,t.sources.USER)):this.quill.setSelection(i+1,t.sources.USER),this.hideMentionList()}}},{key:"onItemMouseEnter",value:function(t){if(!this.suspendMouseEnter){var e=Number(t.target.dataset.index);Number.isNaN(e)||e===this.itemIndex||(this.itemIndex=e,this.highlightItem(!1))}}},{key:"onItemClick",value:function(t){t.preventDefault(),t.stopImmediatePropagation(),this.itemIndex=t.currentTarget.dataset.index,this.highlightItem(),this.selectItem()}},{key:"renderList",value:function(t,e,n){if(e&&e.length>0){this.values=e,this.mentionList.innerHTML="";for(var i=0;i<e.length;i+=1){var o=document.createElement("li");o.className=this.options.listItemClass?this.options.listItemClass:"",o.dataset.index=i,o.innerHTML=this.options.renderItem(e[i],n),o.onmouseenter=this.onItemMouseEnter.bind(this),o.dataset.denotationChar=t,o.onclick=this.onItemClick.bind(this),this.mentionList.appendChild(p(o,e[i],this.options.dataAttributes))}this.itemIndex=0,this.highlightItem(),this.showMentionList()}else this.hideMentionList()}},{key:"nextItem",value:function(){this.itemIndex=(this.itemIndex+1)%this.values.length,this.suspendMouseEnter=!0,this.highlightItem()}},{key:"prevItem",value:function(){this.itemIndex=(this.itemIndex+this.values.length-1)%this.values.length,this.suspendMouseEnter=!0,this.highlightItem()}},{key:"containerBottomIsNotVisible",value:function(t,e){return t+this.mentionContainer.offsetHeight+e.top>window.pageYOffset+window.innerHeight}},{key:"containerRightIsNotVisible",value:function(t,e){return!this.options.fixMentionsToQuill&&t+this.mentionContainer.offsetWidth+e.left>window.pageXOffset+document.documentElement.clientWidth}},{key:"setIsOpen",value:function(t){this.isOpen!==t&&(t?this.options.onOpen():this.options.onClose(),this.isOpen=t)}},{key:"setMentionContainerPosition",value:function(){var t=this,e=this.quill.container.getBoundingClientRect(),n=this.quill.getBounds(this.mentionCharPos),i=this.mentionContainer.offsetHeight,o=this.options.offsetTop,s=this.options.offsetLeft;if(this.options.fixMentionsToQuill){this.mentionContainer.style.right="".concat(0,"px")}else s+=n.left;if(this.containerRightIsNotVisible(s,e)){var r=this.mentionContainer.offsetWidth+this.options.offsetLeft;s=e.width-r}if("top"===this.options.defaultMenuOrientation){if((o=this.options.fixMentionsToQuill?-1*(i+this.options.offsetTop):n.top-(i+this.options.offsetTop))+e.top<=0){var a=this.options.offsetTop;this.options.fixMentionsToQuill?a+=e.height:a+=n.bottom,o=a}}else if(this.options.fixMentionsToQuill?o+=e.height:o+=n.bottom,this.containerBottomIsNotVisible(o,e)){var h=-1*this.options.offsetTop;this.options.fixMentionsToQuill||(h+=n.top),o=h-i}o>=0?this.options.mentionContainerClass.split(" ").forEach((function(e){t.mentionContainer.classList.add("".concat(e,"-bottom")),t.mentionContainer.classList.remove("".concat(e,"-top"))})):this.options.mentionContainerClass.split(" ").forEach((function(e){t.mentionContainer.classList.add("".concat(e,"-top")),t.mentionContainer.classList.remove("".concat(e,"-bottom"))})),this.mentionContainer.style.top="".concat(o,"px"),this.mentionContainer.style.left="".concat(s,"px"),this.mentionContainer.style.visibility="visible"}},{key:"getTextBeforeCursor",value:function(){var t=Math.max(0,this.cursorPos-this.options.maxChars);return this.quill.getText(t,this.cursorPos-t)}},{key:"onSomethingChange",value:function(){var t=this.quill.getSelection();if(null!=t){this.cursorPos=t.index;var e,n=this.getTextBeforeCursor(),i=(e=n,this.options.mentionDenotationChars.reduce((function(t,n){var i=e.lastIndexOf(n);return i>t.mentionCharIndex?{mentionChar:n,mentionCharIndex:i}:{mentionChar:t.mentionChar,mentionCharIndex:t.mentionCharIndex}}),{mentionChar:null,mentionCharIndex:-1})),o=i.mentionChar,s=i.mentionCharIndex;if(function(t,e,n){return t>-1&&!(n&&0!==t&&!e[t-1].match(/\s/g))}(s,n,this.options.isolateCharacter)){var r=this.cursorPos-(n.length-s);this.mentionCharPos=r;var a=n.substring(s+o.length);a.length>=this.options.minChars&&function(t,e){return e.test(t)}(a,this.options.allowedChars)?this.options.source(a,this.renderList.bind(this,o),o):this.hideMentionList()}else this.hideMentionList()}}},{key:"onTextChange",value:function(t,e,n){"user"===n&&this.onSomethingChange()}},{key:"onSelectionChange",value:function(t){t&&0===t.length?this.onSomethingChange():this.hideMentionList()}}]),n}();return t.register("modules/mention",v),v}(Quill); | ||
var quillMention=function(t){"use strict";function e(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function n(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function i(t,e,i){return e&&n(t.prototype,e),i&&n(t,i),t}function o(){return(o=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(t[i]=n[i])}return t}).apply(this,arguments)}function s(t){return(s=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function a(t,e){return(a=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function r(t,e){return!e||"object"!=typeof e&&"function"!=typeof e?function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t):e}function h(t){var e=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],(function(){}))),!0}catch(t){return!1}}();return function(){var n,i=s(t);if(e){var o=s(this).constructor;n=Reflect.construct(i,arguments,o)}else n=i.apply(this,arguments);return r(this,n)}}function l(t,e,n){return(l="undefined"!=typeof Reflect&&Reflect.get?Reflect.get:function(t,e,n){var i=function(t,e){for(;!Object.prototype.hasOwnProperty.call(t,e)&&null!==(t=s(t)););return t}(t,e);if(i){var o=Object.getOwnPropertyDescriptor(i,e);return o.get?o.get.call(n):o.value}})(t,e,n||t)}t=t&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t;var u=9,c=13,d=27,m=38,f=40;function p(t,e,n){var i=t;return Object.keys(e).forEach((function(t){n.indexOf(t)>-1?i.dataset[t]=e[t]:delete i.dataset[t]})),i}var g=function(t){!function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&a(t,e)}(o,t);var n=h(o);function o(){return e(this,o),n.apply(this,arguments)}return i(o,null,[{key:"create",value:function(t){var e=l(s(o),"create",this).call(this),n=document.createElement("span");return n.className="ql-mention-denotation-char",n.innerHTML=t.denotationChar,e.appendChild(n),e.innerHTML+=t.value,o.setDataValues(e,t)}},{key:"setDataValues",value:function(t,e){var n=t;return Object.keys(e).forEach((function(t){n.dataset[t]=e[t]})),n}},{key:"value",value:function(t){return t.dataset}}]),o}(t.import("blots/embed"));g.blotName="mention",g.tagName="span",g.className="mention",t.register(g);var C=function(){function n(t,i){e(this,n),this.isOpen=!1,this.itemIndex=0,this.mentionCharPos=null,this.cursorPos=null,this.values=[],this.suspendMouseEnter=!1,this.existingSourceExecutionToken=null,this.quill=t,this.options={source:null,renderItem:function(t){return"".concat(t.value)},renderLoading:function(){return null},onSelect:function(t,e){e(t)},mentionDenotationChars:["@"],showDenotationChar:!0,allowedChars:/^[a-zA-Z0-9_]*$/,minChars:0,maxChars:31,offsetTop:2,offsetLeft:0,isolateCharacter:!1,fixMentionsToQuill:!1,positioningStrategy:"normal",defaultMenuOrientation:"bottom",blotName:"mention",dataAttributes:["id","value","denotationChar","link","target","disabled"],linkTarget:"_blank",onOpen:function(){return!0},onClose:function(){return!0},listItemClass:"ql-mention-list-item",mentionContainerClass:"ql-mention-list-container",mentionListClass:"ql-mention-list",spaceAfterInsert:!0},o(this.options,i,{dataAttributes:Array.isArray(i.dataAttributes)?this.options.dataAttributes.concat(i.dataAttributes):this.options.dataAttributes}),this.mentionContainer=document.createElement("div"),this.mentionContainer.className=this.options.mentionContainerClass?this.options.mentionContainerClass:"",this.mentionContainer.style.cssText="display: none; position: absolute;",this.mentionContainer.onmousemove=this.onContainerMouseMove.bind(this),this.options.fixMentionsToQuill&&(this.mentionContainer.style.width="auto"),this.mentionList=document.createElement("ul"),this.mentionList.className=this.options.mentionListClass?this.options.mentionListClass:"",this.mentionContainer.appendChild(this.mentionList),t.on("text-change",this.onTextChange.bind(this)),t.on("selection-change",this.onSelectionChange.bind(this)),t.keyboard.addBinding({key:u},this.selectHandler.bind(this)),t.keyboard.bindings[u].unshift(t.keyboard.bindings[u].pop()),t.keyboard.addBinding({key:c},this.selectHandler.bind(this)),t.keyboard.bindings[c].unshift(t.keyboard.bindings[c].pop()),t.keyboard.addBinding({key:d},this.escapeHandler.bind(this)),t.keyboard.addBinding({key:m},this.upHandler.bind(this)),t.keyboard.addBinding({key:f},this.downHandler.bind(this))}return i(n,[{key:"selectHandler",value:function(){return!(this.isOpen&&!this.existingSourceExecutionToken)||(this.selectItem(),!1)}},{key:"escapeHandler",value:function(){return!this.isOpen||(this.existingSourceExecutionToken&&(this.existingSourceExecutionToken.abandoned=!0),this.hideMentionList(),!1)}},{key:"upHandler",value:function(){return!(this.isOpen&&!this.existingSourceExecutionToken)||(this.prevItem(),!1)}},{key:"downHandler",value:function(){return!(this.isOpen&&!this.existingSourceExecutionToken)||(this.nextItem(),!1)}},{key:"showMentionList",value:function(){"fixed"===this.options.positioningStrategy?document.body.appendChild(this.mentionContainer):this.quill.container.appendChild(this.mentionContainer),this.mentionContainer.style.visibility="hidden",this.mentionContainer.style.display="",this.mentionContainer.scrollTop=0,this.setMentionContainerPosition(),this.setIsOpen(!0)}},{key:"hideMentionList",value:function(){this.mentionContainer.style.display="none",this.mentionContainer.remove(),this.setIsOpen(!1)}},{key:"highlightItem",value:function(){for(var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0],e=0;e<this.mentionList.childNodes.length;e+=1)this.mentionList.childNodes[e].classList.remove("selected");if(-1!==this.itemIndex&&"true"!==this.mentionList.childNodes[this.itemIndex].dataset.disabled&&(this.mentionList.childNodes[this.itemIndex].classList.add("selected"),t)){var n=this.mentionList.childNodes[this.itemIndex].offsetHeight,i=this.mentionList.childNodes[this.itemIndex].offsetTop,o=this.mentionContainer.scrollTop,s=o+this.mentionContainer.offsetHeight;i<o?this.mentionContainer.scrollTop=i:i>s-n&&(this.mentionContainer.scrollTop+=i-s+n)}}},{key:"getItemData",value:function(){var t=this.mentionList.childNodes[this.itemIndex].dataset.link,e=void 0!==t,n=this.mentionList.childNodes[this.itemIndex].dataset.target;return e&&(this.mentionList.childNodes[this.itemIndex].dataset.value='<a href="'.concat(t,'" target=').concat(n||this.options.linkTarget,">").concat(this.mentionList.childNodes[this.itemIndex].dataset.value)),this.mentionList.childNodes[this.itemIndex].dataset}},{key:"onContainerMouseMove",value:function(){this.suspendMouseEnter=!1}},{key:"selectItem",value:function(){var t=this;if(-1!==this.itemIndex){var e=this.getItemData();e.disabled||(this.options.onSelect(e,(function(e){t.insertItem(e)})),this.hideMentionList())}}},{key:"insertItem",value:function(e,n){var i,o=e;null!==o&&(this.options.showDenotationChar||(o.denotationChar=""),n?i=this.cursorPos:(i=this.mentionCharPos,this.quill.deleteText(this.mentionCharPos,this.cursorPos-this.mentionCharPos,t.sources.USER)),this.quill.insertEmbed(i,this.options.blotName,o,t.sources.USER),this.options.spaceAfterInsert?(this.quill.insertText(i+1," ",t.sources.USER),this.quill.setSelection(i+2,t.sources.USER)):this.quill.setSelection(i+1,t.sources.USER),this.hideMentionList())}},{key:"onItemMouseEnter",value:function(t){if(!this.suspendMouseEnter){var e=Number(t.target.dataset.index);Number.isNaN(e)||e===this.itemIndex||(this.itemIndex=e,this.highlightItem(!1))}}},{key:"onDisabledItemMouseEnter",value:function(t){this.suspendMouseEnter||(this.itemIndex=-1,this.highlightItem(!1))}},{key:"onItemClick",value:function(t){0===t.button&&(t.preventDefault(),t.stopImmediatePropagation(),this.itemIndex=t.currentTarget.dataset.index,this.highlightItem(),this.selectItem())}},{key:"onItemMouseDown",value:function(t){t.preventDefault(),t.stopImmediatePropagation()}},{key:"renderLoading",value:function(){if(this.options.renderLoading())if(this.mentionContainer.getElementsByClassName("ql-mention-loading").length>0)this.showMentionList();else{this.mentionList.innerHTML="";var t=document.createElement("div");t.className="ql-mention-loading",t.innerHTML=this.options.renderLoading(),this.mentionContainer.append(t),this.showMentionList()}}},{key:"removeLoading",value:function(){var t=this.mentionContainer.getElementsByClassName("ql-mention-loading");t.length>0&&t[0].remove()}},{key:"renderList",value:function(t,e,n){if(e&&e.length>0){this.removeLoading(),this.values=e,this.mentionList.innerHTML="";for(var i=-1,o=0;o<e.length;o+=1){var s=document.createElement("li");s.className=this.options.listItemClass?this.options.listItemClass:"",e[o].disabled?s.className+=" disabled":-1===i&&(i=o),s.dataset.index=o,s.innerHTML=this.options.renderItem(e[o],n),e[o].disabled?s.onmouseenter=this.onDisabledItemMouseEnter.bind(this):(s.onmouseenter=this.onItemMouseEnter.bind(this),s.onmouseup=this.onItemClick.bind(this),s.onmousedown=this.onItemMouseDown.bind(this)),s.dataset.denotationChar=t,this.mentionList.appendChild(p(s,e[o],this.options.dataAttributes))}this.itemIndex=i,this.highlightItem(),this.showMentionList()}else this.hideMentionList()}},{key:"nextItem",value:function(){var t,e=0;do{e++,t=(this.itemIndex+e)%this.values.length;var n="true"===this.mentionList.childNodes[t].dataset.disabled;if(e===this.values.length+1){t=-1;break}}while(n);this.itemIndex=t,this.suspendMouseEnter=!0,this.highlightItem()}},{key:"prevItem",value:function(){var t,e=0;do{e++,t=(this.itemIndex+this.values.length-e)%this.values.length;var n="true"===this.mentionList.childNodes[t].dataset.disabled;if(e===this.values.length+1){t=-1;break}}while(n);this.itemIndex=t,this.suspendMouseEnter=!0,this.highlightItem()}},{key:"containerBottomIsNotVisible",value:function(t,e){return t+this.mentionContainer.offsetHeight+e.top>window.pageYOffset+window.innerHeight}},{key:"containerRightIsNotVisible",value:function(t,e){return!this.options.fixMentionsToQuill&&t+this.mentionContainer.offsetWidth+e.left>window.pageXOffset+document.documentElement.clientWidth}},{key:"setIsOpen",value:function(t){this.isOpen!==t&&(t?this.options.onOpen():this.options.onClose(),this.isOpen=t)}},{key:"setMentionContainerPosition",value:function(){"fixed"===this.options.positioningStrategy?this.setMentionContainerPosition_Fixed():this.setMentionContainerPosition_Normal()}},{key:"setMentionContainerPosition_Normal",value:function(){var t=this,e=this.quill.container.getBoundingClientRect(),n=this.quill.getBounds(this.mentionCharPos),i=this.mentionContainer.offsetHeight,o=this.options.offsetTop,s=this.options.offsetLeft;if(this.options.fixMentionsToQuill){this.mentionContainer.style.right="".concat(0,"px")}else s+=n.left;if(this.containerRightIsNotVisible(s,e)){var a=this.mentionContainer.offsetWidth+this.options.offsetLeft;s=e.width-a}if("top"===this.options.defaultMenuOrientation){if((o=this.options.fixMentionsToQuill?-1*(i+this.options.offsetTop):n.top-(i+this.options.offsetTop))+e.top<=0){var r=this.options.offsetTop;this.options.fixMentionsToQuill?r+=e.height:r+=n.bottom,o=r}}else if(this.options.fixMentionsToQuill?o+=e.height:o+=n.bottom,this.containerBottomIsNotVisible(o,e)){var h=-1*this.options.offsetTop;this.options.fixMentionsToQuill||(h+=n.top),o=h-i}o>=0?this.options.mentionContainerClass.split(" ").forEach((function(e){t.mentionContainer.classList.add("".concat(e,"-bottom")),t.mentionContainer.classList.remove("".concat(e,"-top"))})):this.options.mentionContainerClass.split(" ").forEach((function(e){t.mentionContainer.classList.add("".concat(e,"-top")),t.mentionContainer.classList.remove("".concat(e,"-bottom"))})),this.mentionContainer.style.top="".concat(o,"px"),this.mentionContainer.style.left="".concat(s,"px"),this.mentionContainer.style.visibility="visible"}},{key:"setMentionContainerPosition_Fixed",value:function(){var t=this;this.mentionContainer.style.position="fixed",this.mentionContainer.style.height=null;var e=this.quill.container.getBoundingClientRect(),n=this.quill.getBounds(this.mentionCharPos),i={left:e.left+n.left,top:e.top+n.top,width:0,height:n.height},o=this.options.fixMentionsToQuill?e:i,s=this.options.offsetTop,a=this.options.offsetLeft;if(this.options.fixMentionsToQuill){var r=o.right;this.mentionContainer.style.right="".concat(r,"px")}else(a+=o.left)+this.mentionContainer.offsetWidth>document.documentElement.clientWidth&&(a-=a+this.mentionContainer.offsetWidth-document.documentElement.clientWidth);var h=o.top,l=document.documentElement.clientHeight-(o.top+o.height),u=this.mentionContainer.offsetHeight<=l,c=this.mentionContainer.offsetHeight<=h;"bottom"===("top"===this.options.defaultMenuOrientation&&c?"top":"bottom"===this.options.defaultMenuOrientation&&u||l>h?"bottom":"top")?(s=o.top+o.height,u||(this.mentionContainer.style.height=l-3+"px"),this.options.mentionContainerClass.split(" ").forEach((function(e){t.mentionContainer.classList.add("".concat(e,"-bottom")),t.mentionContainer.classList.remove("".concat(e,"-top"))}))):(s=o.top-this.mentionContainer.offsetHeight,c||(this.mentionContainer.style.height=h-3+"px",s=3),this.options.mentionContainerClass.split(" ").forEach((function(e){t.mentionContainer.classList.add("".concat(e,"-top")),t.mentionContainer.classList.remove("".concat(e,"-bottom"))}))),this.mentionContainer.style.top="".concat(s,"px"),this.mentionContainer.style.left="".concat(a,"px"),this.mentionContainer.style.visibility="visible"}},{key:"getTextBeforeCursor",value:function(){var t=Math.max(0,this.cursorPos-this.options.maxChars);return this.quill.getText(t,this.cursorPos-t)}},{key:"onSomethingChange",value:function(){var t=this,e=this.quill.getSelection();if(null!=e){this.cursorPos=e.index;var n,i=this.getTextBeforeCursor(),o=(n=i,this.options.mentionDenotationChars.reduce((function(t,e){var i=n.lastIndexOf(e);return i>t.mentionCharIndex?{mentionChar:e,mentionCharIndex:i}:{mentionChar:t.mentionChar,mentionCharIndex:t.mentionCharIndex}}),{mentionChar:null,mentionCharIndex:-1})),s=o.mentionChar,a=o.mentionCharIndex;if(function(t,e,n){return t>-1&&!(n&&0!==t&&!e[t-1].match(/\s/g))}(a,i,this.options.isolateCharacter)){var r=this.cursorPos-(i.length-a);this.mentionCharPos=r;var h=i.substring(a+s.length);if(h.length>=this.options.minChars&&function(t,e){return e.test(t)}(h,this.getAllowedCharsRegex(s))){this.existingSourceExecutionToken&&(this.existingSourceExecutionToken.abandoned=!0),this.renderLoading();var l={abandoned:!1};this.existingSourceExecutionToken=l,this.options.source(h,(function(e,n){l.abandoned||(t.existingSourceExecutionToken=null,t.renderList(s,e,n))}),s)}else this.hideMentionList()}else this.hideMentionList()}}},{key:"getAllowedCharsRegex",value:function(t){return this.options.allowedChars instanceof RegExp?this.options.allowedChars:this.options.allowedChars(t)}},{key:"onTextChange",value:function(t,e,n){"user"===n&&this.onSomethingChange()}},{key:"onSelectionChange",value:function(t){t&&0===t.length?this.onSomethingChange():this.hideMentionList()}},{key:"openMenu",value:function(t){var e=this.quill.getSelection(!0);this.quill.insertText(e.index,t),this.quill.blur(),this.quill.focus()}}]),n}();return t.register("modules/mention",C),C}(Quill); |
{ | ||
"name": "quill-mention", | ||
"version": "2.2.7", | ||
"version": "3.0.0", | ||
"description": "@mentions for the Quill rich text editor", | ||
@@ -5,0 +5,0 @@ "main": "dist/quill.mention.csj.js", |
@@ -141,27 +141,38 @@ ![Quill Mention](docs/static/quill-mention.png "Quill Mention") | ||
| Property | Default | Description | | ||
| --------------------------------------------- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `source(searchTerm, renderList, mentionChar)` | `null` | Required callback function to handle the search term and connect it to a data source for matches. The data source can be a local source or an AJAX request. The callback should call `renderList(matches, searchTerm);` with matches of JSON Objects in an array to show the result for the user. The JSON Objects should have `id` and `value` but can also have other values to be used in `renderItem` for custom display. | | ||
| `renderItem(item, searchTerm)` | `function` | A function that gives you control over how matches from source are displayed. You can use this function to highlight the search term or change the design with custom HTML. | | ||
| `allowedChars` | `[a-zA-Z0-9_]` | Allowed characters in search term triggering a search request using regular expressions | | ||
| `minChars` | `0` | Minimum number of characters after the @ symbol triggering a search request | | ||
| `maxChars` | `31` | Maximum number of characters after the @ symbol triggering a search request | | ||
| `offsetTop` | `2` | Additional top offset of the mention container position | | ||
| `offsetLeft` | `0` | Additional left offset of the mention container position | | ||
| `mentionDenotationChars` | `["@"]` | Specifies which characters will cause the mention autocomplete to open | | ||
| `isolateCharacter` | `false` | Whether or not the denotation character(s) should be isolated. For example, to avoid mentioning in an email. | | ||
| `fixMentionsToQuill` | `false` | When set to true, the mentions menu will be rendered above or below the quill container. Otherwise, the mentions menu will track the denotation character(s); | | ||
| `showDenotationChar` | `true` | Whether to show the used denotation character in the mention item or not | | ||
| `defaultMenuOrientation` | `'bottom'` | Options are `'bottom'` and `'top'`. Determines what the default orientation of the menu will be. Quill-mention will attempt to render the menu either above or below the editor. If `'top'` is provided as a value, and there is not enough space above the editor, the menu will be rendered below. Vice versa, if there is not enough space below the editor, and `'bottom'` is provided as a value (or no value is provided at all), the menu will be rendered above the editor. | | ||
| `blotName` | `'mention'` | The name of the [Quill Blot](https://github.com/quilljs/parchment#blots) to be used for inserted mentions. A default implementation is provided named 'mention', which may be overidden with a custom blot. | ||
| `dataAttributes` | `['id', 'value', 'denotationChar', 'link', 'target']` | A list of data values you wish to be passed from your list data to the html node. (`id, value, denotationChar, link, target` are included by default). | | ||
| `onOpen` | `function` | Callback when mention dropdown is open. | | ||
| `onClose` | `function` | Callback when mention dropdown is closed. | | ||
| `onSelect(item, insertItem)` | `function` | Callback for a selected item. When overriding this method, `insertItem` should be used to insert `item` to the editor. This makes async requests possible. | | ||
| `linkTarget` | `'_blank'` | Link target for mentions with a link | | ||
| `listItemClass` | `'ql-mention-list-item'` | Style class to be used for list items (may be null) | | ||
| `mentionContainerClass` | `'ql-mention-list-container'` | Style class to be used for the mention list container (may be null) | | ||
| `mentionListClass` | `'ql-mention-list'` | Style class to be used for the mention list (may be null) | | ||
| `spaceAfterInsert` | `true` | Whether or not insert 1 space after mention block in text | | ||
| Property | Default | Description | | ||
| --------------------------------------------- | ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `source(searchTerm, renderList, mentionChar)` | `null` | Required callback function to handle the search term and connect it to a data source for matches. The data source can be a local source or an AJAX request. The callback should call `renderList(matches, searchTerm);` with matches of JSON Objects in an array to show the result for the user. The JSON Objects should have `id` and `value` but can also have other values to be used in `renderItem` for custom display. | | ||
| `renderItem(item, searchTerm)` | `function` | A function that gives you control over how matches from source are displayed. You can use this function to highlight the search term or change the design with custom HTML. | | ||
| `allowedChars` | `[a-zA-Z0-9_]` (or `function`) | Allowed characters in search term triggering a search request using regular expressions. Can be a function that takes the denotationChar and returns a regex. | | ||
| `minChars` | `0` | Minimum number of characters after the @ symbol triggering a search request | | ||
| `maxChars` | `31` | Maximum number of characters after the @ symbol triggering a search request | | ||
| `offsetTop` | `2` | Additional top offset of the mention container position | | ||
| `offsetLeft` | `0` | Additional left offset of the mention container position | | ||
| `mentionDenotationChars` | `["@"]` | Specifies which characters will cause the mention autocomplete to open | | ||
| `isolateCharacter` | `false` | Whether or not the denotation character(s) should be isolated. For example, to avoid mentioning in an email. | | ||
| `fixMentionsToQuill` | `false` | When set to true, the mentions menu will be rendered above or below the quill container. Otherwise, the mentions menu will track the denotation character(s); | | ||
| `showDenotationChar` | `true` | Whether to show the used denotation character in the mention item or not | | ||
| `defaultMenuOrientation` | `'bottom'` | Options are `'bottom'` and `'top'`. Determines what the default orientation of the menu will be. Quill-mention will attempt to render the menu either above or below the editor. If `'top'` is provided as a value, and there is not enough space above the editor, the menu will be rendered below. Vice versa, if there is not enough space below the editor, and `'bottom'` is provided as a value (or no value is provided at all), the menu will be rendered above the editor. | | ||
| `blotName` | `'mention'` | The name of the [Quill Blot](https://github.com/quilljs/parchment#blots) to be used for inserted mentions. A default implementation is provided named 'mention', which may be overidden with a custom blot. | | ||
| `dataAttributes` | `['id', 'value', 'denotationChar', 'link', 'target','disabled']` | A list of data values you wish to be passed from your list data to the html node. (`id, value, denotationChar, link, target` are included by default). | | ||
| `onOpen` | `function` | Callback when mention dropdown is open. | | ||
| `onClose` | `function` | Callback when mention dropdown is closed. | | ||
| `onSelect(item, insertItem)` | `function` | Callback for a selected item. When overriding this method, `insertItem` should be used to insert `item` to the editor. This makes async requests possible. | | ||
| `linkTarget` | `'_blank'` | Link target for mentions with a link | | ||
| `listItemClass` | `'ql-mention-list-item'` | Style class to be used for list items (may be null) | | ||
| `mentionContainerClass` | `'ql-mention-list-container'` | Style class to be used for the mention list container (may be null) | | ||
| `mentionListClass` | `'ql-mention-list'` | Style class to be used for the mention list (may be null) | | ||
| `spaceAfterInsert` | `true` | Whether or not insert 1 space after mention block in text | | ||
| `positioningStrategy` | `'absolute'` | Options are `'normal'` and `'fixed'`. When `'fixed'`, the menu will be appended to the body and use fixed positioning. Use this if the menu is clipped by a parent element that's using `overflow:hidden|scroll`. | | ||
| `renderLoading` | `function` | A function that returns the HTML for a loading message during async calls from `source`. The default functions returns `null` to prevent a loading message. | | ||
### Methods | ||
You may retrieve the module from Quill like `quill.getModule('mention')` then call one of the imperative methdos below. | ||
| Method | Example | Description | | ||
| -------------------------------------- | ------------------------------------------------ | ----------------------------------------------------------- | | ||
| `insertItem(data, programmaticInsert)` | `insertItem({id:'123',value:'My Mention'},true)` | Inserts the given mention into the editor. | | ||
| `openMenu(denotationChar)` | `openMenu('@')` | Opens the mentions menu for the given denotation character. | | ||
### Styling | ||
@@ -171,2 +182,6 @@ | ||
### Headers and Informational Items | ||
Sometimes you may want to display a menu item that should not be selectable. These items may be group headers, hint text, or even a message saying there were no matching results. To show items like these, add `disabled:true` to items passed to `renderList` from your `source` method. Disabled items are shown but not selectable with the mouse or keyboard. If you need to style the disabled items differently, you will need to override the `renderItem` method. | ||
## Authors | ||
@@ -173,0 +188,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
100739
1762
194