diff --git a/Sources/Actions/Credits.php b/Sources/Actions/Credits.php
index 7c7f45b6ab..f69191d7ef 100644
--- a/Sources/Actions/Credits.php
+++ b/Sources/Actions/Credits.php
@@ -332,7 +332,7 @@ public function execute(): void
'animaDrag | © Abel Mohler | Licensed under The MIT License (MIT)',
'jQuery Custom Scrollbar | © Maciej Zubala | Licensed under The MIT License (MIT)',
'jQuery Responsive Slider | © booncon ROCKETS | Licensed under The MIT License (MIT)',
- 'At.js | © chord.luo@gmail.com | Licensed under The MIT License (MIT)',
+ 'Tribute | © Matt York and contributors | Licensed under The MIT License (MIT)',
'HTML5 Desktop Notifications | © Tsvetan Tsvetkov | Licensed under The Apache License Version 2.0',
'GAuth Code Generator/Validator | © Chris Cornutt | Licensed under The MIT License (MIT)',
'Dropzone.js | © Matias Meno | Licensed under The MIT License (MIT)',
diff --git a/Sources/Actions/Display.php b/Sources/Actions/Display.php
index c234039183..b835545f1d 100644
--- a/Sources/Actions/Display.php
+++ b/Sources/Actions/Display.php
@@ -1041,8 +1041,8 @@ protected function setupTemplate(): void
// Mentions
if (!empty(Config::$modSettings['enable_mentions']) && User::$me->allowedTo('mention')) {
- Theme::loadJavaScriptFile('jquery.atwho.min.js', ['defer' => true], 'smf_atwho');
- Theme::loadJavaScriptFile('jquery.caret.min.js', ['defer' => true], 'smf_caret');
+ Theme::loadCSSFile('tribute.css', ['minimize' => true], 'smf_tribute');
+ Theme::loadJavaScriptFile('tribute.js', ['defer' => true, 'minimize' => true], 'smf_tribute');
Theme::loadJavaScriptFile('mentions.js', ['defer' => true, 'minimize' => true], 'smf_mentions');
}
diff --git a/Sources/Actions/Post.php b/Sources/Actions/Post.php
index 55f690b3c7..da602ab1bf 100644
--- a/Sources/Actions/Post.php
+++ b/Sources/Actions/Post.php
@@ -355,8 +355,8 @@ public function show(): void
// Mentions
if (!empty(Config::$modSettings['enable_mentions']) && User::$me->allowedTo('mention')) {
- Theme::loadJavaScriptFile('jquery.caret.min.js', ['defer' => true], 'smf_caret');
- Theme::loadJavaScriptFile('jquery.atwho.min.js', ['defer' => true], 'smf_atwho');
+ Theme::loadCSSFile('tribute.css', ['minimize' => true], 'smf_tribute');
+ Theme::loadJavaScriptFile('tribute.js', ['defer' => true, 'minimize' => true], 'smf_tribute');
Theme::loadJavaScriptFile('mentions.js', ['defer' => true, 'minimize' => true], 'smf_mentions');
}
diff --git a/Themes/default/css/index.css b/Themes/default/css/index.css
index 3493cbb612..2115d5a4e3 100644
--- a/Themes/default/css/index.css
+++ b/Themes/default/css/index.css
@@ -3814,50 +3814,6 @@ p.information img {
.topic_pages::after {
content: " \00bb"
}
-/* Mentions */
-.atwho-view {
- position: absolute;
- top: 0;
- left: 0;
- display: none;
- margin-top: 18px;
- background: #fff;
- border: 1px solid #ddd;
- border-radius: 3px;
- box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
- min-width: 120px;
- z-index: 11110 !important;
-}
-.atwho-view .cur {
- background: #3366ff;
- color: #fff;
-}
-.atwho-view .cur small {
- color: #fff;
-}
-.atwho-view strong {
- color: #3366ff;
-}
-.atwho-view .cur strong {
- color: #fff;
- font-weight: bold;
-}
-.atwho-view ul {
- list-style: none;
- padding: 0;
- margin: auto;
-}
-.atwho-view ul li {
- display: block;
- padding: 5px 10px;
- border-bottom: 1px solid #ddd;
- cursor: pointer;
-}
-.atwho-view small {
- font-size: smaller;
- color: #777;
- font-weight: normal;
-}
/* On/Off Icons (User) */
.on, .off {
display: inline-block;
diff --git a/Themes/default/css/tribute.css b/Themes/default/css/tribute.css
new file mode 100644
index 0000000000..3268c09aac
--- /dev/null
+++ b/Themes/default/css/tribute.css
@@ -0,0 +1,32 @@
+.tribute-container {
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: auto;
+ overflow: auto;
+ display: block;
+ z-index: 999999;
+}
+.tribute-container ul {
+ margin: 0;
+ margin-top: 2px;
+ padding: 0;
+ list-style: none;
+ background: #efefef;
+}
+.tribute-container li {
+ padding: 5px 5px;
+ cursor: pointer;
+}
+.tribute-container li.highlight {
+ background: #ddd;
+}
+.tribute-container li span {
+ font-weight: bold;
+}
+.tribute-container li.no-match {
+ cursor: default;
+}
+.tribute-container .menu-highlighted {
+ font-weight: bold;
+}
\ No newline at end of file
diff --git a/Themes/default/scripts/jquery.atwho.min.js b/Themes/default/scripts/jquery.atwho.min.js
deleted file mode 100644
index e5d9dfada3..0000000000
--- a/Themes/default/scripts/jquery.atwho.min.js
+++ /dev/null
@@ -1 +0,0 @@
-!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(a){var b,c,d,e,f,g,h,i,j,k=[].slice,l=function(a,b){function c(){this.constructor=a}for(var d in b)m.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},m={}.hasOwnProperty;c=function(){function a(a){this.currentFlag=null,this.controllers={},this.aliasMaps={},this.$inputor=$(a),this.setupRootElement(),this.listen()}return a.prototype.createContainer=function(a){var b;return null!=(b=this.$el)&&b.remove(),$(a.body).append(this.$el=$("
"))},a.prototype.setupRootElement=function(a,b){var c;if(null==b&&(b=!1),a)this.window=a.contentWindow,this.document=a.contentDocument||this.window.document,this.iframe=a;else{this.document=this.$inputor[0].ownerDocument,this.window=this.document.defaultView||this.document.parentWindow;try{this.iframe=this.window.frameElement}catch(d){if(c=d,this.iframe=null,$.fn.atwho.debug)throw new Error("iframe auto-discovery is failed.\nPlease use `setIframe` to set the target iframe manually.\n"+c)}}return this.createContainer((this.iframeAsRoot=b)?this.document:document)},a.prototype.controller=function(a){var b,c,d,e;if(this.aliasMaps[a])c=this.controllers[this.aliasMaps[a]];else{e=this.controllers;for(d in e)if(b=e[d],d===a){c=b;break}}return c?c:this.controllers[this.currentFlag]},a.prototype.setContextFor=function(a){return this.currentFlag=a,this},a.prototype.reg=function(a,b){var c,d;return d=(c=this.controllers)[a]||(c[a]=this.$inputor.is("[contentEditable]")?new f(this,a):new i(this,a)),b.alias&&(this.aliasMaps[b.alias]=a),d.init(b),this},a.prototype.listen=function(){return this.$inputor.on("compositionstart",function(a){return function(b){var c;return null!=(c=a.controller())&&c.view.hide(),a.isComposing=!0}}(this)).on("compositionend",function(a){return function(b){return a.isComposing=!1}}(this)).on("keyup.atwhoInner",function(a){return function(b){return a.onKeyup(b)}}(this)).on("keydown.atwhoInner",function(a){return function(b){return a.onKeydown(b)}}(this)).on("scroll.atwhoInner",function(a){return function(b){var c;return null!=(c=a.controller())?c.view.hide(b):void 0}}(this)).on("blur.atwhoInner",function(a){return function(b){var c;return(c=a.controller())?c.view.hide(b,c.getOpt("displayTimeout")):void 0}}(this)).on("click.atwhoInner",function(a){return function(b){return a.dispatch(b)}}(this))},a.prototype.shutdown=function(){var a,b,c;c=this.controllers;for(a in c)b=c[a],b.destroy(),delete this.controllers[a];return this.$inputor.off(".atwhoInner"),this.$el.remove()},a.prototype.dispatch=function(a){var b,c,d,e;d=this.controllers,e=[];for(b in d)c=d[b],e.push(c.lookUp(a));return e},a.prototype.onKeyup=function(a){var b;switch(a.keyCode){case g.ESC:a.preventDefault(),null!=(b=this.controller())&&b.view.hide();break;case g.DOWN:case g.UP:case g.CTRL:$.noop();break;case g.P:case g.N:a.ctrlKey||this.dispatch(a);break;default:this.dispatch(a)}},a.prototype.onKeydown=function(a){var b,c;if(c=null!=(b=this.controller())?b.view:void 0,c&&c.visible())switch(a.keyCode){case g.ESC:a.preventDefault(),c.hide(a);break;case g.UP:a.preventDefault(),c.prev();break;case g.DOWN:a.preventDefault(),c.next();break;case g.P:if(!a.ctrlKey)return;a.preventDefault(),c.prev();break;case g.N:if(!a.ctrlKey)return;a.preventDefault(),c.next();break;case g.TAB:case g.ENTER:case g.SPACE:if(!c.visible())return;if(!this.controller().getOpt("spaceSelectsMatch")&&a.keyCode===g.SPACE)return;c.highlighted()?(a.preventDefault(),c.choose(a)):c.hide(a);break;default:$.noop()}},a}(),d=function(){function a(a,b){this.app=a,this.at=b,this.$inputor=this.app.$inputor,this.id=this.$inputor[0].id||this.uid(),this.setting=null,this.query=null,this.pos=0,this.range=null,0===(this.$el=$("#atwho-ground-"+this.id,this.app.$el)).length&&this.app.$el.append(this.$el=$("")),this.model=new h(this),this.view=new j(this)}return a.prototype.uid=function(){return(Math.random().toString(16)+"000000000").substr(2,8)+(new Date).getTime()},a.prototype.init=function(a){return this.setting=$.extend({},this.setting||$.fn.atwho["default"],a),this.view.init(),this.model.reload(this.setting.data)},a.prototype.destroy=function(){return this.trigger("beforeDestroy"),this.model.destroy(),this.view.destroy(),this.$el.remove()},a.prototype.callDefault=function(){var a,b,c;c=arguments[0],a=2<=arguments.length?k.call(arguments,1):[];try{return e[c].apply(this,a)}catch(d){return b=d,$.error(b+" Or maybe At.js doesn't have function "+c)}},a.prototype.trigger=function(a,b){var c,d;return null==b&&(b=[]),b.push(this),c=this.getOpt("alias"),d=c?a+"-"+c+".atwho":a+".atwho",this.$inputor.trigger(d,b)},a.prototype.callbacks=function(a){return this.getOpt("callbacks")[a]||e[a]},a.prototype.getOpt=function(a,b){var c;try{return this.setting[a]}catch(d){return c=d,null}},a.prototype.insertContentFor=function(a){var b,c;return c=this.getOpt("insertTpl"),b=$.extend({},a.data("item-data"),{"atwho-at":this.at}),this.callbacks("tplEval").call(this,c,b,"onInsert")},a.prototype.renderView=function(a){var b;return b=this.getOpt("searchKey"),a=this.callbacks("sorter").call(this,this.query.text,a.slice(0,1001),b),this.view.render(a.slice(0,this.getOpt("limit")))},a.arrayToDefaultHash=function(a){var b,c,d,e;if(!$.isArray(a))return a;for(e=[],b=0,d=a.length;d>b;b++)c=a[b],e.push($.isPlainObject(c)?c:{name:c});return e},a.prototype.lookUp=function(a){var b,c;if(b=this.catchQuery(a))return this.app.setContextFor(this.at),(c=this.getOpt("delay"))?this._delayLookUp(b,c):this._lookUp(b),b},a.prototype._delayLookUp=function(a,b){var c,d;return c=Date.now?Date.now():(new Date).getTime(),this.previousCallTime||(this.previousCallTime=c),d=b-(c-this.previousCallTime),d>0&&b>d?(this.previousCallTime=c,this._stopDelayedCall(),this.delayedCallTimeout=setTimeout(function(b){return function(){return b.previousCallTime=0,b.delayedCallTimeout=null,b._lookUp(a)}}(this),b)):(this._stopDelayedCall(),this.previousCallTime!==c&&(this.previousCallTime=0),this._lookUp(a))},a.prototype._stopDelayedCall=function(){return this.delayedCallTimeout?(clearTimeout(this.delayedCallTimeout),this.delayedCallTimeout=null):void 0},a.prototype._lookUp=function(a){var b;return b=function(a){return a&&a.length>0?this.renderView(this.constructor.arrayToDefaultHash(a)):this.view.hide()},this.model.query(a.text,$.proxy(b,this))},a}(),i=function(a){function b(){return b.__super__.constructor.apply(this,arguments)}return l(b,a),b.prototype.catchQuery=function(){var a,b,c,d,e,f;return b=this.$inputor.val(),a=this.$inputor.caret("pos",{iframe:this.app.iframe}),f=b.slice(0,a),d=this.callbacks("matcher").call(this,this.at,f,this.getOpt("startWithSpace")),"string"==typeof d&&d.length<=this.getOpt("maxLen",20)?(e=a-d.length,c=e+d.length,this.pos=e,d={text:d,headPos:e,endPos:c},this.trigger("matched",[this.at,d.text])):(d=null,this.view.hide()),this.query=d},b.prototype.rect=function(){var a,b,c;if(a=this.$inputor.caret("offset",this.pos-1,{iframe:this.app.iframe}))return this.app.iframe&&!this.app.iframeAsRoot&&(b=$(this.app.iframe).offset(),a.left+=b.left,a.top+=b.top),c=this.app.document.selection?0:2,{left:a.left,top:a.top,bottom:a.top+a.height+c}},b.prototype.insert=function(a,b){var c,d,e,f,g;return c=this.$inputor,d=c.val(),e=d.slice(0,Math.max(this.query.headPos-this.at.length,0)),f=""===(f=this.getOpt("suffix"))?f:f||" ",a+=f,g=""+e+a+d.slice(this.query.endPos||0),c.val(g),c.caret("pos",e.length+a.length,{iframe:this.app.iframe}),c.is(":focus")||c.focus(),c.change()},b}(d),f=function(a){function b(){return b.__super__.constructor.apply(this,arguments)}return l(b,a),b.prototype._getRange=function(){var a;return a=this.app.window.getSelection(),a.rangeCount>0?a.getRangeAt(0):void 0},b.prototype._setRange=function(a,b,c){return null==c&&(c=this._getRange()),c?(b=$(b)[0],"after"===a?(c.setEndAfter(b),c.setStartAfter(b)):(c.setEndBefore(b),c.setStartBefore(b)),c.collapse(!1),this._clearRange(c)):void 0},b.prototype._clearRange=function(a){var b;return null==a&&(a=this._getRange()),b=this.app.window.getSelection(),null==this.ctrl_a_pressed?(b.removeAllRanges(),b.addRange(a)):void 0},b.prototype._movingEvent=function(a){var b;return"click"===a.type||(b=a.which)===g.RIGHT||b===g.LEFT||b===g.UP||b===g.DOWN},b.prototype._unwrap=function(a){var b;return a=$(a).unwrap().get(0),(b=a.nextSibling)&&b.nodeValue&&(a.nodeValue+=b.nodeValue,$(b).remove()),a},b.prototype.catchQuery=function(a){var b,c,d,e,f,h,i,j,k,l;if(!this.app.isComposing&&(l=this._getRange())){if(a.which===g.CTRL?this.ctrl_pressed=!0:a.which===g.A?null==this.ctrl_pressed&&(this.ctrl_a_pressed=!0):(delete this.ctrl_a_pressed,delete this.ctrl_pressed),a.which===g.ENTER)return(c=$(l.startContainer).closest(".atwho-query")).contents().unwrap(),c.is(":empty")&&c.remove(),(c=$(".atwho-query",this.app.document)).text(c.text()).contents().last().unwrap(),void this._clearRange();if(/firefox/i.test(navigator.userAgent)){if($(l.startContainer).is(this.$inputor))return void this._clearRange();a.which===g.BACKSPACE&&l.startContainer.nodeType===document.ELEMENT_NODE&&(j=l.startOffset-1)>=0?(d=l.cloneRange(),d.setStart(l.startContainer,j),$(d.cloneContents()).contents().last().is(".atwho-inserted")&&(f=$(l.startContainer).contents().get(j),this._setRange("after",$(f).contents().last()))):a.which===g.LEFT&&l.startContainer.nodeType===document.TEXT_NODE&&(b=$(l.startContainer.previousSibling),b.is(".atwho-inserted")&&0===l.startOffset&&this._setRange("after",b.contents().last()))}return $(l.startContainer).closest(".atwho-inserted").addClass("atwho-query").siblings().removeClass("atwho-query"),(c=$(".atwho-query",this.app.document)).length>0&&c.is(":empty")&&0===c.text().length&&c.remove(),this._movingEvent(a)||c.removeClass("atwho-inserted"),d=l.cloneRange(),d.setStart(l.startContainer,0),i=this.callbacks("matcher").call(this,this.at,d.toString(),this.getOpt("startWithSpace")),0===c.length&&"string"==typeof i&&(e=l.startOffset-this.at.length-i.length)>=0&&(l.setStart(l.startContainer,e),c=$("",this.app.document).attr(this.getOpt("editableAtwhoQueryAttrs")).addClass("atwho-query"),l.surroundContents(c.get(0)),h=c.contents().last().get(0),/firefox/i.test(navigator.userAgent)?(l.setStart(h,h.length),l.setEnd(h,h.length),this._clearRange(l)):this._setRange("after",h,l)),"string"==typeof i&&i.length<=this.getOpt("maxLen",20)?(k={text:i,el:c},this.trigger("matched",[this.at,k.text]),this.query=k):(this.view.hide(),this.query={el:c},c.text().indexOf(this.at)>=0&&(this._movingEvent(a)&&c.hasClass("atwho-inserted")?c.removeClass("atwho-query"):!1!==this.callbacks("afterMatchFailed").call(this,this.at,c)&&this._setRange("after",this._unwrap(c.text(c.text()).contents().first()))),null)}},b.prototype.rect=function(){var a,b,c;return c=this.query.el.offset(),this.app.iframe&&!this.app.iframeAsRoot&&(b=(a=$(this.app.iframe)).offset(),c.left+=b.left-this.$inputor.scrollLeft(),c.top+=b.top-this.$inputor.scrollTop()),c.bottom=c.top+this.query.el.height(),c},b.prototype.insert=function(a,b){var c,d,e;return d=(d=this.getOpt("suffix"))?d:d||" ",this.query.el.removeClass("atwho-query").addClass("atwho-inserted").html(a),(c=this._getRange())&&(c.setEndAfter(this.query.el[0]),c.collapse(!1),c.insertNode(e=this.app.document.createTextNode(d)),this._setRange("after",e,c)),this.$inputor.is(":focus")||this.$inputor.focus(),this.$inputor.change()},b}(d),h=function(){function a(a){this.context=a,this.at=this.context.at,this.storage=this.context.$inputor}return a.prototype.destroy=function(){return this.storage.data(this.at,null)},a.prototype.saved=function(){return this.fetch()>0},a.prototype.query=function(a,b){var c,d,e;return d=this.fetch(),e=this.context.getOpt("searchKey"),d=this.context.callbacks("filter").call(this.context,a,d,e)||[],c=this.context.callbacks("remoteFilter"),d.length>0||!c&&0===d.length?b(d):c.call(this.context,a,b)},a.prototype.fetch=function(){return this.storage.data(this.at)||[]},a.prototype.save=function(a){return this.storage.data(this.at,this.context.callbacks("beforeSave").call(this.context,a||[]))},a.prototype.load=function(a){return!this.saved()&&a?this._load(a):void 0},a.prototype.reload=function(a){return this._load(a)},a.prototype._load=function(a){return"string"==typeof a?$.ajax(a,{dataType:"json"}).done(function(a){return function(b){return a.save(b)}}(this)):this.save(a)},a}(),j=function(){function a(a){this.context=a,this.$el=$(""),this.timeoutID=null,this.context.$el.append(this.$el),this.bindEvent()}return a.prototype.init=function(){var a;return a=this.context.getOpt("alias")||this.context.at.charCodeAt(0),this.$el.attr({id:"at-view-"+a})},a.prototype.destroy=function(){return this.$el.remove()},a.prototype.bindEvent=function(){var a;return a=this.$el.find("ul"),a.on("mouseenter.atwho-view","li",function(b){return a.find(".cur").removeClass("cur"),$(b.currentTarget).addClass("cur")}).on("click.atwho-view","li",function(b){return function(c){return a.find(".cur").removeClass("cur"),$(c.currentTarget).addClass("cur"),b.choose(c),c.preventDefault()}}(this))},a.prototype.visible=function(){return this.$el.is(":visible")},a.prototype.highlighted=function(){return this.$el.find(".cur").length>0},a.prototype.choose=function(a){var b,c;return(b=this.$el.find(".cur")).length&&(c=this.context.insertContentFor(b),this.context.insert(this.context.callbacks("beforeInsert").call(this.context,c,b),b),this.context.trigger("inserted",[b,a]),this.hide(a)),this.context.getOpt("hideWithoutSuffix")?this.stopShowing=!0:void 0},a.prototype.reposition=function(a){var b,c,d,e;return b=this.context.app.iframeAsRoot?this.context.app.window:window,a.bottom+this.$el.height()-$(b).scrollTop()>$(b).height()&&(a.bottom=a.top-this.$el.height()),a.left>(d=$(b).width()-this.$el.width()-5)&&(a.left=d),c={left:a.left,top:a.bottom},null!=(e=this.context.callbacks("beforeReposition"))&&e.call(this.context,c),this.$el.offset(c),this.context.trigger("reposition",[c])},a.prototype.next=function(){var a,b;return a=this.$el.find(".cur").removeClass("cur"),b=a.next(),b.length||(b=this.$el.find("li:first")),b.addClass("cur"),this.scrollTop(Math.max(0,a.innerHeight()*(b.index()+2)-this.$el.height()))},a.prototype.prev=function(){var a,b;return a=this.$el.find(".cur").removeClass("cur"),b=a.prev(),b.length||(b=this.$el.find("li:last")),b.addClass("cur"),this.scrollTop(Math.max(0,a.innerHeight()*(b.index()+2)-this.$el.height()))},a.prototype.scrollTop=function(a){var b;return b=this.context.getOpt("scrollDuration"),b?this.$el.animate({scrollTop:a},b):this.$el.scrollTop(a)},a.prototype.show=function(){var a;return this.stopShowing?void(this.stopShowing=!1):(this.visible()||(this.$el.show(),this.$el.scrollTop(0),this.context.trigger("shown")),(a=this.context.rect())?this.reposition(a):void 0)},a.prototype.hide=function(a,b){var c;if(this.visible())return isNaN(b)?(this.$el.hide(),this.context.trigger("hidden",[a])):(c=function(a){return function(){return a.hide()}}(this),clearTimeout(this.timeoutID),this.timeoutID=setTimeout(c,b))},a.prototype.render=function(a){var b,c,d,e,f,g,h;if(!($.isArray(a)&&a.length>0))return void this.hide();for(this.$el.find("ul").empty(),c=this.$el.find("ul"),h=this.context.getOpt("displayTpl"),d=0,f=a.length;f>d;d++)e=a[d],e=$.extend({},e,{"atwho-at":this.context.at}),g=this.context.callbacks("tplEval").call(this.context,h,e,"onDisplay"),b=$(this.context.callbacks("highlighter").call(this.context,g,this.context.query.text)),b.data("item-data",e),c.append(b);return this.show(),this.context.getOpt("highlightFirst")?c.find("li:first").addClass("cur"):void 0},a}(),g={DOWN:40,UP:38,ESC:27,TAB:9,ENTER:13,CTRL:17,A:65,P:80,N:78,LEFT:37,UP:38,RIGHT:39,DOWN:40,BACKSPACE:8,SPACE:32},e={beforeSave:function(a){return d.arrayToDefaultHash(a)},matcher:function(a,b,c,d){var e,f,g,h,i;return a=a.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&"),c&&(a="(?:^|\\s)"+a),e=decodeURI("%C3%80"),f=decodeURI("%C3%BF"),i=d?" ":"",h=new RegExp(a+"([A-Za-z"+e+"-"+f+"0-9_"+i+".+-]*)$|"+a+"([^\\x00-\\xff]*)$","gi"),g=h.exec(b),g?g[2]||g[1]:null},filter:function(a,b,c){var d,e,f,g;for(d=[],e=0,g=b.length;g>e;e++)f=b[e],~new String(f[c]).toLowerCase().indexOf(a.toLowerCase())&&d.push(f);return d},remoteFilter:null,sorter:function(a,b,c){var d,e,f,g;if(!a)return b;for(d=[],e=0,g=b.length;g>e;e++)f=b[e],f.atwho_order=new String(f[c]).toLowerCase().indexOf(a.toLowerCase()),f.atwho_order>-1&&d.push(f);return d.sort(function(a,b){return a.atwho_order-b.atwho_order})},tplEval:function(a,b){var c,d;d=a;try{return"string"!=typeof a&&(d=a(b)),d.replace(/\$\{([^\}]*)\}/g,function(a,c,d){return b[c]})}catch(e){return c=e,""}},highlighter:function(a,b){var c;return b?(c=new RegExp(">\\s*(\\w*?)("+b.replace("+","\\+")+")(\\w*)\\s*<","ig"),a.replace(c,function(a,b,c,d){return"> "+b+""+c+""+d+" <"})):a},beforeInsert:function(a,b){return a},beforeReposition:function(a){return a},afterMatchFailed:function(a,b){}},b={load:function(a,b){var c;return(c=this.controller(a))?c.model.load(b):void 0},isSelecting:function(){var a;return null!=(a=this.controller())?a.view.visible():void 0},hide:function(){var a;return null!=(a=this.controller())?a.view.hide():void 0},reposition:function(){var a;return(a=this.controller())?(a.view.reposition(a.rect()),console.log("reposition",a)):void 0},setIframe:function(a,b){return this.setupRootElement(a,b),null},run:function(){return this.dispatch()},destroy:function(){return this.shutdown(),this.$inputor.data("atwho",null)}},$.fn.atwho=function(a){var d,e;return d=arguments,e=null,this.filter('textarea, input, [contenteditable=""], [contenteditable=true]').each(function(){var f,g;return(g=(f=$(this)).data("atwho"))||f.data("atwho",g=new c(this)),"object"!=typeof a&&a?b[a]&&g?e=b[a].apply(g,Array.prototype.slice.call(d,1)):$.error("Method "+a+" does not exist on jQuery.atwho"):g.reg(a.at,a)}),e||this},$.fn.atwho["default"]={at:void 0,alias:void 0,data:null,displayTpl:"${name}",insertTpl:"${atwho-at}${name}",callbacks:e,searchKey:"name",suffix:void 0,hideWithoutSuffix:!1,startWithSpace:!0,highlightFirst:!0,limit:5,maxLen:20,displayTimeout:300,delay:null,spaceSelectsMatch:!1,editableAtwhoQueryAttrs:{},scrollDuration:150},$.fn.atwho.debug=!1});
\ No newline at end of file
diff --git a/Themes/default/scripts/jquery.caret.min.js b/Themes/default/scripts/jquery.caret.min.js
deleted file mode 100644
index a4d02eae24..0000000000
--- a/Themes/default/scripts/jquery.caret.min.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/*! jquery.caret 2015-02-01 */
-!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(c){return a.returnExportsGlobal=b(c)}):"object"==typeof exports?module.exports=b(require("jquery")):b(jQuery)}(this,function(a){"use strict";var b,c,d,e,f,g,h,i,j,k,l;k="caret",b=function(){function b(a){this.$inputor=a,this.domInputor=this.$inputor[0]}return b.prototype.setPos=function(){return this.domInputor},b.prototype.getIEPosition=function(){return this.getPosition()},b.prototype.getPosition=function(){var a,b;return b=this.getOffset(),a=this.$inputor.offset(),b.left-=a.left,b.top-=a.top,b},b.prototype.getOldIEPos=function(){var a,b;return b=h.selection.createRange(),a=h.body.createTextRange(),a.moveToElementText(this.domInputor),a.setEndPoint("EndToEnd",b),a.text.length},b.prototype.getPos=function(){var a,b,c;return(c=this.range())?(a=c.cloneRange(),a.selectNodeContents(this.domInputor),a.setEnd(c.endContainer,c.endOffset),b=a.toString().length,a.detach(),b):h.selection?this.getOldIEPos():void 0},b.prototype.getOldIEOffset=function(){var a,b;return a=h.selection.createRange().duplicate(),a.moveStart("character",-1),b=a.getBoundingClientRect(),{height:b.bottom-b.top,left:b.left,top:b.top}},b.prototype.getOffset=function(){var b,c,d,e,f;return j.getSelection&&(d=this.range())?(d.endOffset-1>0&&d.endContainer===!this.domInputor&&(b=d.cloneRange(),b.setStart(d.endContainer,d.endOffset-1),b.setEnd(d.endContainer,d.endOffset),e=b.getBoundingClientRect(),c={height:e.height,left:e.left+e.width,top:e.top},b.detach()),c&&0!==(null!=c?c.height:void 0)||(b=d.cloneRange(),f=a(h.createTextNode("|")),b.insertNode(f[0]),b.selectNode(f[0]),e=b.getBoundingClientRect(),c={height:e.height,left:e.left,top:e.top},f.remove(),b.detach())):h.selection&&(c=this.getOldIEOffset()),c&&(c.top+=a(j).scrollTop(),c.left+=a(j).scrollLeft()),c},b.prototype.range=function(){var a;if(j.getSelection)return a=j.getSelection(),a.rangeCount>0?a.getRangeAt(0):null},b}(),c=function(){function b(a){this.$inputor=a,this.domInputor=this.$inputor[0]}return b.prototype.getIEPos=function(){var a,b,c,d,e,f,g;return b=this.domInputor,f=h.selection.createRange(),e=0,f&&f.parentElement()===b&&(d=b.value.replace(/\r\n/g,"\n"),c=d.length,g=b.createTextRange(),g.moveToBookmark(f.getBookmark()),a=b.createTextRange(),a.collapse(!1),e=g.compareEndPoints("StartToEnd",a)>-1?c:-g.moveStart("character",-c)),e},b.prototype.getPos=function(){return h.selection?this.getIEPos():this.domInputor.selectionStart},b.prototype.setPos=function(a){var b,c;return b=this.domInputor,h.selection?(c=b.createTextRange(),c.move("character",a),c.select()):b.setSelectionRange&&b.setSelectionRange(a,a),b},b.prototype.getIEOffset=function(a){var b,c,d,e;return c=this.domInputor.createTextRange(),a||(a=this.getPos()),c.move("character",a),d=c.boundingLeft,e=c.boundingTop,b=c.boundingHeight,{left:d,top:e,height:b}},b.prototype.getOffset=function(b){var c,d,e;return c=this.$inputor,h.selection?(d=this.getIEOffset(b),d.top+=a(j).scrollTop()+c.scrollTop(),d.left+=a(j).scrollLeft()+c.scrollLeft(),d):(d=c.offset(),e=this.getPosition(b),d={left:d.left+e.left-c.scrollLeft(),top:d.top+e.top-c.scrollTop(),height:e.height})},b.prototype.getPosition=function(a){var b,c,e,f,g,h,i;return b=this.$inputor,f=function(a){return a=a.replace(/<|>|`|"|&/g,"?").replace(/\r\n|\r|\n/g,"
"),/firefox/i.test(navigator.userAgent)&&(a=a.replace(/\s/g," ")),a},void 0===a&&(a=this.getPos()),i=b.val().slice(0,a),e=b.val().slice(a),g=""+f(i)+"",g+="|",g+=""+f(e)+"",h=new d(b),c=h.create(g).rect()},b.prototype.getIEPosition=function(a){var b,c,d,e,f;return d=this.getIEOffset(a),c=this.$inputor.offset(),e=d.left-c.left,f=d.top-c.top,b=d.height,{left:e,top:f,height:b}},b}(),d=function(){function b(a){this.$inputor=a}return b.prototype.css_attr=["borderBottomWidth","borderLeftWidth","borderRightWidth","borderTopStyle","borderRightStyle","borderBottomStyle","borderLeftStyle","borderTopWidth","boxSizing","fontFamily","fontSize","fontWeight","height","letterSpacing","lineHeight","marginBottom","marginLeft","marginRight","marginTop","outlineWidth","overflow","overflowX","overflowY","paddingBottom","paddingLeft","paddingRight","paddingTop","textAlign","textOverflow","textTransform","whiteSpace","wordBreak","wordWrap"],b.prototype.mirrorCss=function(){var b,c=this;return b={position:"absolute",left:-9999,top:0,zIndex:-2e4},"TEXTAREA"===this.$inputor.prop("tagName")&&this.css_attr.push("width"),a.each(this.css_attr,function(a,d){return b[d]=c.$inputor.css(d)}),b},b.prototype.create=function(b){return this.$mirror=a(""),this.$mirror.css(this.mirrorCss()),this.$mirror.html(b),this.$inputor.after(this.$mirror),this},b.prototype.rect=function(){var a,b,c;return a=this.$mirror.find("#caret"),b=a.position(),c={left:b.left,top:b.top,height:a.height()},this.$mirror.remove(),c},b}(),e={contentEditable:function(a){return!(!a[0].contentEditable||"true"!==a[0].contentEditable)}},g={pos:function(a){return a||0===a?this.setPos(a):this.getPos()},position:function(a){return h.selection?this.getIEPosition(a):this.getPosition(a)},offset:function(a){var b;return b=this.getOffset(a)}},h=null,j=null,i=null,l=function(a){var b;return(b=null!=a?a.iframe:void 0)?(i=b,j=b.contentWindow,h=b.contentDocument||j.document):(i=void 0,j=window,h=document)},f=function(a){var b;h=a[0].ownerDocument,j=h.defaultView||h.parentWindow;try{return i=j.frameElement}catch(c){b=c}},a.fn.caret=function(d,f,h){var i;return g[d]?(a.isPlainObject(f)?(l(f),f=void 0):l(h),i=e.contentEditable(this)?new b(this):new c(this),g[d].apply(i,[f])):a.error("Method "+d+" does not exist on jQuery.caret")},a.fn.caret.EditableCaret=b,a.fn.caret.InputCaret=c,a.fn.caret.Utils=e,a.fn.caret.apis=g});
\ No newline at end of file
diff --git a/Themes/default/scripts/jquery.sceditor.smf.js b/Themes/default/scripts/jquery.sceditor.smf.js
index 6d6e7e73a6..e6f95c426a 100644
--- a/Themes/default/scripts/jquery.sceditor.smf.js
+++ b/Themes/default/scripts/jquery.sceditor.smf.js
@@ -198,8 +198,16 @@
* Only resize the text areas instead.
*/
document.querySelector(".sceditor-container").removeAttribute("style");
- document.querySelector(".sceditor-container textarea").style.height = options.height;
- document.querySelector(".sceditor-container textarea").style.flexBasis = options.height;
+
+ const textarea = document.querySelector('.sceditor-container textarea');
+ textarea.style.height = options.height;
+ textarea.style.flexBasis = options.height;
+
+ // Add Tribute.js
+ if (typeof tribute === 'object') {
+ tribute.attach(textarea);
+ tribute.attach(instance.getBody());
+ }
isPatched = true;
}
diff --git a/Themes/default/scripts/mentions.js b/Themes/default/scripts/mentions.js
index 7ca21fd2e5..e7df1b0641 100644
--- a/Themes/default/scripts/mentions.js
+++ b/Themes/default/scripts/mentions.js
@@ -1,56 +1,40 @@
-var fails = [];
+const tributeRemoteSearch = (query, callback) => {
+ const URL = smf_scripturl + '?action=suggest;' + smf_session_var + '=' + smf_session_id + ';xml';
-var atwhoConfig = {
- at: '@',
- data: [],
- show_the_at: true,
- startWithSpace: true,
- limit: 10,
- callbacks: {
- remoteFilter: function (query, callback) {
- if (typeof query == 'undefined' || query.length < 2 || query.length > 60)
- return;
+ xhr = new XMLHttpRequest();
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState === 4) {
+ if (xhr.status === 200) {
+ const xmlDoc = xhr.responseXML;
+ const items = xmlDoc.getElementsByTagName('item');
+ const users = [];
- for (i in fails)
- if (query.substr(0, fails[i].length) == fails[i])
- return;
+ for (let i = 0; i < items.length; i++) {
+ users.push({ key: items[i].id, value: items[i].textContent });
+ }
- $.ajax({
- url: smf_scripturl + '?action=suggest;' + smf_session_var + '=' + smf_session_id + ';xml',
- method: 'GET',
- headers: {
- "X-SMF-AJAX": 1
- },
- xhrFields: {
- withCredentials: typeof allow_xhjr_credentials !== "undefined" ? allow_xhjr_credentials : false
- },
- data: {
- search: query,
- suggest_type: 'member'
- },
- success: function (data) {
- var members = $(data).find('smf > items > item');
- if (members.length == 0)
- fails[fails.length] = query;
-
- var callbackArray = [];
- $.each(members, function (index, item) {
- callbackArray[callbackArray.length] = {
- name: $(item).text()
- };
- });
+ callback(users);
+ } else if (xhr.status === 403) {
+ callback([]);
+ }
+ }
+ };
+ xhr.open('GET', URL + ';suggest_type=member;search=' + query, true);
+ xhr.setRequestHeader('X-SMF-AJAX', '1');
+ xhr.withCredentials =
+ typeof allow_xhjr_credentials !== 'undefined' ? allow_xhjr_credentials : false;
+ xhr.send();
+};
- callback(callbackArray);
- }
- });
- }
- }
+const tributeConfig = {
+ values: function (query, callback) {
+ tributeRemoteSearch(query, (users) => callback(users));
+ },
+ lookup: 'value',
+ menuItemLimit: 10,
+ noMatchTemplate: function () {
+ return '';
+ },
};
-$(function()
-{
- $('textarea[name=message]').atwho(atwhoConfig);
- $('.sceditor-container').find('textarea').atwho(atwhoConfig);
- var iframe = $('.sceditor-container').find('iframe')[0];
- if (typeof iframe != 'undefined')
- $(iframe.contentDocument.body).atwho(atwhoConfig);
-});
\ No newline at end of file
+
+const tribute = new Tribute(tributeConfig);
diff --git a/Themes/default/scripts/tribute.js b/Themes/default/scripts/tribute.js
new file mode 100644
index 0000000000..fc7b4c017c
--- /dev/null
+++ b/Themes/default/scripts/tribute.js
@@ -0,0 +1,1781 @@
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+ typeof define === 'function' && define.amd ? define(factory) :
+ (global = global || self, global.Tribute = factory());
+}(this, (function () { 'use strict';
+
+ function _iterableToArrayLimit(r, l) {
+ var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
+ if (null != t) {
+ var e,
+ n,
+ i,
+ u,
+ a = [],
+ f = !0,
+ o = !1;
+ try {
+ if (i = (t = t.call(r)).next, 0 === l) {
+ if (Object(t) !== t) return;
+ f = !1;
+ } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
+ } catch (r) {
+ o = !0, n = r;
+ } finally {
+ try {
+ if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
+ } finally {
+ if (o) throw n;
+ }
+ }
+ return a;
+ }
+ }
+ function _classCallCheck(instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ }
+ function _defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
+ }
+ }
+ function _createClass(Constructor, protoProps, staticProps) {
+ if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) _defineProperties(Constructor, staticProps);
+ Object.defineProperty(Constructor, "prototype", {
+ writable: false
+ });
+ return Constructor;
+ }
+ function _slicedToArray(arr, i) {
+ return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
+ }
+ function _arrayWithHoles(arr) {
+ if (Array.isArray(arr)) return arr;
+ }
+ function _unsupportedIterableToArray(o, minLen) {
+ if (!o) return;
+ if (typeof o === "string") return _arrayLikeToArray(o, minLen);
+ var n = Object.prototype.toString.call(o).slice(8, -1);
+ if (n === "Object" && o.constructor) n = o.constructor.name;
+ if (n === "Map" || n === "Set") return Array.from(o);
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
+ }
+ function _arrayLikeToArray(arr, len) {
+ if (len == null || len > arr.length) len = arr.length;
+ for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
+ return arr2;
+ }
+ function _nonIterableRest() {
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+ }
+ function _toPrimitive(input, hint) {
+ if (typeof input !== "object" || input === null) return input;
+ var prim = input[Symbol.toPrimitive];
+ if (prim !== undefined) {
+ var res = prim.call(input, hint || "default");
+ if (typeof res !== "object") return res;
+ throw new TypeError("@@toPrimitive must return a primitive value.");
+ }
+ return (hint === "string" ? String : Number)(input);
+ }
+ function _toPropertyKey(arg) {
+ var key = _toPrimitive(arg, "string");
+ return typeof key === "symbol" ? key : String(key);
+ }
+
+ if (!Array.prototype.find) {
+ Object.defineProperty(Array.prototype, 'find', {
+ value: function value(predicate) {
+ // 1. Let O be ? ToObject(this value).
+ if (this == null) {
+ throw TypeError('"this" is null or not defined');
+ }
+ var o = Object(this);
+
+ // 2. Let len be ? ToLength(? Get(O, "length")).
+ var len = o.length >>> 0;
+
+ // 3. If IsCallable(predicate) is false, throw a TypeError exception.
+ if (typeof predicate !== 'function') {
+ throw TypeError('predicate must be a function');
+ }
+
+ // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
+ var thisArg = arguments[1];
+
+ // 5. Let k be 0.
+ var k = 0;
+
+ // 6. Repeat, while k < len
+ while (k < len) {
+ // a. Let Pk be ! ToString(k).
+ // b. Let kValue be ? Get(O, Pk).
+ // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
+ // d. If testResult is true, return kValue.
+ var kValue = o[k];
+ if (predicate.call(thisArg, kValue, k, o)) {
+ return kValue;
+ }
+ // e. Increase k by 1.
+ k++;
+ }
+
+ // 7. Return undefined.
+ return undefined;
+ },
+ configurable: true,
+ writable: true
+ });
+ }
+ if (typeof window !== 'undefined' && typeof window.CustomEvent !== "function") {
+ var CustomEvent$1 = function CustomEvent(event, params) {
+ params = params || {
+ bubbles: false,
+ cancelable: false,
+ detail: undefined
+ };
+ var evt = document.createEvent('CustomEvent');
+ evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
+ return evt;
+ };
+ if (typeof window.Event !== 'undefined') {
+ CustomEvent$1.prototype = window.Event.prototype;
+ }
+ window.CustomEvent = CustomEvent$1;
+ }
+
+ var TributeEvents = /*#__PURE__*/function () {
+ function TributeEvents(tribute) {
+ _classCallCheck(this, TributeEvents);
+ this.tribute = tribute;
+ this.tribute.events = this;
+ }
+ _createClass(TributeEvents, [{
+ key: "bind",
+ value: function bind(element) {
+ element.boundKeydown = this.keydown.bind(element, this);
+ element.boundKeyup = this.keyup.bind(element, this);
+ element.boundInput = this.input.bind(element, this);
+ element.addEventListener("keydown", element.boundKeydown, true);
+ element.addEventListener("keyup", element.boundKeyup, true);
+ element.addEventListener("input", element.boundInput, true);
+ }
+ }, {
+ key: "unbind",
+ value: function unbind(element) {
+ element.removeEventListener("keydown", element.boundKeydown, true);
+ element.removeEventListener("keyup", element.boundKeyup, true);
+ element.removeEventListener("input", element.boundInput, true);
+ delete element.boundKeydown;
+ delete element.boundKeyup;
+ delete element.boundInput;
+ }
+ }, {
+ key: "keydown",
+ value: function keydown(instance, event) {
+ if (instance.shouldDeactivate(event)) {
+ instance.tribute.isActive = false;
+ instance.tribute.hideMenu();
+ }
+ var element = this;
+ instance.commandEvent = false;
+ TributeEvents.keys().forEach(function (o) {
+ if (o.key === event.keyCode) {
+ instance.commandEvent = true;
+ instance.callbacks()[o.value.toLowerCase()](event, element);
+ }
+ });
+ }
+ }, {
+ key: "input",
+ value: function input(instance, event) {
+ instance.inputEvent = true;
+ instance.keyup.call(this, instance, event);
+ }
+ }, {
+ key: "click",
+ value: function click(instance, event) {
+ var tribute = instance.tribute;
+ if (tribute.menu && tribute.menu.contains(event.target)) {
+ var li = event.target;
+ event.preventDefault();
+ event.stopPropagation();
+ while (li.nodeName.toLowerCase() !== "li") {
+ li = li.parentNode;
+ if (!li || li === tribute.menu) {
+ // When li === tribute.menu, it's either a click on the entire component or on the scrollbar (if visible)
+ li = undefined;
+ break;
+ }
+ }
+ if (!li) {
+ return;
+ }
+ if (tribute.current.filteredItems.length === 0) li.setAttribute("data-index", -1);
+ if (li.getAttribute("data-disabled") === "true") return;
+ tribute.selectItemAtIndex(li.getAttribute("data-index"), event);
+ tribute.hideMenu();
+
+ // TODO: should fire with externalTrigger and target is outside of menu
+ } else if (tribute.current.externalTrigger) {
+ tribute.current.externalTrigger = false;
+ } else if (tribute.current.element && !tribute.current.externalTrigger) {
+ setTimeout(function () {
+ return tribute.hideMenu();
+ });
+ }
+ }
+ }, {
+ key: "keyup",
+ value: function keyup(instance, event) {
+ if (instance.inputEvent) {
+ instance.inputEvent = false;
+ }
+ instance.updateSelection(this);
+ if (!event.keyCode || event.keyCode === 27) return;
+ if (!instance.tribute.allowSpaces && instance.tribute.hasTrailingSpace) {
+ instance.tribute.hasTrailingSpace = false;
+ instance.commandEvent = true;
+ instance.callbacks()["space"](event, this);
+ return;
+ }
+ if (!instance.tribute.isActive) {
+ if (instance.tribute.autocompleteMode) {
+ instance.callbacks().triggerChar(event, this, "");
+ } else {
+ var keyCode = instance.getKeyCode(instance, this, event);
+ if (isNaN(keyCode) || !keyCode) return;
+ var trigger = instance.tribute.triggers().find(function (trigger) {
+ return trigger.charCodeAt(0) === keyCode;
+ });
+ if (typeof trigger !== "undefined") {
+ instance.callbacks().triggerChar(event, this, trigger);
+ }
+ }
+ }
+ if (instance.tribute.current.mentionText.length < instance.tribute.current.collection.menuShowMinLength) {
+ instance.tribute.hideMenu();
+ return;
+ }
+ if ((instance.tribute.current.trigger || instance.tribute.autocompleteMode) && instance.commandEvent === false || instance.tribute.isActive || event.keyCode === 8) {
+ instance.tribute.showMenuFor(this, true);
+ }
+ }
+ }, {
+ key: "shouldDeactivate",
+ value: function shouldDeactivate(event) {
+ if (!this.tribute.isActive) return false;
+ if (this.tribute.current.mentionText.length === 0) {
+ var eventKeyPressed = false;
+ TributeEvents.keys().forEach(function (o) {
+ if (event.keyCode === o.key) eventKeyPressed = true;
+ });
+ return !eventKeyPressed;
+ }
+ return false;
+ }
+ }, {
+ key: "getKeyCode",
+ value: function getKeyCode(instance, el, event) {
+ var tribute = instance.tribute;
+ var info = tribute.range.getTriggerInfo(false, tribute.hasTrailingSpace, true, tribute.allowSpaces, tribute.autocompleteMode);
+ if (info) {
+ return info.mentionTriggerChar.charCodeAt(0);
+ } else {
+ return false;
+ }
+ }
+ }, {
+ key: "updateSelection",
+ value: function updateSelection(el) {
+ this.tribute.current.element = el;
+ var info = this.tribute.range.getTriggerInfo(false, this.tribute.hasTrailingSpace, true, this.tribute.allowSpaces, this.tribute.autocompleteMode);
+ if (info) {
+ this.tribute.current.selectedPath = info.mentionSelectedPath;
+ this.tribute.current.mentionText = info.mentionText;
+ this.tribute.current.selectedOffset = info.mentionSelectedOffset;
+ }
+ }
+ }, {
+ key: "callbacks",
+ value: function callbacks() {
+ var _this = this;
+ return {
+ triggerChar: function triggerChar(e, el, trigger) {
+ var tribute = _this.tribute;
+ tribute.current.trigger = trigger;
+ var collectionItem = tribute.collection.find(function (item) {
+ return item.trigger === trigger;
+ });
+ tribute.current.collection = collectionItem;
+ if (tribute.current.mentionText.length >= tribute.current.collection.menuShowMinLength && tribute.inputEvent) {
+ tribute.showMenuFor(el, true);
+ }
+ },
+ enter: function enter(e, el) {
+ // choose selection
+ var filteredItems = _this.tribute.current.filteredItems;
+ if (_this.tribute.isActive && filteredItems && filteredItems.length) {
+ e.preventDefault();
+ e.stopPropagation();
+ if (_this.tribute.current.filteredItems.length === 0) _this.tribute.menuSelected = -1;
+ setTimeout(function () {
+ _this.tribute.selectItemAtIndex(_this.tribute.menuSelected, e);
+ _this.tribute.hideMenu();
+ }, 0);
+ }
+ },
+ escape: function escape(e, el) {
+ if (_this.tribute.isActive) {
+ e.preventDefault();
+ e.stopPropagation();
+ _this.tribute.isActive = false;
+ _this.tribute.hideMenu();
+ }
+ },
+ tab: function tab(e, el) {
+ // choose first match
+ _this.callbacks().enter(e, el);
+ },
+ space: function space(e, el) {
+ if (_this.tribute.isActive) {
+ if (_this.tribute.spaceSelectsMatch) {
+ _this.callbacks().enter(e, el);
+ } else if (!_this.tribute.allowSpaces) {
+ e.stopPropagation();
+ setTimeout(function () {
+ _this.tribute.hideMenu();
+ _this.tribute.isActive = false;
+ }, 0);
+ }
+ }
+ },
+ up: function up(e, el) {
+ // navigate up ul
+ if (_this.tribute.isActive && _this.tribute.current.filteredItems) {
+ e.preventDefault();
+ e.stopPropagation();
+ var count = _this.tribute.current.filteredItems.length;
+ var lis = _this.tribute.menu.querySelectorAll("li");
+
+ //If menuSelected is -1 then there are no valid, non-disabled items
+ //to navigate through
+ if (_this.tribute.menuSelected === -1) {
+ return;
+ }
+ do {
+ _this.tribute.menuSelected--;
+ if (_this.tribute.menuSelected === -1) {
+ _this.tribute.menuSelected = count - 1;
+ _this.tribute.menu.scrollTop = _this.tribute.menu.scrollHeight;
+ }
+ } while (lis[_this.tribute.menuSelected].getAttribute("data-disabled") === "true");
+ _this.setActiveLi();
+ }
+ },
+ down: function down(e, el) {
+ // navigate down ul
+ if (_this.tribute.isActive && _this.tribute.current.filteredItems) {
+ e.preventDefault();
+ e.stopPropagation();
+ var count = _this.tribute.current.filteredItems.length;
+ var lis = _this.tribute.menu.querySelectorAll("li");
+
+ //If menuSelected is -1 then there are no valid, non-disabled items
+ //to navigate through
+ if (_this.tribute.menuSelected === -1) {
+ return;
+ }
+ do {
+ _this.tribute.menuSelected++;
+ if (_this.tribute.menuSelected >= count) {
+ _this.tribute.menuSelected = 0;
+ _this.tribute.menu.scrollTop = 0;
+ }
+ } while (lis[_this.tribute.menuSelected].getAttribute("data-disabled") === "true");
+ _this.setActiveLi();
+ }
+ },
+ "delete": function _delete(e, el) {
+ if (_this.tribute.isActive && _this.tribute.current.mentionText.length < 1) {
+ _this.tribute.hideMenu();
+ } else if (_this.tribute.isActive) {
+ _this.tribute.showMenuFor(el);
+ }
+ }
+ };
+ }
+ }, {
+ key: "setActiveLi",
+ value: function setActiveLi(index) {
+ var lis = this.tribute.menu.querySelectorAll("li"),
+ length = lis.length >>> 0;
+ if (index) this.tribute.menuSelected = parseInt(index);
+ for (var i = 0; i < length; i++) {
+ var li = lis[i];
+ if (i === this.tribute.menuSelected) {
+ if (li.getAttribute("data-disabled") !== "true") {
+ li.classList.add(this.tribute.current.collection.selectClass);
+ }
+ var liClientRect = li.getBoundingClientRect();
+ var menuClientRect = this.tribute.menu.getBoundingClientRect();
+ if (liClientRect.bottom > menuClientRect.bottom) {
+ var scrollDistance = liClientRect.bottom - menuClientRect.bottom;
+ this.tribute.menu.scrollTop += scrollDistance;
+ } else if (liClientRect.top < menuClientRect.top) {
+ var _scrollDistance = menuClientRect.top - liClientRect.top;
+ this.tribute.menu.scrollTop -= _scrollDistance;
+ }
+ } else {
+ li.classList.remove(this.tribute.current.collection.selectClass);
+ }
+ }
+ }
+ }, {
+ key: "getFullHeight",
+ value: function getFullHeight(elem, includeMargin) {
+ var height = elem.getBoundingClientRect().height;
+ if (includeMargin) {
+ var style = elem.currentStyle || window.getComputedStyle(elem);
+ return height + parseFloat(style.marginTop) + parseFloat(style.marginBottom);
+ }
+ return height;
+ }
+ }], [{
+ key: "keys",
+ value: function keys() {
+ return [{
+ key: 9,
+ value: "TAB"
+ }, {
+ key: 8,
+ value: "DELETE"
+ }, {
+ key: 13,
+ value: "ENTER"
+ }, {
+ key: 27,
+ value: "ESCAPE"
+ }, {
+ key: 32,
+ value: "SPACE"
+ }, {
+ key: 38,
+ value: "UP"
+ }, {
+ key: 40,
+ value: "DOWN"
+ }];
+ }
+ }]);
+ return TributeEvents;
+ }();
+
+ var TributeMenuEvents = /*#__PURE__*/function () {
+ function TributeMenuEvents(tribute) {
+ _classCallCheck(this, TributeMenuEvents);
+ this.tribute = tribute;
+ this.tribute.menuEvents = this;
+ this.menu = this.tribute.menu;
+ }
+ _createClass(TributeMenuEvents, [{
+ key: "bind",
+ value: function bind(menu) {
+ var _this = this;
+ this.menuClickEvent = this.tribute.events.click.bind(null, this);
+ this.menuContainerScrollEvent = this.debounce(function () {
+ if (_this.tribute.isActive) {
+ _this.tribute.hideMenu();
+ }
+ }, 10, false);
+ this.windowResizeEvent = this.debounce(function () {
+ if (_this.tribute.isActive) {
+ _this.tribute.hideMenu();
+ }
+ }, 10, false);
+ this.closeOnScrollEvent = this.debounce(function () {
+ if (_this.tribute.isActive) {
+ _this.tribute.hideMenu();
+ }
+ }, 10, false);
+
+ // fixes IE11 issues with mousedown
+ this.tribute.range.getDocument().addEventListener("MSPointerDown", this.menuClickEvent, false);
+ this.tribute.range.getDocument().addEventListener("mousedown", this.menuClickEvent, false);
+ window.addEventListener("resize", this.windowResizeEvent);
+ if (this.tribute.closeOnScroll == true) {
+ window.addEventListener('scroll', this.closeOnScrollEvent);
+ } else if (this.tribute.closeOnScroll != false) {
+ this.tribute.closeOnScroll.addEventListener('scroll', this.closeOnScrollEvent, false);
+ } else {
+ if (this.menuContainer) {
+ this.menuContainer.addEventListener('scroll', this.menuContainerScrollEvent, false);
+ } else {
+ window.addEventListener('scroll', this.menuContainerScrollEvent);
+ }
+ }
+ }
+ }, {
+ key: "unbind",
+ value: function unbind(menu) {
+ this.tribute.range.getDocument().removeEventListener("mousedown", this.menuClickEvent, false);
+ this.tribute.range.getDocument().removeEventListener("MSPointerDown", this.menuClickEvent, false);
+ window.removeEventListener("resize", this.windowResizeEvent);
+ if (this.tribute.closeOnScroll === true) {
+ window.removeEventListener('scroll', this.closeOnScrollEvent);
+ } else if (this.tribute.closeOnScroll != false) {
+ this.tribute.closeOnScroll.removeEventListener('scroll', this.closeOnScrollEvent);
+ } else {
+ if (this.menuContainer) {
+ this.menuContainer.removeEventListener('scroll', this.menuContainerScrollEvent, false);
+ } else {
+ window.removeEventListener('scroll', this.menuContainerScrollEvent);
+ }
+ }
+ }
+ }, {
+ key: "debounce",
+ value: function debounce(func, wait, immediate) {
+ var _arguments = arguments,
+ _this2 = this;
+ var timeout;
+ return function () {
+ var context = _this2,
+ args = _arguments;
+ var later = function later() {
+ timeout = null;
+ if (!immediate) func.apply(context, args);
+ };
+ var callNow = immediate && !timeout;
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
+ if (callNow) func.apply(context, args);
+ };
+ }
+ }]);
+ return TributeMenuEvents;
+ }();
+
+ var TributeRange = /*#__PURE__*/function () {
+ function TributeRange(tribute) {
+ _classCallCheck(this, TributeRange);
+ this.tribute = tribute;
+ this.tribute.range = this;
+ }
+ _createClass(TributeRange, [{
+ key: "getDocument",
+ value: function getDocument() {
+ var iframe;
+ if (this.tribute.current.collection) {
+ iframe = this.tribute.current.collection.iframe;
+ }
+ if (!iframe) {
+ return document;
+ }
+ return iframe.contentWindow.document;
+ }
+ }, {
+ key: "positionMenuAtCaret",
+ value: function positionMenuAtCaret(scrollTo) {
+ var context = this.tribute.current,
+ coordinates;
+ var info = this.getTriggerInfo(false, this.tribute.hasTrailingSpace, true, this.tribute.allowSpaces, this.tribute.autocompleteMode);
+ if (typeof info !== 'undefined') {
+ if (!this.tribute.positionMenu) {
+ this.tribute.menu.style.cssText = "display: block;";
+ return;
+ }
+ if (!this.isContentEditable(context.element)) {
+ coordinates = this.getTextAreaOrInputUnderlinePosition(this.tribute.current.element, info.mentionPosition);
+ } else {
+ coordinates = this.getContentEditableCaretPosition(info.mentionPosition);
+ }
+ this.tribute.menu.style.cssText = "top: ".concat(coordinates.top, "px;\n left: ").concat(coordinates.left, "px;\n right: ").concat(coordinates.right, "px;\n bottom: ").concat(coordinates.bottom, "px;\n max-height: ").concat(coordinates.maxHeight || 500, "px;\n max-width: ").concat(coordinates.maxWidth || 300, "px;\n position: ").concat(coordinates.position || 'absolute', ";\n display: block;");
+ if (coordinates.left === 'auto') {
+ this.tribute.menu.style.left = 'auto';
+ }
+ if (coordinates.top === 'auto') {
+ this.tribute.menu.style.top = 'auto';
+ }
+ if (scrollTo) this.scrollIntoView();
+ } else {
+ this.tribute.menu.style.cssText = 'display: none';
+ }
+ }
+ }, {
+ key: "menuContainerIsBody",
+ get: function get() {
+ return this.tribute.menuContainer === document.body || !this.tribute.menuContainer;
+ }
+ }, {
+ key: "selectElement",
+ value: function selectElement(targetElement, path, offset) {
+ var range;
+ var elem = targetElement;
+ if (path) {
+ for (var i = 0; i < path.length; i++) {
+ elem = elem.childNodes[path[i]];
+ if (elem === undefined) {
+ return;
+ }
+ while (elem.length < offset) {
+ offset -= elem.length;
+ elem = elem.nextSibling;
+ }
+ if (elem.childNodes.length === 0 && !elem.length) {
+ elem = elem.previousSibling;
+ }
+ }
+ }
+ var sel = this.getWindowSelection();
+ range = this.getDocument().createRange();
+ range.setStart(elem, offset);
+ range.setEnd(elem, offset);
+ range.collapse(true);
+ try {
+ sel.removeAllRanges();
+ } catch (error) {}
+ sel.addRange(range);
+ targetElement.focus();
+ }
+ }, {
+ key: "replaceTriggerText",
+ value: function replaceTriggerText(text, requireLeadingSpace, hasTrailingSpace, originalEvent, item) {
+ var info = this.getTriggerInfo(true, hasTrailingSpace, requireLeadingSpace, this.tribute.allowSpaces, this.tribute.autocompleteMode);
+ if (info !== undefined) {
+ var context = this.tribute.current;
+ var replaceEvent = new CustomEvent('tribute-replaced', {
+ detail: {
+ item: item,
+ instance: context,
+ context: info,
+ event: originalEvent
+ }
+ });
+ if (!this.isContentEditable(context.element)) {
+ var myField = this.tribute.current.element;
+ var textSuffix = typeof this.tribute.replaceTextSuffix == 'string' ? this.tribute.replaceTextSuffix : ' ';
+ text += textSuffix;
+ var startPos = info.mentionPosition;
+ var endPos = info.mentionPosition + info.mentionText.length + (textSuffix === '' ? 1 : textSuffix.length);
+ if (!this.tribute.autocompleteMode) {
+ endPos += info.mentionTriggerChar.length - 1;
+ }
+ myField.value = myField.value.substring(0, startPos) + text + myField.value.substring(endPos, myField.value.length);
+ myField.selectionStart = startPos + text.length;
+ myField.selectionEnd = startPos + text.length;
+ } else {
+ // add a space to the end of the pasted text
+ var _textSuffix = typeof this.tribute.replaceTextSuffix == 'string' ? this.tribute.replaceTextSuffix : '\xA0';
+ text += _textSuffix;
+ var _endPos = info.mentionPosition + info.mentionText.length;
+ if (!this.tribute.autocompleteMode) {
+ _endPos += info.mentionTriggerChar.length;
+ }
+ this.pasteHtml(text, info.mentionPosition, _endPos);
+ }
+ context.element.dispatchEvent(new CustomEvent('input', {
+ bubbles: true
+ }));
+ context.element.dispatchEvent(replaceEvent);
+ }
+ }
+ }, {
+ key: "pasteHtml",
+ value: function pasteHtml(html, startPos, endPos) {
+ var range, sel;
+ sel = this.getWindowSelection();
+ range = this.getDocument().createRange();
+ range.setStart(sel.anchorNode, startPos);
+ range.setEnd(sel.anchorNode, endPos);
+ range.deleteContents();
+ var el = this.getDocument().createElement('div');
+ el.innerHTML = html;
+ var frag = this.getDocument().createDocumentFragment(),
+ node,
+ lastNode;
+ while (node = el.firstChild) {
+ lastNode = frag.appendChild(node);
+ }
+ range.insertNode(frag);
+
+ // Preserve the selection
+ if (lastNode) {
+ range = range.cloneRange();
+ range.setStartAfter(lastNode);
+ range.collapse(true);
+ sel.removeAllRanges();
+ sel.addRange(range);
+ }
+ }
+ }, {
+ key: "getWindowSelection",
+ value: function getWindowSelection() {
+ if (this.tribute.collection.iframe) {
+ return this.tribute.collection.iframe.contentWindow.getSelection();
+ }
+ if (this.tribute.collection[0].shadowRoot) {
+ return this.tribute.collection[0].shadowRoot.getSelection();
+ }
+ return window.getSelection();
+ }
+ }, {
+ key: "getNodePositionInParent",
+ value: function getNodePositionInParent(element) {
+ if (element.parentNode === null) {
+ return 0;
+ }
+ for (var i = 0; i < element.parentNode.childNodes.length; i++) {
+ var node = element.parentNode.childNodes[i];
+ if (node === element) {
+ return i;
+ }
+ }
+ }
+ }, {
+ key: "getContentEditableSelectedPath",
+ value: function getContentEditableSelectedPath(ctx) {
+ var sel = this.getWindowSelection();
+ var selected = sel.anchorNode;
+ var path = [];
+ var offset;
+ if (selected != null) {
+ var i;
+ var ce = selected.contentEditable;
+ while (selected !== null && ce !== 'true') {
+ i = this.getNodePositionInParent(selected);
+ path.push(i);
+ selected = selected.parentNode;
+ if (selected !== null) {
+ ce = selected.contentEditable;
+ }
+ }
+ path.reverse();
+
+ // getRangeAt may not exist, need alternative
+ offset = sel.getRangeAt(0).startOffset;
+ return {
+ selected: selected,
+ path: path,
+ offset: offset
+ };
+ }
+ }
+ }, {
+ key: "getTextPrecedingCurrentSelection",
+ value: function getTextPrecedingCurrentSelection() {
+ var context = this.tribute.current,
+ text = '';
+ if (!this.isContentEditable(context.element)) {
+ var textComponent = this.tribute.current.element;
+ if (textComponent) {
+ var startPos = textComponent.selectionStart;
+ if (textComponent.value && startPos >= 0) {
+ text = textComponent.value.substring(0, startPos);
+ }
+ }
+ } else {
+ var selectedElem = this.getWindowSelection().anchorNode;
+ if (selectedElem != null) {
+ var workingNodeContent = selectedElem.textContent;
+ var selectStartOffset = this.getWindowSelection().getRangeAt(0).startOffset;
+ if (workingNodeContent && selectStartOffset >= 0) {
+ text = workingNodeContent.substring(0, selectStartOffset);
+ }
+ }
+ }
+ return text;
+ }
+ }, {
+ key: "getLastWordInText",
+ value: function getLastWordInText(text) {
+ var wordsArray;
+ if (this.tribute.autocompleteMode) {
+ if (this.tribute.autocompleteSeparator) {
+ wordsArray = text.split(this.tribute.autocompleteSeparator);
+ } else {
+ wordsArray = [text];
+ }
+ } else {
+ wordsArray = text.split(/\s+/);
+ }
+ var wordsCount = wordsArray.length - 1;
+ return wordsArray[wordsCount];
+ }
+ }, {
+ key: "getTriggerInfo",
+ value: function getTriggerInfo(menuAlreadyActive, hasTrailingSpace, requireLeadingSpace, allowSpaces, isAutocomplete) {
+ var _this = this;
+ var ctx = this.tribute.current;
+ var selected, path, offset;
+ if (!this.isContentEditable(ctx.element)) {
+ selected = this.tribute.current.element;
+ } else {
+ var selectionInfo = this.getContentEditableSelectedPath(ctx);
+ if (selectionInfo) {
+ selected = selectionInfo.selected;
+ path = selectionInfo.path;
+ offset = selectionInfo.offset;
+ }
+ }
+ var effectiveRange = this.getTextPrecedingCurrentSelection();
+ var lastWordOfEffectiveRange = this.getLastWordInText(effectiveRange);
+ if (isAutocomplete) {
+ return {
+ mentionPosition: effectiveRange.length - lastWordOfEffectiveRange.length,
+ mentionText: lastWordOfEffectiveRange,
+ mentionSelectedElement: selected,
+ mentionSelectedPath: path,
+ mentionSelectedOffset: offset
+ };
+ }
+ if (effectiveRange !== undefined && effectiveRange !== null) {
+ var mostRecentTriggerCharPos = -1;
+ var triggerChar;
+ this.tribute.collection.forEach(function (config) {
+ var c = config.trigger;
+ var idx = config.requireLeadingSpace ? _this.lastIndexWithLeadingSpace(effectiveRange, c) : effectiveRange.lastIndexOf(c);
+ if (idx > mostRecentTriggerCharPos) {
+ mostRecentTriggerCharPos = idx;
+ triggerChar = c;
+ requireLeadingSpace = config.requireLeadingSpace;
+ }
+ });
+ if (mostRecentTriggerCharPos >= 0 && (mostRecentTriggerCharPos === 0 || !requireLeadingSpace || /\s/.test(effectiveRange.substring(mostRecentTriggerCharPos - 1, mostRecentTriggerCharPos)))) {
+ var currentTriggerSnippet = effectiveRange.substring(mostRecentTriggerCharPos + triggerChar.length, effectiveRange.length);
+ triggerChar = effectiveRange.substring(mostRecentTriggerCharPos, mostRecentTriggerCharPos + triggerChar.length);
+ var firstSnippetChar = currentTriggerSnippet.substring(0, 1);
+ var leadingSpace = currentTriggerSnippet.length > 0 && (firstSnippetChar === ' ' || firstSnippetChar === '\xA0');
+ if (hasTrailingSpace) {
+ currentTriggerSnippet = currentTriggerSnippet.trim();
+ }
+ var regex = allowSpaces ? /[^\S ]/g : /[\xA0\s]/g;
+ this.tribute.hasTrailingSpace = regex.test(currentTriggerSnippet);
+ if (!leadingSpace && (menuAlreadyActive || !regex.test(currentTriggerSnippet))) {
+ return {
+ mentionPosition: mostRecentTriggerCharPos,
+ mentionText: currentTriggerSnippet,
+ mentionSelectedElement: selected,
+ mentionSelectedPath: path,
+ mentionSelectedOffset: offset,
+ mentionTriggerChar: triggerChar
+ };
+ }
+ }
+ }
+ }
+ }, {
+ key: "lastIndexWithLeadingSpace",
+ value: function lastIndexWithLeadingSpace(str, trigger) {
+ var reversedStr = str.split('').reverse().join('');
+ var index = -1;
+ for (var cidx = 0, len = str.length; cidx < len; cidx++) {
+ var firstChar = cidx === str.length - 1;
+ var leadingSpace = /\s/.test(reversedStr[cidx + 1]);
+ var match = true;
+ for (var triggerIdx = trigger.length - 1; triggerIdx >= 0; triggerIdx--) {
+ if (trigger[triggerIdx] !== reversedStr[cidx - triggerIdx]) {
+ match = false;
+ break;
+ }
+ }
+ if (match && (firstChar || leadingSpace)) {
+ index = str.length - 1 - cidx;
+ break;
+ }
+ }
+ return index;
+ }
+ }, {
+ key: "isContentEditable",
+ value: function isContentEditable(element) {
+ return element.nodeName !== 'INPUT' && element.nodeName !== 'TEXTAREA';
+ }
+ }, {
+ key: "isMenuOffScreen",
+ value: function isMenuOffScreen(coordinates, menuDimensions) {
+ var windowWidth = window.innerWidth;
+ var windowHeight = window.innerHeight;
+ var doc = document.documentElement;
+ var windowLeft = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
+ var windowTop = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
+ var menuTop = typeof coordinates.top === 'number' ? coordinates.top : windowTop + windowHeight - coordinates.bottom - menuDimensions.height;
+ var menuRight = typeof coordinates.right === 'number' ? coordinates.right : coordinates.left + menuDimensions.width;
+ var menuBottom = typeof coordinates.bottom === 'number' ? coordinates.bottom : coordinates.top + menuDimensions.height;
+ var menuLeft = typeof coordinates.left === 'number' ? coordinates.left : windowLeft + windowWidth - coordinates.right - menuDimensions.width;
+ return {
+ top: menuTop < Math.floor(windowTop),
+ right: menuRight > Math.ceil(windowLeft + windowWidth),
+ bottom: menuBottom > Math.ceil(windowTop + windowHeight),
+ left: menuLeft < Math.floor(windowLeft)
+ };
+ }
+ }, {
+ key: "getMenuDimensions",
+ value: function getMenuDimensions() {
+ // Width of the menu depends of its contents and position
+ // We must check what its width would be without any obstruction
+ // This way, we can achieve good positioning for flipping the menu
+ var dimensions = {
+ width: null,
+ height: null
+ };
+ this.tribute.menu.style.cssText = "top: 0px;\n left: 0px;\n position: fixed;\n display: block;\n visibility; hidden;\n max-height:500px;";
+ dimensions.width = this.tribute.menu.offsetWidth;
+ dimensions.height = this.tribute.menu.offsetHeight;
+ this.tribute.menu.style.cssText = "display: none;";
+ return dimensions;
+ }
+ }, {
+ key: "getTextAreaOrInputUnderlinePosition",
+ value: function getTextAreaOrInputUnderlinePosition(element, position, flipped) {
+ var properties = ['direction', 'boxSizing', 'width', 'height', 'overflowX', 'overflowY', 'borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth', 'borderStyle', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'fontStyle', 'fontVariant', 'fontWeight', 'fontStretch', 'fontSize', 'fontSizeAdjust', 'lineHeight', 'fontFamily', 'textAlign', 'textTransform', 'textIndent', 'textDecoration', 'letterSpacing', 'wordSpacing'];
+ var div = this.getDocument().createElement('div');
+ div.id = 'input-textarea-caret-position-mirror-div';
+ this.getDocument().body.appendChild(div);
+ var style = div.style;
+ var computed = window.getComputedStyle ? getComputedStyle(element) : element.currentStyle;
+ style.whiteSpace = 'pre-wrap';
+ if (element.nodeName !== 'INPUT') {
+ style.wordWrap = 'break-word';
+ }
+ style.position = 'absolute';
+ style.visibility = 'hidden';
+
+ // transfer the element's properties to the div
+ properties.forEach(function (prop) {
+ style[prop] = computed[prop];
+ });
+
+ //NOT SURE WHY THIS IS HERE AND IT DOESNT SEEM HELPFUL
+ // if (isFirefox) {
+ // style.width = `${(parseInt(computed.width) - 2)}px`
+ // if (element.scrollHeight > parseInt(computed.height))
+ // style.overflowY = 'scroll'
+ // } else {
+ // style.overflow = 'hidden'
+ // }
+
+ var span0 = document.createElement('span');
+ span0.textContent = element.value.substring(0, position);
+ div.appendChild(span0);
+ if (element.nodeName === 'INPUT') {
+ div.textContent = div.textContent.replace(/\s/g, ' ');
+ }
+
+ //Create a span in the div that represents where the cursor
+ //should be
+ var span = this.getDocument().createElement('span');
+ //we give it no content as this represents the cursor
+ span.textContent = '';
+ div.appendChild(span);
+ var span2 = this.getDocument().createElement('span');
+ span2.textContent = element.value.substring(position);
+ div.appendChild(span2);
+ var rect = element.getBoundingClientRect();
+
+ //position the div exactly over the element
+ //so we can get the bounding client rect for the span and
+ //it should represent exactly where the cursor is
+ div.style.position = 'fixed';
+ div.style.left = rect.left + 'px';
+ div.style.top = rect.top + 'px';
+ div.style.width = rect.width + 'px';
+ div.style.height = rect.height + 'px';
+ div.scrollTop = element.scrollTop;
+ var spanRect = span.getBoundingClientRect();
+ this.getDocument().body.removeChild(div);
+ return this.getFixedCoordinatesRelativeToRect(spanRect);
+ }
+ }, {
+ key: "getContentEditableCaretPosition",
+ value: function getContentEditableCaretPosition(selectedNodePosition) {
+ var range;
+ var sel = this.getWindowSelection();
+ range = this.getDocument().createRange();
+ range.setStart(sel.anchorNode, selectedNodePosition);
+ range.setEnd(sel.anchorNode, selectedNodePosition);
+ range.collapse(false);
+ var rect = range.getBoundingClientRect();
+ return this.getFixedCoordinatesRelativeToRect(rect);
+ }
+ }, {
+ key: "getFixedCoordinatesRelativeToRect",
+ value: function getFixedCoordinatesRelativeToRect(rect) {
+ var coordinates = {
+ position: 'fixed',
+ left: rect.left,
+ top: rect.top + rect.height
+ };
+ var menuDimensions = this.getMenuDimensions();
+ var availableSpaceOnTop = rect.top;
+ var availableSpaceOnBottom = window.innerHeight - (rect.top + rect.height);
+
+ //check to see where's the right place to put the menu vertically
+ if (availableSpaceOnBottom < menuDimensions.height) {
+ if (availableSpaceOnTop >= menuDimensions.height || availableSpaceOnTop > availableSpaceOnBottom) {
+ coordinates.top = 'auto';
+ coordinates.bottom = window.innerHeight - rect.top;
+ if (availableSpaceOnBottom < menuDimensions.height) {
+ coordinates.maxHeight = availableSpaceOnTop;
+ }
+ } else {
+ if (availableSpaceOnTop < menuDimensions.height) {
+ coordinates.maxHeight = availableSpaceOnBottom;
+ }
+ }
+ }
+ var availableSpaceOnLeft = rect.left;
+ var availableSpaceOnRight = window.innerWidth - rect.left;
+
+ //check to see where's the right place to put the menu horizontally
+ if (availableSpaceOnRight < menuDimensions.width) {
+ if (availableSpaceOnLeft >= menuDimensions.width || availableSpaceOnLeft > availableSpaceOnRight) {
+ coordinates.left = 'auto';
+ coordinates.right = window.innerWidth - rect.left;
+ if (availableSpaceOnRight < menuDimensions.width) {
+ coordinates.maxWidth = availableSpaceOnLeft;
+ }
+ } else {
+ if (availableSpaceOnLeft < menuDimensions.width) {
+ coordinates.maxWidth = availableSpaceOnRight;
+ }
+ }
+ }
+ return coordinates;
+ }
+ }, {
+ key: "scrollIntoView",
+ value: function scrollIntoView(elem) {
+ var reasonableBuffer = 20,
+ clientRect;
+ var maxScrollDisplacement = 100;
+ var e = this.menu;
+ if (typeof e === 'undefined') return;
+ while (clientRect === undefined || clientRect.height === 0) {
+ clientRect = e.getBoundingClientRect();
+ if (clientRect.height === 0) {
+ e = e.childNodes[0];
+ if (e === undefined || !e.getBoundingClientRect) {
+ return;
+ }
+ }
+ }
+ var elemTop = clientRect.top;
+ var elemBottom = elemTop + clientRect.height;
+ if (elemTop < 0) {
+ window.scrollTo(0, window.pageYOffset + clientRect.top - reasonableBuffer);
+ } else if (elemBottom > window.innerHeight) {
+ var maxY = window.pageYOffset + clientRect.top - reasonableBuffer;
+ if (maxY - window.pageYOffset > maxScrollDisplacement) {
+ maxY = window.pageYOffset + maxScrollDisplacement;
+ }
+ var targetY = window.pageYOffset - (window.innerHeight - elemBottom);
+ if (targetY > maxY) {
+ targetY = maxY;
+ }
+ window.scrollTo(0, targetY);
+ }
+ }
+ }]);
+ return TributeRange;
+ }();
+
+ // Thanks to https://github.com/mattyork/fuzzy
+ var TributeSearch = /*#__PURE__*/function () {
+ function TributeSearch(tribute) {
+ _classCallCheck(this, TributeSearch);
+ this.tribute = tribute;
+ this.tribute.search = this;
+ }
+ _createClass(TributeSearch, [{
+ key: "simpleFilter",
+ value: function simpleFilter(pattern, array) {
+ var _this = this;
+ return array.filter(function (string) {
+ return _this.test(pattern, string);
+ });
+ }
+ }, {
+ key: "test",
+ value: function test(pattern, string) {
+ return this.match(pattern, string) !== null;
+ }
+ }, {
+ key: "match",
+ value: function match(pattern, string, opts) {
+ opts = opts || {};
+ var len = string.length,
+ pre = opts.pre || '',
+ post = opts.post || '',
+ compareString = opts.caseSensitive && string || string.toLowerCase();
+ if (opts.skip) {
+ return {
+ rendered: string,
+ score: 0
+ };
+ }
+ pattern = opts.caseSensitive && pattern || pattern.toLowerCase();
+ var patternCache = this.traverse(compareString, pattern, 0, 0, []);
+ if (!patternCache) {
+ return null;
+ }
+ return {
+ rendered: this.render(string, patternCache.cache, pre, post),
+ score: patternCache.score
+ };
+ }
+ }, {
+ key: "traverse",
+ value: function traverse(string, pattern, stringIndex, patternIndex, patternCache) {
+ if (this.tribute.autocompleteSeparator) {
+ // if the pattern search at end
+ pattern = pattern.split(this.tribute.autocompleteSeparator).splice(-1)[0];
+ }
+ if (pattern.length === patternIndex) {
+ // calculate score and copy the cache containing the indices where it's found
+ return {
+ score: this.calculateScore(patternCache),
+ cache: patternCache.slice()
+ };
+ }
+
+ // if string at end or remaining pattern > remaining string
+ if (string.length === stringIndex || pattern.length - patternIndex > string.length - stringIndex) {
+ return undefined;
+ }
+ var c = pattern[patternIndex];
+ var index = string.indexOf(c, stringIndex);
+ var best, temp;
+ while (index > -1) {
+ patternCache.push(index);
+ temp = this.traverse(string, pattern, index + 1, patternIndex + 1, patternCache);
+ patternCache.pop();
+
+ // if downstream traversal failed, return best answer so far
+ if (!temp) {
+ return best;
+ }
+ if (!best || best.score < temp.score) {
+ best = temp;
+ }
+ index = string.indexOf(c, index + 1);
+ }
+ return best;
+ }
+ }, {
+ key: "calculateScore",
+ value: function calculateScore(patternCache) {
+ var score = 0;
+ var temp = 1;
+ patternCache.forEach(function (index, i) {
+ if (i > 0) {
+ if (patternCache[i - 1] + 1 === index) {
+ temp += temp + 1;
+ } else {
+ temp = 1;
+ }
+ }
+ score += temp;
+ });
+ return score;
+ }
+ }, {
+ key: "render",
+ value: function render(string, indices, pre, post) {
+ var rendered = string.substring(0, indices[0]);
+ indices.forEach(function (index, i) {
+ rendered += pre + string[index] + post + string.substring(index + 1, indices[i + 1] ? indices[i + 1] : string.length);
+ });
+ return rendered;
+ }
+ }, {
+ key: "filter",
+ value: function filter(pattern, arr, opts) {
+ var _this2 = this;
+ opts = opts || {};
+ return arr.reduce(function (prev, element, idx, arr) {
+ var str = element;
+ if (opts.extract) {
+ str = opts.extract(element);
+ if (!str) {
+ // take care of undefineds / nulls / etc.
+ str = '';
+ }
+ }
+ var rendered = _this2.match(pattern, str, opts);
+ if (rendered != null) {
+ prev[prev.length] = {
+ string: rendered.rendered,
+ score: rendered.score,
+ index: idx,
+ original: element
+ };
+ }
+ return prev;
+ }, []).sort(function (a, b) {
+ var compare = b.score - a.score;
+ if (compare) return compare;
+ return a.index - b.index;
+ });
+ }
+ }]);
+ return TributeSearch;
+ }();
+
+ var Tribute = /*#__PURE__*/function () {
+ function Tribute(_ref) {
+ var _this = this;
+ var _ref$values = _ref.values,
+ values = _ref$values === void 0 ? null : _ref$values,
+ _ref$loadingItemTempl = _ref.loadingItemTemplate,
+ loadingItemTemplate = _ref$loadingItemTempl === void 0 ? null : _ref$loadingItemTempl,
+ _ref$iframe = _ref.iframe,
+ iframe = _ref$iframe === void 0 ? null : _ref$iframe,
+ _ref$shadowRoot = _ref.shadowRoot,
+ shadowRoot = _ref$shadowRoot === void 0 ? null : _ref$shadowRoot,
+ _ref$selectClass = _ref.selectClass,
+ selectClass = _ref$selectClass === void 0 ? "highlight" : _ref$selectClass,
+ _ref$containerClass = _ref.containerClass,
+ containerClass = _ref$containerClass === void 0 ? "tribute-container" : _ref$containerClass,
+ _ref$itemClass = _ref.itemClass,
+ itemClass = _ref$itemClass === void 0 ? "" : _ref$itemClass,
+ _ref$trigger = _ref.trigger,
+ trigger = _ref$trigger === void 0 ? "@" : _ref$trigger,
+ _ref$autocompleteMode = _ref.autocompleteMode,
+ autocompleteMode = _ref$autocompleteMode === void 0 ? false : _ref$autocompleteMode,
+ _ref$autocompleteSepa = _ref.autocompleteSeparator,
+ autocompleteSeparator = _ref$autocompleteSepa === void 0 ? /\s+/ : _ref$autocompleteSepa,
+ _ref$selectTemplate = _ref.selectTemplate,
+ selectTemplate = _ref$selectTemplate === void 0 ? null : _ref$selectTemplate,
+ _ref$menuItemTemplate = _ref.menuItemTemplate,
+ menuItemTemplate = _ref$menuItemTemplate === void 0 ? null : _ref$menuItemTemplate,
+ _ref$lookup = _ref.lookup,
+ lookup = _ref$lookup === void 0 ? "key" : _ref$lookup,
+ _ref$fillAttr = _ref.fillAttr,
+ fillAttr = _ref$fillAttr === void 0 ? "value" : _ref$fillAttr,
+ _ref$collection = _ref.collection,
+ collection = _ref$collection === void 0 ? null : _ref$collection,
+ _ref$menuContainer = _ref.menuContainer,
+ menuContainer = _ref$menuContainer === void 0 ? null : _ref$menuContainer,
+ _ref$noMatchTemplate = _ref.noMatchTemplate,
+ noMatchTemplate = _ref$noMatchTemplate === void 0 ? null : _ref$noMatchTemplate,
+ _ref$requireLeadingSp = _ref.requireLeadingSpace,
+ requireLeadingSpace = _ref$requireLeadingSp === void 0 ? true : _ref$requireLeadingSp,
+ _ref$allowSpaces = _ref.allowSpaces,
+ allowSpaces = _ref$allowSpaces === void 0 ? false : _ref$allowSpaces,
+ _ref$replaceTextSuffi = _ref.replaceTextSuffix,
+ replaceTextSuffix = _ref$replaceTextSuffi === void 0 ? null : _ref$replaceTextSuffi,
+ _ref$positionMenu = _ref.positionMenu,
+ positionMenu = _ref$positionMenu === void 0 ? true : _ref$positionMenu,
+ _ref$spaceSelectsMatc = _ref.spaceSelectsMatch,
+ spaceSelectsMatch = _ref$spaceSelectsMatc === void 0 ? false : _ref$spaceSelectsMatc,
+ _ref$searchOpts = _ref.searchOpts,
+ searchOpts = _ref$searchOpts === void 0 ? {} : _ref$searchOpts,
+ _ref$menuItemLimit = _ref.menuItemLimit,
+ menuItemLimit = _ref$menuItemLimit === void 0 ? null : _ref$menuItemLimit,
+ _ref$menuShowMinLengt = _ref.menuShowMinLength,
+ menuShowMinLength = _ref$menuShowMinLengt === void 0 ? 0 : _ref$menuShowMinLengt,
+ _ref$closeOnScroll = _ref.closeOnScroll,
+ closeOnScroll = _ref$closeOnScroll === void 0 ? false : _ref$closeOnScroll,
+ _ref$maxDisplayItems = _ref.maxDisplayItems,
+ maxDisplayItems = _ref$maxDisplayItems === void 0 ? null : _ref$maxDisplayItems,
+ _ref$isBlocked = _ref.isBlocked,
+ isBlocked = _ref$isBlocked === void 0 ? false : _ref$isBlocked;
+ _classCallCheck(this, Tribute);
+ this.autocompleteMode = autocompleteMode;
+ this.autocompleteSeparator = autocompleteSeparator;
+ this.menuSelected = 0;
+ this.current = {};
+ this.inputEvent = false;
+ this.isActive = false;
+ this.menuContainer = menuContainer;
+ this.allowSpaces = allowSpaces;
+ this.replaceTextSuffix = replaceTextSuffix;
+ this.positionMenu = positionMenu;
+ this.hasTrailingSpace = false;
+ this.spaceSelectsMatch = spaceSelectsMatch;
+ this.closeOnScroll = closeOnScroll;
+ if (this.autocompleteMode) {
+ trigger = "";
+ allowSpaces = false;
+ }
+ if (values) {
+ this.collection = [{
+ // symbol that starts the lookup
+ trigger: trigger,
+ // is it wrapped in an iframe
+ iframe: iframe,
+ // is it wrapped in a web component
+ shadowRoot: shadowRoot,
+ // class applied to selected item
+ selectClass: selectClass,
+ // class applied to the Container
+ containerClass: containerClass,
+ // class applied to each item
+ itemClass: itemClass,
+ // function called on select that retuns the content to insert
+ selectTemplate: (selectTemplate || Tribute.defaultSelectTemplate).bind(this),
+ // function called that returns content for an item
+ menuItemTemplate: (menuItemTemplate || Tribute.defaultMenuItemTemplate).bind(this),
+ // function called when menu is empty, disables hiding of menu.
+ noMatchTemplate: function (t) {
+ if (typeof t === "string") {
+ if (t.trim() === "") return null;
+ return t;
+ }
+ if (typeof t === "function") {
+ return t.bind(_this);
+ }
+ return noMatchTemplate || function () {
+ return "No Match Found!";
+ }.bind(_this);
+ }(noMatchTemplate),
+ // column to search against in the object
+ lookup: lookup,
+ // column that contains the content to insert by default
+ fillAttr: fillAttr,
+ // array of objects or a function returning an array of objects
+ values: values,
+ // useful for when values is an async function
+ loadingItemTemplate: loadingItemTemplate,
+ requireLeadingSpace: requireLeadingSpace,
+ searchOpts: searchOpts,
+ menuItemLimit: menuItemLimit,
+ menuShowMinLength: menuShowMinLength,
+ // Fix for maximum number of items added to the input for the specific Collection
+ maxDisplayItems: maxDisplayItems,
+ isBlocked: isBlocked
+ }];
+ } else if (collection) {
+ if (this.autocompleteMode) console.warn("Tribute in autocomplete mode does not work for collections");
+ this.collection = collection.map(function (item) {
+ return {
+ trigger: item.trigger || trigger,
+ iframe: item.iframe || iframe,
+ shadowRoot: item.shadowRoot || shadowRoot,
+ selectClass: item.selectClass || selectClass,
+ containerClass: item.containerClass || containerClass,
+ itemClass: item.itemClass || itemClass,
+ selectTemplate: (item.selectTemplate || Tribute.defaultSelectTemplate).bind(_this),
+ menuItemTemplate: (item.menuItemTemplate || Tribute.defaultMenuItemTemplate).bind(_this),
+ // function called when menu is empty, disables hiding of menu.
+ noMatchTemplate: function (t) {
+ if (typeof t === "string") {
+ if (t.trim() === "") return null;
+ return t;
+ }
+ if (typeof t === "function") {
+ return t.bind(_this);
+ }
+ return noMatchTemplate || function () {
+ return "No Match Found!";
+ }.bind(_this);
+ }(noMatchTemplate),
+ lookup: item.lookup || lookup,
+ fillAttr: item.fillAttr || fillAttr,
+ values: item.values,
+ loadingItemTemplate: item.loadingItemTemplate,
+ requireLeadingSpace: item.requireLeadingSpace,
+ searchOpts: item.searchOpts || searchOpts,
+ menuItemLimit: item.menuItemLimit || menuItemLimit,
+ menuShowMinLength: item.menuShowMinLength || menuShowMinLength,
+ // Set maximum number of items added to the input for the specific Collection
+ maxDisplayItems: item.maxDisplayItems || maxDisplayItems,
+ isBlocked: item.isBlocked || isBlocked
+ };
+ });
+ } else {
+ throw new Error("[Tribute] No collection specified.");
+ }
+ new TributeRange(this);
+ new TributeEvents(this);
+ new TributeMenuEvents(this);
+ new TributeSearch(this);
+ }
+ _createClass(Tribute, [{
+ key: "isActive",
+ get: function get() {
+ return this._isActive;
+ },
+ set: function set(val) {
+ if (this._isActive != val) {
+ this._isActive = val;
+ if (this.current.element) {
+ var noMatchEvent = new CustomEvent("tribute-active-".concat(val));
+ this.current.element.dispatchEvent(noMatchEvent);
+ }
+ }
+ }
+ }, {
+ key: "triggers",
+ value: function triggers() {
+ return this.collection.map(function (config) {
+ return config.trigger;
+ });
+ }
+ }, {
+ key: "attach",
+ value: function attach(el) {
+ if (!el) {
+ throw new Error("[Tribute] Must pass in a DOM node or NodeList.");
+ }
+
+ // Check if it is a jQuery collection
+ if (typeof jQuery !== "undefined" && el instanceof jQuery) {
+ el = el.get();
+ }
+
+ // Is el an Array/Array-like object?
+ if (el.constructor === NodeList || el.constructor === HTMLCollection || el.constructor === Array) {
+ var length = el.length;
+ for (var i = 0; i < length; ++i) {
+ this._attach(el[i]);
+ }
+ } else {
+ this._attach(el);
+ }
+ }
+ }, {
+ key: "_attach",
+ value: function _attach(el) {
+ if (el.hasAttribute("data-tribute")) {
+ console.warn("Tribute was already bound to " + el.nodeName);
+ }
+ this.ensureEditable(el);
+ this.events.bind(el);
+ el.setAttribute("data-tribute", true);
+ }
+ }, {
+ key: "ensureEditable",
+ value: function ensureEditable(element) {
+ if (Tribute.inputTypes().indexOf(element.nodeName) === -1) {
+ if (!element.contentEditable) {
+ throw new Error("[Tribute] Cannot bind to " + element.nodeName + ", not contentEditable");
+ }
+ }
+ }
+ }, {
+ key: "createMenu",
+ value: function createMenu(containerClass) {
+ var wrapper = this.range.getDocument().createElement("div"),
+ ul = this.range.getDocument().createElement("ul");
+ wrapper.className = containerClass;
+ wrapper.appendChild(ul);
+ if (this.menuContainer) {
+ return this.menuContainer.appendChild(wrapper);
+ }
+ return this.range.getDocument().body.appendChild(wrapper);
+ }
+ }, {
+ key: "showMenuFor",
+ value: function showMenuFor(element, scrollTo) {
+ var _this2 = this;
+ // Check for maximum number of items added to the input for the specific Collection
+ if (this.current.collection.maxDisplayItems && element.querySelectorAll('[data-tribute-trigger="' + this.current.collection.trigger + '"]').length >= this.current.collection.maxDisplayItems || this.current.collection.isBlocked) {
+ //console.log("Tribute: Maximum number of items added!");
+ return;
+ }
+ this.currentMentionTextSnapshot = this.current.mentionText;
+
+ // create the menu if it doesn't exist.
+ if (!this.menu) {
+ this.menu = this.createMenu(this.current.collection.containerClass);
+ element.tributeMenu = this.menu;
+ this.menuEvents.bind(this.menu);
+ }
+ this.isActive = true;
+ this.menuSelected = 0;
+ window.setTimeout(function () {
+ _this2.menu.scrollTop = 0;
+ }, 0);
+ if (!this.current.mentionText) {
+ this.current.mentionText = "";
+ }
+ var processValues = function processValues(values) {
+ // Tribute may not be active any more by the time the value callback returns
+ if (!_this2.isActive) {
+ return;
+ }
+ var items = _this2.search.filter(_this2.current.mentionText, values, {
+ pre: _this2.current.collection.searchOpts.pre || "",
+ post: _this2.current.collection.searchOpts.post || "",
+ skip: _this2.current.collection.searchOpts.skip || false,
+ caseSensitive: _this2.current.collection.searchOpts.caseSensitive || false,
+ extract: function extract(el) {
+ if (typeof _this2.current.collection.lookup === "string") {
+ return el[_this2.current.collection.lookup];
+ } else if (typeof _this2.current.collection.lookup === "function") {
+ return _this2.current.collection.lookup(el, _this2.current.mentionText);
+ } else {
+ throw new Error("Invalid lookup attribute, lookup must be string or function.");
+ }
+ }
+ });
+ if (_this2.current.collection.menuItemLimit) {
+ items = items.slice(0, _this2.current.collection.menuItemLimit);
+ }
+ _this2.current.filteredItems = items;
+ var ul = _this2.menu.querySelector("ul");
+ if (!items.length) {
+ var noMatchEvent = new CustomEvent("tribute-no-match", {
+ detail: _this2.menu
+ });
+ _this2.current.element.dispatchEvent(noMatchEvent);
+ if (typeof _this2.current.collection.noMatchTemplate === "function" && !_this2.current.collection.noMatchTemplate() || !_this2.current.collection.noMatchTemplate) {
+ _this2.hideMenu();
+ } else {
+ typeof _this2.current.collection.noMatchTemplate === "function" ? ul.innerHTML = _this2.current.collection.noMatchTemplate() : ul.innerHTML = _this2.current.collection.noMatchTemplate;
+ _this2.range.positionMenuAtCaret(scrollTo);
+ }
+ return;
+ }
+ ul.innerHTML = "";
+ var fragment = _this2.range.getDocument().createDocumentFragment();
+ _this2.menuSelected = items.findIndex(function (item) {
+ return item.original.disabled !== true;
+ });
+ items.forEach(function (item, index) {
+ var li = _this2.range.getDocument().createElement("li");
+ li.setAttribute("data-index", index);
+ if (item.original.disabled) li.setAttribute("data-disabled", "true");
+ li.className = _this2.current.collection.itemClass;
+ li.addEventListener("mousemove", function (e) {
+ var _this2$_findLiTarget = _this2._findLiTarget(e.target),
+ _this2$_findLiTarget2 = _slicedToArray(_this2$_findLiTarget, 2),
+ li = _this2$_findLiTarget2[0],
+ index = _this2$_findLiTarget2[1];
+ if (e.movementY !== 0) {
+ _this2.events.setActiveLi(index);
+ }
+ });
+ if (_this2.menuSelected === index) {
+ li.classList.add(_this2.current.collection.selectClass);
+ }
+ li.innerHTML = _this2.current.collection.menuItemTemplate(item);
+ fragment.appendChild(li);
+ });
+ ul.appendChild(fragment);
+ _this2.range.positionMenuAtCaret(scrollTo);
+ };
+ if (typeof this.current.collection.values === "function") {
+ if (this.current.collection.loadingItemTemplate) {
+ this.menu.querySelector("ul").innerHTML = this.current.collection.loadingItemTemplate;
+ this.range.positionMenuAtCaret(scrollTo);
+ }
+ this.current.collection.values(this.current.mentionText, processValues);
+ } else {
+ processValues(this.current.collection.values);
+ }
+ }
+ }, {
+ key: "_findLiTarget",
+ value: function _findLiTarget(el) {
+ if (!el) return [];
+ var index = el.getAttribute("data-index");
+ return !index ? this._findLiTarget(el.parentNode) : [el, index];
+ }
+ }, {
+ key: "showMenuForCollection",
+ value: function showMenuForCollection(element, collectionIndex) {
+ // Check for maximum number of items added to the input for the specific Collection
+ if (this.collection[collectionIndex || 0].maxDisplayItems && element.querySelectorAll('[data-tribute-trigger="' + this.collection[collectionIndex || 0].trigger + '"]').length >= this.collection[collectionIndex || 0].maxDisplayItems || this.collection[collectionIndex || 0].isBlocked) {
+ //console.log("Tribute: Maximum number of items added!");
+ return;
+ }
+ if (element !== document.activeElement) {
+ this.placeCaretAtEnd(element);
+ }
+ this.current.collection = this.collection[collectionIndex || 0];
+ this.current.externalTrigger = true;
+ this.current.element = element;
+ if (element.isContentEditable) this.insertTextAtCursor(this.current.collection.trigger);else this.insertAtCaret(element, this.current.collection.trigger);
+ this.showMenuFor(element);
+ }
+
+ // TODO: make sure this works for inputs/textareas
+ }, {
+ key: "placeCaretAtEnd",
+ value: function placeCaretAtEnd(el) {
+ el.focus();
+ if (typeof window.getSelection != "undefined" && typeof document.createRange != "undefined") {
+ var range = document.createRange();
+ range.selectNodeContents(el);
+ range.collapse(false);
+ var sel = window.getSelection();
+ sel.removeAllRanges();
+ sel.addRange(range);
+ } else if (typeof document.body.createTextRange != "undefined") {
+ var textRange = document.body.createTextRange();
+ textRange.moveToElementText(el);
+ textRange.collapse(false);
+ textRange.select();
+ }
+ }
+
+ // for contenteditable
+ }, {
+ key: "insertTextAtCursor",
+ value: function insertTextAtCursor(text) {
+ var sel, range;
+ sel = window.getSelection();
+ range = sel.getRangeAt(0);
+ range.deleteContents();
+ var textNode = document.createTextNode(text);
+ range.insertNode(textNode);
+ range.selectNodeContents(textNode);
+ range.collapse(false);
+ sel.removeAllRanges();
+ sel.addRange(range);
+ }
+
+ // for regular inputs
+ }, {
+ key: "insertAtCaret",
+ value: function insertAtCaret(textarea, text) {
+ var scrollPos = textarea.scrollTop;
+ var caretPos = textarea.selectionStart;
+ var front = textarea.value.substring(0, caretPos);
+ var back = textarea.value.substring(textarea.selectionEnd, textarea.value.length);
+ textarea.value = front + text + back;
+ caretPos = caretPos + text.length;
+ textarea.selectionStart = caretPos;
+ textarea.selectionEnd = caretPos;
+ textarea.focus();
+ textarea.scrollTop = scrollPos;
+ }
+ }, {
+ key: "hideMenu",
+ value: function hideMenu() {
+ if (this.menu) {
+ this.menu.style.cssText = "display: none;";
+ this.isActive = false;
+ this.menuSelected = 0;
+ this.current = {};
+ }
+ }
+ }, {
+ key: "selectItemAtIndex",
+ value: function selectItemAtIndex(index, originalEvent) {
+ index = parseInt(index);
+ if (typeof index !== "number" || isNaN(index) || !originalEvent.target) return;
+ var item = this.current.filteredItems[index];
+ var content = this.current.collection.selectTemplate(item);
+ if (index === -1) {
+ var selectedNoMatchEvent = new CustomEvent('tribute-selected-no-match', {
+ detail: content
+ });
+ this.current.element.dispatchEvent(selectedNoMatchEvent);
+ return;
+ }
+ if (content !== null) this.replaceText(content, originalEvent, item);
+ }
+ }, {
+ key: "replaceText",
+ value: function replaceText(content, originalEvent, item) {
+ this.range.replaceTriggerText(content, true, true, originalEvent, item);
+ }
+ }, {
+ key: "_append",
+ value: function _append(collection, newValues, replace) {
+ if (typeof collection.values === "function") {
+ throw new Error("Unable to append to values, as it is a function.");
+ } else if (!replace) {
+ collection.values = collection.values.concat(newValues);
+ } else {
+ collection.values = newValues;
+ }
+ }
+ }, {
+ key: "append",
+ value: function append(collectionIndex, newValues, replace) {
+ var index = parseInt(collectionIndex);
+ if (typeof index !== "number") throw new Error("please provide an index for the collection to update.");
+ var collection = this.collection[index];
+ this._append(collection, newValues, replace);
+ }
+ }, {
+ key: "appendCurrent",
+ value: function appendCurrent(newValues, replace) {
+ if (this.isActive) {
+ this._append(this.current.collection, newValues, replace);
+ } else {
+ throw new Error("No active state. Please use append instead and pass an index.");
+ }
+ }
+ }, {
+ key: "detach",
+ value: function detach(el) {
+ if (!el) {
+ throw new Error("[Tribute] Must pass in a DOM node or NodeList.");
+ }
+
+ // Check if it is a jQuery collection
+ if (typeof jQuery !== "undefined" && el instanceof jQuery) {
+ el = el.get();
+ }
+
+ // Is el an Array/Array-like object?
+ if (el.constructor === NodeList || el.constructor === HTMLCollection || el.constructor === Array) {
+ var length = el.length;
+ for (var i = 0; i < length; ++i) {
+ this._detach(el[i]);
+ }
+ } else {
+ this._detach(el);
+ }
+ }
+ }, {
+ key: "_detach",
+ value: function _detach(el) {
+ var _this3 = this;
+ this.events.unbind(el);
+ if (el.tributeMenu) {
+ this.menuEvents.unbind(el.tributeMenu);
+ }
+ setTimeout(function () {
+ el.removeAttribute("data-tribute");
+ _this3.isActive = false;
+ if (el.tributeMenu) {
+ el.tributeMenu.remove();
+ }
+ });
+ }
+ }], [{
+ key: "defaultSelectTemplate",
+ value: function defaultSelectTemplate(item) {
+ if (typeof item === "undefined") return "".concat(this.current.collection.trigger).concat(this.current.mentionText);
+ if (this.range.isContentEditable(this.current.element)) {
+ return '' + (this.current.collection.trigger + item.original[this.current.collection.fillAttr]) + "";
+ }
+ return this.current.collection.trigger + item.original[this.current.collection.fillAttr];
+ }
+ }, {
+ key: "defaultMenuItemTemplate",
+ value: function defaultMenuItemTemplate(matchItem) {
+ return matchItem.string;
+ }
+ }, {
+ key: "inputTypes",
+ value: function inputTypes() {
+ return ["TEXTAREA", "INPUT"];
+ }
+ }]);
+ return Tribute;
+ }();
+
+ /**
+ * Tribute.js
+ * Native ES6 JavaScript @mention Plugin
+ **/
+
+ return Tribute;
+
+})));