angular-ui-mention
Version:
Facebook-like @mentions for text inputs built around composability
1 lines • 5.4 kB
JavaScript
"use strict";var _slicedToArray=function(){function sliceIterator(arr,i){var _arr=[],_n=!0,_d=!1,_e=void 0;try{for(var _s,_i=arr[Symbol.iterator]();!(_n=(_s=_i.next()).done)&&(_arr.push(_s.value),!i||_arr.length!==i);_n=!0);}catch(err){_d=!0,_e=err}finally{try{!_n&&_i["return"]&&_i["return"]()}finally{if(_d)throw _e}}return _arr}return function(arr,i){if(Array.isArray(arr))return arr;if(Symbol.iterator in Object(arr))return sliceIterator(arr,i);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();angular.module("ui.mention",[]).directive("uiMention",function(){return{require:["ngModel","uiMention"],controller:"uiMention",controllerAs:"$mention",link:function($scope,$element,$attrs,_ref){var _ref2=_slicedToArray(_ref,2),ngModel=_ref2[0],uiMention=_ref2[1];uiMention.init(ngModel)}}}),angular.module("ui.mention").controller("uiMention",["$element","$scope","$attrs","$q","$timeout","$document",function($element,$scope,$attrs,$q,$timeout,$document){function parseContentAsText(content){try{return temp.textContent=content,temp.innerHTML}finally{temp.textContent=null}}var _this=this;this.delimiter="@",this.searchPattern=this.pattern||new RegExp("(?:\\s+|^)"+this.delimiter+"(\\w+(?: \\w+)?)$"),this.decodePattern=new RegExp(this.delimiter+"[[\\s\\w]+:[0-9a-z-]+]","gi"),this.$element=$element,this.choices=[],this.mentions=[];var ngModel;this.init=function(model){$attrs.ngTrim="false",ngModel=model,ngModel.$parsers.push(function(value){return _this.mentions=_this.mentions.filter(function(mention){if(~value.indexOf(_this.label(mention)))return value=value.split(_this.label(mention)).join(_this.encode(mention))}),_this.render(value),value}),ngModel.$formatters.push(function(){var value=arguments.length<=0||void 0===arguments[0]?"":arguments[0];return value=value.toString(),_this.mentions=_this.mentions.filter(function(mention){return!!~value.indexOf(_this.encode(mention))&&(value=value.split(_this.encode(mention)).join(_this.label(mention)),!0)}),value}),ngModel.$render=function(){$element.val(ngModel.$viewValue||""),$timeout(_this.autogrow,!0),_this.render()}};var temp=document.createElement("span");this.render=function(){var html=arguments.length<=0||void 0===arguments[0]?ngModel.$modelValue:arguments[0];return html=(html||"").toString(),html=parseContentAsText(html),_this.mentions.forEach(function(mention){html=html.split(_this.encode(mention)).join(_this.highlight(mention))}),_this.renderElement().html(html),html},this.renderElement=function(){return $element.next()},this.highlight=function(choice){return"<span>"+_this.label(choice)+"</span>"},this.decode=function(){var value=arguments.length<=0||void 0===arguments[0]?ngModel.$modelValue:arguments[0];return value?value.replace(_this.decodePattern,"$1"):""},this.label=function(choice){return choice.first+" "+choice.last},this.encode=function(choice){return _this.delimiter+"["+_this.label(choice)+":"+choice.id+"]"},this.replace=function(mention){var search=arguments.length<=1||void 0===arguments[1]?_this.searching:arguments[1],text=arguments.length<=2||void 0===arguments[2]?ngModel.$viewValue:arguments[2];return null===search?text:text=text.substr(0,search.index+search[0].indexOf(_this.delimiter))+_this.label(mention)+" "+text.substr(search.index+search[0].length)},this.select=function(){var choice=arguments.length<=0||void 0===arguments[0]?_this.activeChoice:arguments[0];if(!choice)return!1;var mentionExists=_this.mentions.some(function(mention){return _this.encode(mention)===_this.encode(choice)});mentionExists||_this.mentions.push(choice),ngModel.$setViewValue(_this.replace(choice)),_this.cancel(),ngModel.$render()},this.up=function(){var index=_this.choices.indexOf(_this.activeChoice);index>0?_this.activeChoice=_this.choices[index-1]:_this.activeChoice=_this.choices[_this.choices.length-1]},this.down=function(){var index=_this.choices.indexOf(_this.activeChoice);index<_this.choices.length-1?_this.activeChoice=_this.choices[index+1]:_this.activeChoice=_this.choices[0]},this.search=function(match){return _this.searching=match,$q.when(_this.findChoices(match,_this.mentions)).then(function(choices){return _this.choices=choices,_this.activeChoice=choices[0],choices})},this.findChoices=function(match,mentions){return[]},this.cancel=function(){_this.choices=[],_this.searching=null},this.autogrow=function(){$element[0].style.height=0;var style=getComputedStyle($element[0]);"border-box"==style.boxSizing&&($element[0].style.height=$element[0].scrollHeight+"px")},$element.on("keyup click focus",function(event){if(_this.moved)return _this.moved=!1;if($element[0].selectionStart==$element[0].selectionEnd){var text=$element.val(),match=_this.searchPattern.exec(text.substr(0,$element[0].selectionStart));match?_this.search(match):_this.cancel(),$scope.$$phase||$scope.$apply()}}),$element.on("keydown",function(event){if(_this.searching){switch(event.keyCode){case 13:_this.select();break;case 38:_this.up();break;case 40:_this.down();break;default:return}_this.moved=!0,event.preventDefault(),$scope.$$phase||$scope.$apply()}}),this.onMouseup=function(event){var _this2=this;event.target!=$element[0]&&($document.off("mouseup",this.onMouseup),this.searching&&$scope.$evalAsync(function(){_this2.cancel()}))}.bind(this),$element.on("focus",function(event){$document.on("mouseup",_this.onMouseup)}),$element.on("input",this.autogrow),$timeout(this.autogrow,!0)}]);