angular-mentions
Version:
Angular mentions for text fields.
1 lines • 62.8 kB
Source Map (JSON)
{"version":3,"file":"angular-mentions.mjs","sources":["../../../projects/angular-mentions/src/lib/mention-config.ts","../../../projects/angular-mentions/src/lib/mention-utils.ts","../../../projects/angular-mentions/src/lib/caret-coords.ts","../../../projects/angular-mentions/src/lib/mention-list.component.ts","../../../projects/angular-mentions/src/lib/mention.directive.ts","../../../projects/angular-mentions/src/lib/mention.module.ts","../../../projects/angular-mentions/src/public-api.ts","../../../projects/angular-mentions/src/angular-mentions.ts"],"sourcesContent":["// configuration structure, backwards compatible with earlier versions\n\nexport interface MentionConfig extends Mentions {\n // nested config\n mentions?:Mentions[];\n \n // option to disable encapsulated styles so global styles can be used instead\n disableStyle?:boolean; \n}\n\nexport interface Mentions {\n // an array of strings or objects to suggest\n items?:any[];\n\n // the character that will trigger the menu behavior\n triggerChar?:string;\n\n // option to specify the field in the objects to be used as the item label\n labelKey?:string;\n\n // option to limit the number of items shown in the pop-up menu\n maxItems?:number;\n\n // option to disable sorting\n disableSort?:boolean;\n\n // option to disable internal filtering. can be used to show the full list returned\n // from an async operation\n disableSearch?:boolean;\n\n // display menu above text instead of below\n dropUp?:boolean;\n\n // whether to allow space while mentioning or not\n allowSpace?:boolean;\n\n // option to include the trigger char in the searchTerm event\n returnTrigger?:boolean;\n\n // optional function to format the selected item before inserting the text\n mentionSelect?:(item:any, triggerChar?:string) => (string);\n\n // optional function to customize the search implementation\n mentionFilter?:(searchString:string, items?:any) => (any[]);\n}","// DOM element manipulation functions...\n//\n\nfunction setValue(el: HTMLInputElement, value: any) {\n //console.log(\"setValue\", el.nodeName, \"[\"+value+\"]\");\n if (isInputOrTextAreaElement(el)) {\n el.value = value;\n }\n else {\n el.textContent = value;\n }\n}\n\nexport function getValue(el: HTMLInputElement) {\n return isInputOrTextAreaElement(el) ? el.value : el.textContent;\n}\n\nexport function insertValue(\n el: HTMLInputElement,\n start: number,\n end: number,\n text: string,\n iframe: HTMLIFrameElement,\n noRecursion: boolean = false\n) {\n //console.log(\"insertValue\", el.nodeName, start, end, \"[\"+text+\"]\", el);\n if (isTextElement(el)) {\n let val = getValue(el);\n setValue(el, val.substring(0, start) + text + val.substring(end, val.length));\n setCaretPosition(el, start + text.length, iframe);\n }\n else if (!noRecursion) {\n let selObj: Selection = getWindowSelection(iframe);\n if (selObj && selObj.rangeCount > 0) {\n var selRange = selObj.getRangeAt(0);\n var position = selRange.startOffset;\n var anchorNode = selObj.anchorNode;\n // if (text.endsWith(' ')) {\n // text = text.substring(0, text.length-1) + '\\xA0';\n // }\n insertValue(<HTMLInputElement>anchorNode, position - (end - start), position, text, iframe, true);\n }\n }\n}\n\nexport function isInputOrTextAreaElement(el: HTMLElement): boolean {\n return el != null && (el.nodeName == 'INPUT' || el.nodeName == 'TEXTAREA');\n};\n\nexport function isTextElement(el: HTMLElement): boolean {\n return el != null && (el.nodeName == 'INPUT' || el.nodeName == 'TEXTAREA' || el.nodeName == '#text');\n};\n\nexport function setCaretPosition(el: HTMLInputElement, pos: number, iframe: HTMLIFrameElement = null) {\n //console.log(\"setCaretPosition\", pos, el, iframe==null);\n if (isInputOrTextAreaElement(el) && el.selectionStart) {\n el.focus();\n el.setSelectionRange(pos, pos);\n }\n else {\n let range = getDocument(iframe).createRange();\n range.setStart(el, pos);\n range.collapse(true);\n let sel = getWindowSelection(iframe);\n sel.removeAllRanges();\n sel.addRange(range);\n }\n}\n\nexport function getCaretPosition(el: HTMLInputElement, iframe: HTMLIFrameElement = null) {\n //console.log(\"getCaretPosition\", el);\n if (isInputOrTextAreaElement(el)) {\n var val = el.value;\n return val.slice(0, el.selectionStart).length;\n }\n else {\n var selObj = getWindowSelection(iframe); //window.getSelection();\n if (selObj.rangeCount > 0) {\n var selRange = selObj.getRangeAt(0);\n var preCaretRange = selRange.cloneRange();\n preCaretRange.selectNodeContents(el);\n preCaretRange.setEnd(selRange.endContainer, selRange.endOffset);\n var position = preCaretRange.toString().length;\n return position;\n }\n }\n}\n\n// Based on ment.io functions...\n//\n\nfunction getDocument(iframe: HTMLIFrameElement) {\n if (!iframe) {\n return document;\n } else {\n return iframe.contentWindow.document;\n }\n}\n\nfunction getWindowSelection(iframe: HTMLIFrameElement): Selection {\n if (!iframe) {\n return window.getSelection();\n } else {\n return iframe.contentWindow.getSelection();\n }\n}\n\nexport function getContentEditableCaretCoords(ctx: { iframe: HTMLIFrameElement, parent?: Element }) {\n let markerTextChar = '\\ufeff';\n let markerId = 'sel_' + new Date().getTime() + '_' + Math.random().toString().substr(2);\n let doc = getDocument(ctx ? ctx.iframe : null);\n let sel = getWindowSelection(ctx ? ctx.iframe : null);\n let prevRange = sel.getRangeAt(0);\n\n // create new range and set postion using prevRange\n let range = doc.createRange();\n range.setStart(sel.anchorNode, prevRange.startOffset);\n range.setEnd(sel.anchorNode, prevRange.startOffset);\n range.collapse(false);\n\n // Create the marker element containing a single invisible character\n // using DOM methods and insert it at the position in the range\n let markerEl = doc.createElement('span');\n markerEl.id = markerId;\n markerEl.appendChild(doc.createTextNode(markerTextChar));\n range.insertNode(markerEl);\n sel.removeAllRanges();\n sel.addRange(prevRange);\n\n let coordinates = {\n left: 0,\n top: markerEl.offsetHeight\n };\n\n localToRelativeCoordinates(ctx, markerEl, coordinates);\n\n markerEl.parentNode.removeChild(markerEl);\n return coordinates;\n}\n\nfunction localToRelativeCoordinates(\n ctx: { iframe: HTMLIFrameElement, parent?: Element },\n element: Element,\n coordinates: { top: number; left: number }\n) {\n let obj = <HTMLElement>element;\n let iframe = ctx ? ctx.iframe : null;\n while (obj) {\n if (ctx.parent != null && ctx.parent == obj) {\n break;\n }\n coordinates.left += obj.offsetLeft + obj.clientLeft;\n coordinates.top += obj.offsetTop + obj.clientTop;\n obj = <HTMLElement>obj.offsetParent;\n if (!obj && iframe) {\n obj = iframe;\n iframe = null;\n }\n }\n obj = <HTMLElement>element;\n iframe = ctx ? ctx.iframe : null;\n while (obj !== getDocument(null).body && obj != null) {\n if (ctx.parent != null && ctx.parent == obj) {\n break;\n }\n if (obj.scrollTop && obj.scrollTop > 0) {\n coordinates.top -= obj.scrollTop;\n }\n if (obj.scrollLeft && obj.scrollLeft > 0) {\n coordinates.left -= obj.scrollLeft;\n }\n obj = <HTMLElement>obj.parentNode;\n if (!obj && iframe) {\n obj = iframe;\n iframe = null;\n }\n }\n}\n","/* From: https://github.com/component/textarea-caret-position */\n/* jshint browser: true */\n\n// (function () {\n\n // We'll copy the properties below into the mirror div.\n // Note that some browsers, such as Firefox, do not concatenate properties\n // into their shorthand (e.g. padding-top, padding-bottom etc. -> padding),\n // so we have to list every single property explicitly.\n var properties = [\n 'direction', // RTL support\n 'boxSizing',\n 'width', // on Chrome and IE, exclude the scrollbar, so the mirror div wraps exactly as the textarea does\n 'height',\n 'overflowX',\n 'overflowY', // copy the scrollbar for IE\n\n 'borderTopWidth',\n 'borderRightWidth',\n 'borderBottomWidth',\n 'borderLeftWidth',\n 'borderStyle',\n\n 'paddingTop',\n 'paddingRight',\n 'paddingBottom',\n 'paddingLeft',\n\n // https://developer.mozilla.org/en-US/docs/Web/CSS/font\n 'fontStyle',\n 'fontVariant',\n 'fontWeight',\n 'fontStretch',\n 'fontSize',\n 'fontSizeAdjust',\n 'lineHeight',\n 'fontFamily',\n\n 'textAlign',\n 'textTransform',\n 'textIndent',\n 'textDecoration', // might not make a difference, but better be safe\n\n 'letterSpacing',\n 'wordSpacing',\n\n 'tabSize',\n 'MozTabSize'\n\n ];\n\n var isBrowser = (typeof window !== 'undefined');\n var isFirefox = (isBrowser && window['mozInnerScreenX'] != null);\n\n export function getCaretCoordinates(element, position, options) {\n if (!isBrowser) {\n throw new Error('textarea-caret-position#getCaretCoordinates should only be called in a browser');\n }\n\n var debug = options && options.debug || false;\n if (debug) {\n var el = document.querySelector('#input-textarea-caret-position-mirror-div');\n if (el) el.parentNode.removeChild(el);\n }\n\n // The mirror div will replicate the textarea's style\n var div = document.createElement('div');\n div.id = 'input-textarea-caret-position-mirror-div';\n document.body.appendChild(div);\n\n var style = div.style;\n var computed = window.getComputedStyle ? window.getComputedStyle(element) : element.currentStyle; // currentStyle for IE < 9\n var isInput = element.nodeName === 'INPUT';\n\n // Default textarea styles\n style.whiteSpace = 'pre-wrap';\n if (!isInput)\n style.wordWrap = 'break-word'; // only for textarea-s\n\n // Position off-screen\n style.position = 'absolute'; // required to return coordinates properly\n if (!debug)\n style.visibility = 'hidden'; // not 'display: none' because we want rendering\n\n // Transfer the element's properties to the div\n properties.forEach(function (prop) {\n if (isInput && prop === 'lineHeight') {\n // Special case for <input>s because text is rendered centered and line height may be != height\n if (computed.boxSizing === \"border-box\") {\n var height = parseInt(computed.height);\n var outerHeight =\n parseInt(computed.paddingTop) +\n parseInt(computed.paddingBottom) +\n parseInt(computed.borderTopWidth) +\n parseInt(computed.borderBottomWidth);\n var targetHeight = outerHeight + parseInt(computed.lineHeight);\n if (height > targetHeight) {\n style.lineHeight = height - outerHeight + \"px\";\n } else if (height === targetHeight) {\n style.lineHeight = computed.lineHeight;\n } else {\n style.lineHeight = '0';\n }\n } else {\n style.lineHeight = computed.height;\n }\n } else {\n style[prop] = computed[prop];\n }\n });\n\n if (isFirefox) {\n // Firefox lies about the overflow property for textareas: https://bugzilla.mozilla.org/show_bug.cgi?id=984275\n if (element.scrollHeight > parseInt(computed.height))\n style.overflowY = 'scroll';\n } else {\n style.overflow = 'hidden'; // for Chrome to not render a scrollbar; IE keeps overflowY = 'scroll'\n }\n\n div.textContent = element.value.substring(0, position);\n // The second special handling for input type=\"text\" vs textarea:\n // spaces need to be replaced with non-breaking spaces - http://stackoverflow.com/a/13402035/1269037\n if (isInput)\n div.textContent = div.textContent.replace(/\\s/g, '\\u00a0');\n\n var span = document.createElement('span');\n // Wrapping must be replicated *exactly*, including when a long word gets\n // onto the next line, with whitespace at the end of the line before (#7).\n // The *only* reliable way to do that is to copy the *entire* rest of the\n // textarea's content into the <span> created at the caret position.\n // For inputs, just '.' would be enough, but no need to bother.\n span.textContent = element.value.substring(position) || '.'; // || because a completely empty faux span doesn't render at all\n div.appendChild(span);\n\n var coordinates = {\n top: span.offsetTop + parseInt(computed['borderTopWidth']),\n left: span.offsetLeft + parseInt(computed['borderLeftWidth']),\n height: parseInt(computed['lineHeight'])\n };\n\n if (debug) {\n span.style.backgroundColor = '#aaa';\n } else {\n document.body.removeChild(div);\n }\n\n return coordinates;\n }\n\n // if (typeof module != 'undefined' && typeof module.exports != 'undefined') {\n // module.exports = getCaretCoordinates;\n // } else if(isBrowser) {\n // window.getCaretCoordinates = getCaretCoordinates;\n // }\n\n // }());","import {\n Component, ElementRef, Output, EventEmitter, ViewChild, Input, TemplateRef, AfterContentChecked\n} from '@angular/core';\n\nimport { isInputOrTextAreaElement, getContentEditableCaretCoords } from './mention-utils';\nimport { getCaretCoordinates } from './caret-coords';\n\n/**\n * Angular Mentions.\n * https://github.com/dmacfarlane/angular-mentions\n *\n * Copyright (c) 2016 Dan MacFarlane\n */\n@Component({\n selector: 'mention-list',\n styleUrls: ['./mention-list.component.scss'],\n template: `\n <ng-template #defaultItemTemplate let-item=\"item\">\n {{item[labelKey]}}\n </ng-template>\n <ul #list [hidden]=\"hidden\" class=\"dropdown-menu scrollable-menu\"\n [class.mention-menu]=\"!styleOff\" [class.mention-dropdown]=\"!styleOff && dropUp\">\n <li *ngFor=\"let item of items; let i = index\"\n [class.active]=\"activeIndex==i\" [class.mention-active]=\"!styleOff && activeIndex==i\">\n <a class=\"dropdown-item\" [class.mention-item]=\"!styleOff\"\n (mousedown)=\"activeIndex=i;itemClick.emit();$event.preventDefault()\">\n <ng-template [ngTemplateOutlet]=\"itemTemplate\" [ngTemplateOutletContext]=\"{'item':item}\"></ng-template>\n </a>\n </li>\n </ul>\n `\n})\nexport class MentionListComponent implements AfterContentChecked {\n @Input() labelKey: string = 'label';\n @Input() itemTemplate: TemplateRef<any>;\n @Output() itemClick = new EventEmitter();\n @ViewChild('list', { static: true }) list: ElementRef;\n @ViewChild('defaultItemTemplate', { static: true }) defaultItemTemplate: TemplateRef<any>;\n items = [];\n activeIndex: number = 0;\n hidden: boolean = false;\n dropUp: boolean = false;\n styleOff: boolean = false;\n private coords: {top:number, left:number} = {top:0, left:0};\n private offset: number = 0;\n constructor(private element: ElementRef) {}\n\n ngAfterContentChecked() {\n if (!this.itemTemplate) {\n this.itemTemplate = this.defaultItemTemplate;\n }\n }\n\n // lots of confusion here between relative coordinates and containers\n position(nativeParentElement: HTMLInputElement, iframe: HTMLIFrameElement = null) {\n if (isInputOrTextAreaElement(nativeParentElement)) {\n // parent elements need to have postition:relative for this to work correctly?\n this.coords = getCaretCoordinates(nativeParentElement, nativeParentElement.selectionStart, null);\n this.coords.top = nativeParentElement.offsetTop + this.coords.top - nativeParentElement.scrollTop;\n this.coords.left = nativeParentElement.offsetLeft + this.coords.left - nativeParentElement.scrollLeft;\n // getCretCoordinates() for text/input elements needs an additional offset to position the list correctly\n this.offset = this.getBlockCursorDimensions(nativeParentElement).height;\n }\n else if (iframe) {\n let context: { iframe: HTMLIFrameElement, parent: Element } = { iframe: iframe, parent: iframe.offsetParent };\n this.coords = getContentEditableCaretCoords(context);\n }\n else {\n let doc = document.documentElement;\n let scrollLeft = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);\n let scrollTop = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);\n // bounding rectangles are relative to view, offsets are relative to container?\n let caretRelativeToView = getContentEditableCaretCoords({ iframe: iframe });\n let parentRelativeToContainer: ClientRect = nativeParentElement.getBoundingClientRect();\n this.coords.top = caretRelativeToView.top - parentRelativeToContainer.top + nativeParentElement.offsetTop - scrollTop;\n this.coords.left = caretRelativeToView.left - parentRelativeToContainer.left + nativeParentElement.offsetLeft - scrollLeft;\n }\n // set the default/inital position\n this.positionElement();\n }\n\n get activeItem() {\n return this.items[this.activeIndex];\n }\n\n activateNextItem() {\n // adjust scrollable-menu offset if the next item is out of view\n let listEl: HTMLElement = this.list.nativeElement;\n let activeEl = listEl.getElementsByClassName('active').item(0);\n if (activeEl) {\n let nextLiEl: HTMLElement = <HTMLElement> activeEl.nextSibling;\n if (nextLiEl && nextLiEl.nodeName == \"LI\") {\n let nextLiRect: ClientRect = nextLiEl.getBoundingClientRect();\n if (nextLiRect.bottom > listEl.getBoundingClientRect().bottom) {\n listEl.scrollTop = nextLiEl.offsetTop + nextLiRect.height - listEl.clientHeight;\n }\n }\n }\n // select the next item\n this.activeIndex = Math.max(Math.min(this.activeIndex + 1, this.items.length - 1), 0);\n }\n\n activatePreviousItem() {\n // adjust the scrollable-menu offset if the previous item is out of view\n let listEl: HTMLElement = this.list.nativeElement;\n let activeEl = listEl.getElementsByClassName('active').item(0);\n if (activeEl) {\n let prevLiEl: HTMLElement = <HTMLElement> activeEl.previousSibling;\n if (prevLiEl && prevLiEl.nodeName == \"LI\") {\n let prevLiRect: ClientRect = prevLiEl.getBoundingClientRect();\n if (prevLiRect.top < listEl.getBoundingClientRect().top) {\n listEl.scrollTop = prevLiEl.offsetTop;\n }\n }\n }\n // select the previous item\n this.activeIndex = Math.max(Math.min(this.activeIndex - 1, this.items.length - 1), 0);\n }\n\n // reset for a new mention search\n reset() {\n this.list.nativeElement.scrollTop = 0;\n this.checkBounds();\n }\n\n // final positioning is done after the list is shown (and the height and width are known)\n // ensure it's in the page bounds\n private checkBounds() {\n let left = this.coords.left, top = this.coords.top, dropUp = this.dropUp;\n const bounds: ClientRect = this.list.nativeElement.getBoundingClientRect();\n // if off right of page, align right\n if (bounds.left + bounds.width > window.innerWidth) {\n left -= bounds.left + bounds.width - window.innerWidth + 10;\n }\n // if more than half off the bottom of the page, force dropUp\n // if ((bounds.top+bounds.height/2)>window.innerHeight) {\n // dropUp = true;\n // }\n // if top is off page, disable dropUp\n if (bounds.top<0) {\n dropUp = false;\n }\n // set the revised/final position\n this.positionElement(left, top, dropUp);\n }\n\n private positionElement(left:number=this.coords.left, top:number=this.coords.top, dropUp:boolean=this.dropUp) {\n const el: HTMLElement = this.element.nativeElement;\n top += dropUp ? 0 : this.offset; // top of list is next line\n el.className = dropUp ? 'dropup' : null;\n el.style.position = \"absolute\";\n el.style.left = left + 'px';\n el.style.top = top + 'px';\n }\n\n private getBlockCursorDimensions(nativeParentElement: HTMLInputElement) {\n const parentStyles = window.getComputedStyle(nativeParentElement);\n return {\n height: parseFloat(parentStyles.lineHeight),\n width: parseFloat(parentStyles.fontSize)\n };\n }\n}\n","import { ComponentFactoryResolver, Directive, ElementRef, TemplateRef, ViewContainerRef } from \"@angular/core\";\nimport { EventEmitter, Input, OnChanges, Output, SimpleChanges } from \"@angular/core\";\nimport { getCaretPosition, getValue, insertValue, setCaretPosition } from './mention-utils';\n\nimport { MentionConfig } from \"./mention-config\";\nimport { MentionListComponent } from './mention-list.component';\n\nconst KEY_BACKSPACE = 8;\nconst KEY_TAB = 9;\nconst KEY_ENTER = 13;\nconst KEY_SHIFT = 16;\nconst KEY_ESCAPE = 27;\nconst KEY_SPACE = 32;\nconst KEY_LEFT = 37;\nconst KEY_UP = 38;\nconst KEY_RIGHT = 39;\nconst KEY_DOWN = 40;\nconst KEY_BUFFERED = 229;\n\n/**\n * Angular Mentions.\n * https://github.com/dmacfarlane/angular-mentions\n *\n * Copyright (c) 2017 Dan MacFarlane\n */\n@Directive({\n selector: '[mention], [mentionConfig]',\n host: {\n '(keydown)': 'keyHandler($event)',\n '(input)': 'inputHandler($event)',\n '(blur)': 'blurHandler($event)',\n 'autocomplete': 'off'\n }\n})\nexport class MentionDirective implements OnChanges {\n\n // stores the items passed to the mentions directive and used to populate the root items in mentionConfig\n private mentionItems: any[];\n\n @Input('mention') set mention(items: any[]) {\n this.mentionItems = items;\n }\n\n // the provided configuration object\n @Input() mentionConfig: MentionConfig = { items: [] };\n\n private activeConfig: MentionConfig;\n\n private DEFAULT_CONFIG: MentionConfig = {\n items: [],\n triggerChar: '@',\n labelKey: 'label',\n maxItems: -1,\n allowSpace: false,\n returnTrigger: false,\n mentionSelect: (item: any, triggerChar?: string) => {\n return this.activeConfig.triggerChar + item[this.activeConfig.labelKey];\n },\n mentionFilter: (searchString: string, items: any[]) => {\n const searchStringLowerCase = searchString.toLowerCase();\n return items.filter(e => e[this.activeConfig.labelKey].toLowerCase().startsWith(searchStringLowerCase));\n }\n }\n\n // template to use for rendering list items\n @Input() mentionListTemplate: TemplateRef<any>;\n\n // event emitted whenever the search term changes\n @Output() searchTerm = new EventEmitter<string>();\n\n // event emitted when an item is selected\n @Output() itemSelected = new EventEmitter<any>();\n\n // event emitted whenever the mention list is opened or closed\n @Output() opened = new EventEmitter();\n @Output() closed = new EventEmitter();\n\n private triggerChars: { [key: string]: MentionConfig } = {};\n\n private searchString: string;\n private startPos: number;\n private startNode;\n private searchList: MentionListComponent;\n private searching: boolean;\n private iframe: any; // optional\n private lastKeyCode: number;\n\n constructor(\n private _element: ElementRef,\n private _componentResolver: ComponentFactoryResolver,\n private _viewContainerRef: ViewContainerRef\n ) { }\n\n ngOnChanges(changes: SimpleChanges) {\n // console.log('config change', changes);\n if (changes['mention'] || changes['mentionConfig']) {\n this.updateConfig();\n }\n }\n\n public updateConfig() {\n let config = this.mentionConfig;\n this.triggerChars = {};\n // use items from directive if they have been set\n if (this.mentionItems) {\n config.items = this.mentionItems;\n }\n this.addConfig(config);\n // nested configs\n if (config.mentions) {\n config.mentions.forEach(config => this.addConfig(config));\n }\n }\n\n // add configuration for a trigger char\n private addConfig(config: MentionConfig) {\n // defaults\n let defaults = Object.assign({}, this.DEFAULT_CONFIG);\n config = Object.assign(defaults, config);\n // items\n let items = config.items;\n if (items && items.length > 0) {\n // convert strings to objects\n if (typeof items[0] == 'string') {\n items = items.map((label) => {\n let object = {};\n object[config.labelKey] = label;\n return object;\n });\n }\n if (config.labelKey) {\n // remove items without an labelKey (as it's required to filter the list)\n items = items.filter(e => e[config.labelKey]);\n if (!config.disableSort) {\n items.sort((a, b) => a[config.labelKey].localeCompare(b[config.labelKey]));\n }\n }\n }\n config.items = items;\n\n // add the config\n this.triggerChars[config.triggerChar] = config;\n\n // for async update while menu/search is active\n if (this.activeConfig && this.activeConfig.triggerChar == config.triggerChar) {\n this.activeConfig = config;\n this.updateSearchList();\n }\n }\n\n setIframe(iframe: HTMLIFrameElement) {\n this.iframe = iframe;\n }\n\n stopEvent(event: any) {\n //if (event instanceof KeyboardEvent) { // does not work for iframe\n if (!event.wasClick) {\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n }\n }\n\n blurHandler(event: any) {\n this.stopEvent(event);\n this.stopSearch();\n }\n\n inputHandler(event: any, nativeElement: HTMLInputElement = this._element.nativeElement) {\n if (this.lastKeyCode === KEY_BUFFERED && event.data) {\n let keyCode = event.data.charCodeAt(0);\n this.keyHandler({ keyCode, inputEvent: true }, nativeElement);\n }\n }\n\n // @param nativeElement is the alternative text element in an iframe scenario\n keyHandler(event: any, nativeElement: HTMLInputElement = this._element.nativeElement) {\n this.lastKeyCode = event.keyCode;\n\n if (event.isComposing || event.keyCode === KEY_BUFFERED) {\n return;\n }\n\n let val: string = getValue(nativeElement);\n let pos = getCaretPosition(nativeElement, this.iframe);\n let charPressed = event.key;\n if (!charPressed) {\n let charCode = event.which || event.keyCode;\n if (!event.shiftKey && (charCode >= 65 && charCode <= 90)) {\n charPressed = String.fromCharCode(charCode + 32);\n }\n // else if (event.shiftKey && charCode === KEY_2) {\n // charPressed = this.config.triggerChar;\n // }\n else {\n // TODO (dmacfarlane) fix this for non-alpha keys\n // http://stackoverflow.com/questions/2220196/how-to-decode-character-pressed-from-jquerys-keydowns-event-handler?lq=1\n charPressed = String.fromCharCode(event.which || event.keyCode);\n }\n }\n if (event.keyCode == KEY_ENTER && event.wasClick && pos < this.startPos) {\n // put caret back in position prior to contenteditable menu click\n pos = this.startNode.length;\n setCaretPosition(this.startNode, pos, this.iframe);\n }\n //console.log(\"keyHandler\", this.startPos, pos, val, charPressed, event);\n\n let config = this.triggerChars[charPressed];\n if (config) {\n this.activeConfig = config;\n this.startPos = event.inputEvent ? pos - 1 : pos;\n this.startNode = (this.iframe ? this.iframe.contentWindow.getSelection() : window.getSelection()).anchorNode;\n this.searching = true;\n this.searchString = null;\n this.showSearchList(nativeElement);\n this.updateSearchList();\n\n if (config.returnTrigger) {\n this.searchTerm.emit(config.triggerChar);\n }\n }\n else if (this.startPos >= 0 && this.searching) {\n if (pos <= this.startPos) {\n this.searchList.hidden = true;\n }\n // ignore shift when pressed alone, but not when used with another key\n else if (event.keyCode !== KEY_SHIFT &&\n !event.metaKey &&\n !event.altKey &&\n !event.ctrlKey &&\n pos > this.startPos\n ) {\n if (!this.activeConfig.allowSpace && event.keyCode === KEY_SPACE) {\n this.startPos = -1;\n }\n else if (event.keyCode === KEY_BACKSPACE && pos > 0) {\n pos--;\n if (pos == this.startPos) {\n this.stopSearch();\n }\n }\n else if (this.searchList.hidden) {\n if (event.keyCode === KEY_TAB || event.keyCode === KEY_ENTER) {\n this.stopSearch();\n return;\n }\n }\n else if (!this.searchList.hidden) {\n if (event.keyCode === KEY_TAB || event.keyCode === KEY_ENTER) {\n this.stopEvent(event);\n // emit the selected list item\n this.itemSelected.emit(this.searchList.activeItem);\n // optional function to format the selected item before inserting the text\n const text = this.activeConfig.mentionSelect(this.searchList.activeItem, this.activeConfig.triggerChar);\n // value is inserted without a trailing space for consistency\n // between element types (div and iframe do not preserve the space)\n insertValue(nativeElement, this.startPos, pos, text, this.iframe);\n // fire input event so angular bindings are updated\n if (\"createEvent\" in document) {\n let evt = document.createEvent(\"HTMLEvents\");\n if (this.iframe) {\n // a 'change' event is required to trigger tinymce updates\n evt.initEvent(\"change\", true, false);\n }\n else {\n evt.initEvent(\"input\", true, false);\n }\n // this seems backwards, but fire the event from this elements nativeElement (not the\n // one provided that may be in an iframe, as it won't be propogate)\n this._element.nativeElement.dispatchEvent(evt);\n }\n this.startPos = -1;\n this.stopSearch();\n return false;\n }\n else if (event.keyCode === KEY_ESCAPE) {\n this.stopEvent(event);\n this.stopSearch();\n return false;\n }\n else if (event.keyCode === KEY_DOWN) {\n this.stopEvent(event);\n this.searchList.activateNextItem();\n return false;\n }\n else if (event.keyCode === KEY_UP) {\n this.stopEvent(event);\n this.searchList.activatePreviousItem();\n return false;\n }\n }\n\n if (charPressed.length!=1 && event.keyCode!=KEY_BACKSPACE) {\n this.stopEvent(event);\n return false;\n }\n else if (this.searching) {\n let mention = val.substring(this.startPos + 1, pos);\n if (event.keyCode !== KEY_BACKSPACE && !event.inputEvent) {\n mention += charPressed;\n }\n this.searchString = mention;\n if (this.activeConfig.returnTrigger) {\n const triggerChar = (this.searchString || event.keyCode === KEY_BACKSPACE) ? val.substring(this.startPos, this.startPos + 1) : '';\n this.searchTerm.emit(triggerChar + this.searchString);\n } \n else {\n this.searchTerm.emit(this.searchString);\n }\n this.updateSearchList();\n }\n }\n }\n }\n\n // exposed for external calls to open the mention list, e.g. by clicking a button\n public startSearch(triggerChar?: string, nativeElement: HTMLInputElement = this._element.nativeElement) {\n triggerChar = triggerChar || this.mentionConfig.triggerChar || this.DEFAULT_CONFIG.triggerChar;\n const pos = getCaretPosition(nativeElement, this.iframe);\n insertValue(nativeElement, pos, pos, triggerChar, this.iframe);\n this.keyHandler({ key: triggerChar, inputEvent: true }, nativeElement);\n }\n\n stopSearch() {\n if (this.searchList && !this.searchList.hidden) {\n this.searchList.hidden = true;\n this.closed.emit();\n }\n this.activeConfig = null;\n this.searching = false;\n }\n\n updateSearchList() {\n let matches: any[] = [];\n if (this.activeConfig && this.activeConfig.items) {\n let objects = this.activeConfig.items;\n // disabling the search relies on the async operation to do the filtering\n if (!this.activeConfig.disableSearch && this.searchString && this.activeConfig.labelKey) {\n if (this.activeConfig.mentionFilter) {\n objects = this.activeConfig.mentionFilter(this.searchString, objects);\n }\n }\n matches = objects;\n if (this.activeConfig.maxItems > 0) {\n matches = matches.slice(0, this.activeConfig.maxItems);\n }\n }\n // update the search list\n if (this.searchList) {\n this.searchList.items = matches;\n this.searchList.hidden = matches.length == 0;\n }\n }\n\n showSearchList(nativeElement: HTMLInputElement) {\n this.opened.emit();\n\n if (this.searchList == null) {\n let componentFactory = this._componentResolver.resolveComponentFactory(MentionListComponent);\n let componentRef = this._viewContainerRef.createComponent(componentFactory);\n this.searchList = componentRef.instance;\n this.searchList.itemTemplate = this.mentionListTemplate;\n componentRef.instance['itemClick'].subscribe(() => {\n nativeElement.focus();\n let fakeKeydown = { key: 'Enter', keyCode: KEY_ENTER, wasClick: true };\n this.keyHandler(fakeKeydown, nativeElement);\n });\n }\n this.searchList.labelKey = this.activeConfig.labelKey;\n this.searchList.dropUp = this.activeConfig.dropUp;\n this.searchList.styleOff = this.mentionConfig.disableStyle;\n this.searchList.activeIndex = 0;\n this.searchList.position(nativeElement, this.iframe);\n window.requestAnimationFrame(() => this.searchList.reset());\n }\n}\n","import { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { MentionDirective } from './mention.directive';\nimport { MentionListComponent } from './mention-list.component';\n\n@NgModule({\n declarations: [\n MentionDirective,\n MentionListComponent\n ],\n imports: [\n CommonModule\n ],\n exports: [\n MentionDirective\n ]\n})\nexport class MentionModule { }\n","/*\n * Public API Surface of angular-mentions\n */\n\nexport * from './lib/mention-config';\nexport * from './lib/mention.directive';\nexport * from './lib/mention.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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