diff --git a/dist/quill.mention.min.js b/dist/quill.mention.min.js index d90c0ee..8fd6e3e 100644 --- a/dist/quill.mention.min.js +++ b/dist/quill.mention.min.js @@ -1 +1 @@ -!function(t){var e={};function n(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return t[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(i,o,function(e){return t[e]}.bind(null,o));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=1)}([function(t,e){t.exports=Quill},function(t,e,n){t.exports=n(2)},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var i=Object.assign||function(t){for(var e=1;e0&&void 0!==arguments[0])||arguments[0],e=0;es-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='0&&void 0!==arguments[0])||arguments[0],e=0;es-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=' + Math.random() + .toString(36) + .substring(2) + new Date().getTime().toString(36); const numberIsNaN = require('./imports/numberisnan.js'); +// escape special characters +function escapeRegExp(string){ + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} class Mention { constructor(quill, options) { @@ -93,6 +103,43 @@ class Mention { quill.keyboard.addBinding({ key: Keys.DOWN, }, this.downHandler.bind(this)); + + quill.clipboard.addMatcher(Node.TEXT_NODE, (node, delta) => { + const triggerMatch = this.options.mentionDenotationChars.find(trigger => { + return node.data.includes(trigger); + }); + + if (triggerMatch) { + // we have at least one trigger string in the pasted content, + // split the string replace any mentions with mentionBlots + + // We need to split on a regex that matches the trigger string + // as well as anything following it that matches the allowedChars. + // This should give us the node that needs to be converted into a + // mention. + const regex = /(\{\{[a-zA-Z0-9.-_]+\}\})/ + + const ops = node.data.split(regex).map(word => { + return { + insert: word.startsWith(triggerMatch) + ? { + mention: { + denotationChar: "", + id: uniqueId(), + index: 0, + value: word + } + } + : word + }; + }); + + return new Delta(ops); + } + + return delta; + }); + } selectHandler() { @@ -370,25 +417,66 @@ class Mention { const range = this.quill.getSelection(); if (range == null) return; this.cursorPos = range.index; + const startPos = Math.max(0, this.cursorPos - this.options.maxChars); - const beforeCursorPos = this.quill.getText(startPos, this.cursorPos - startPos); - const mentionCharIndex = this.options.mentionDenotationChars.reduce((prev, cur) => { - const previousIndex = prev; - const mentionIndex = beforeCursorPos.lastIndexOf(cur); + const beforeCursorPos = this.quill.getText( + startPos, + this.cursorPos - startPos + ); + + // given an array of trigger strings, eg ['{{', '@'], we want to loop + // through them and return if that match, and at which index + const { + index: mentionCharIndex, + match + } = this.options.mentionDenotationChars.reduce( + (prev, trigger) => { + const mentionIndex = beforeCursorPos.lastIndexOf(trigger); + + const isCloserToCursorThanPreviousMatch = mentionIndex > prev.index; + + if (isCloserToCursorThanPreviousMatch) { + return { + index: mentionIndex, + match: trigger + }; + } + + return prev; + }, + { index: -1 } + ); - return mentionIndex > previousIndex ? mentionIndex : previousIndex; - }, -1); if (mentionCharIndex > -1) { - if (this.options.isolateCharacter && !(mentionCharIndex === 0 || !!beforeCursorPos[mentionCharIndex - 1].match(/\s/g))) { + if ( + this.options.isolateCharacter && + !( + mentionCharIndex === 0 || + !!beforeCursorPos[mentionCharIndex - 1].match(/\s/g) + ) + ) { this.hideMentionList(); return; } - const mentionCharPos = this.cursorPos - (beforeCursorPos.length - mentionCharIndex); + const mentionCharPos = + this.cursorPos - (beforeCursorPos.length - mentionCharIndex); this.mentionCharPos = mentionCharPos; - const textAfter = beforeCursorPos.substring(mentionCharIndex + 1); - if (textAfter.length >= this.options.minChars && this.hasValidChars(textAfter)) { - const mentionChar = beforeCursorPos[mentionCharIndex]; - this.options.source(textAfter, this.renderList.bind(this, mentionChar), mentionChar); + const textAfter = beforeCursorPos.substring( + mentionCharIndex + match.length + ); + if ( + textAfter.length >= this.options.minChars && + this.hasValidChars(textAfter) + ) { + const mentionChar = beforeCursorPos.substring( + mentionCharIndex, + match.length + ); + this.options.source( + textAfter, + this.renderList.bind(this, mentionChar), + mentionChar + ); } else { this.hideMentionList(); }