<commit_before>import { Directive, ElementRef, Input, ComponentFactoryResolver, ViewContainerRef, TemplateRef } from "@angular/core";
import { EventEmitter, Output, OnInit, OnChanges, SimpleChanges } from "@angular/core";

import { MentionListComponent } from './mention-list.component';
import { getValue, insertValue, getCaretPosition, setCaretPosition } from './mention-utils';

const KEY_BACKSPACE = 8;
const KEY_TAB = 9;
const KEY_ENTER = 13;
const KEY_SHIFT = 16;
const KEY_ESCAPE = 27;
const KEY_SPACE = 32;
const KEY_LEFT = 37;
const KEY_UP = 38;
const KEY_RIGHT = 39;
const KEY_DOWN = 40;
const KEY_2 = 50;

/**
 * Angular 2 Mentions.
 * https://github.com/dmacfarlane/angular2-mentions
 *
 * Copyright (c) 2017 <NAME>
 */
@Directive({
  selector: '[mention]',
  host: {
    '(keydown)': 'keyHandler($event)',
    '(blur)': 'blurHandler($event)'
  }
})
export class MentionDirective implements OnInit, OnChanges {

  @Input() set mention(items:any[]){
    this.items = items;
  }

  @Input() set mentionConfig(config:any) {
    this.triggerChar = config.triggerChar || this.triggerChar;
    this.labelKey = config.labelKey || this.labelKey;
    this.disableSearch = config.disableSearch || this.disableSearch;
    this.maxItems = config.maxItems || this.maxItems;
    this.mentionSelect = config.mentionSelect || this.mentionSelect;
  }

  // template to use for rendering list items
  @Input() mentionListTemplate: TemplateRef<any>;

  // event emitted whenever the search term changes
  @Output() searchTerm = new EventEmitter();

  // the character that will trigger the menu behavior
  private triggerChar: string = "@";

  // option to specify the field in the objects to be used as the item label
  private labelKey:string = 'label';

  // option to diable internal filtering. can be used to show the full list returned
  // from an async operation (or allows a custom filter function to be used - in future)
  private disableSearch:boolean = false;

  // option to limit the number of items shown in the pop-up menu
  private maxItems:number = -1;

  // optional function to format the selected item before inserting the text
  private mentionSelect: (item: any) => (string) = (item: any) => this.triggerChar + item[this.labelKey];

  searchString: string;
  startPos: number;
  items: any[];
  startNode;
  searchList: MentionListComponent;
  stopSearch: boolean;
  iframe: any; // optional

  constructor(
    private _element: ElementRef,
    private _componentResolver: ComponentFactoryResolver,
    private _viewContainerRef: ViewContainerRef
  ) {}

  ngOnInit() {
    if (this.items && this.items.length>0) {
      if (typeof this.items[0] == 'string') {
        // convert strings to objects
        const me = this;
        this.items = this.items.map(function(label){
          let object = {};
          object[me.labelKey] = label;
          return object;
        });
      }
      // remove items without an labelKey (as it's required to filter the list)
      this.items = this.items.filter(e => e[this.labelKey]);
      this.items.sort((a,b)=>a[this.labelKey].localeCompare(b[this.labelKey]));
      if (this.searchList && !this.searchList.hidden) {
        this.updateSearchList();
      }
    }
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes['mention']) {
      this.ngOnInit();
    }
  }

  setIframe(iframe: HTMLIFrameElement) {
    this.iframe = iframe;
  }

  stopEvent(event: any) {
    //if (event instanceof KeyboardEvent) { // does not work for iframe
    if (!event.wasClick) {
      event.preventDefault();
      event.stopPropagation();
      event.stopImmediatePropagation();
    }
  }

  blurHandler(event: any) {
    this.stopEvent(event);
    this.stopSearch = true;
    if (this.searchList) {
      this.searchList.hidden = true;
    }
  }

  keyHandler(event: any, nativeElement: HTMLInputElement = this._element.nativeElement) {
    let val: string = getValue(nativeElement);
    let pos = getCaretPosition(nativeElement, this.iframe);
    let charPressed = event.key;
    if (!charPressed) {<commit_msg>Modified triggerChar so it can be either a string or number to support keyCodes.<commit_after>import { Directive, ElementRef, Input, ComponentFactoryResolver, ViewContainerRef, TemplateRef } from "@angular/core";
import { EventEmitter, Output, OnInit, OnChanges, SimpleChanges } from "@angular/core";

import { MentionListComponent } from './mention-list.component';
import { getValue, insertValue, getCaretPosition, setCaretPosition } from './mention-utils';

const KEY_BACKSPACE = 8;
const KEY_TAB = 9;
const KEY_ENTER = 13;
const KEY_SHIFT = 16;
const KEY_ESCAPE = 27;
const KEY_SPACE = 32;
const KEY_LEFT = 37;
const KEY_UP = 38;
const KEY_RIGHT = 39;
const KEY_DOWN = 40;
const KEY_2 = 50;

/**
 * Angular 2 Mentions.
 * https://github.com/dmacfarlane/angular2-mentions
 *
 * Copyright (c) 2017 <NAME>
 */
@Directive({
  selector: '[mention]',
  host: {
    '(keydown)': 'keyHandler($event)',
    '(blur)': 'blurHandler($event)'
  }
})
export class MentionDirective implements OnInit, OnChanges {

  @Input() set mention(items:any[]){
    this.items = items;
  }

  @Input() set mentionConfig(config:any) {
    this.triggerChar = config.triggerChar || this.triggerChar;
    this.keyCodeSpecified = typeof this.triggerChar === 'number'
    this.labelKey = config.labelKey || this.labelKey;
    this.disableSearch = config.disableSearch || this.disableSearch;
    this.maxItems = config.maxItems || this.maxItems;
    this.mentionSelect = config.mentionSelect || this.mentionSelect;
  }

  // template to use for rendering list items
  @Input() mentionListTemplate: TemplateRef<any>;

  // event emitted whenever the search term changes
  @Output() searchTerm = new EventEmitter();

  // the character that will trigger the menu behavior
  private triggerChar: string | number = "@";

  // option to specify the field in the objects to be used as the item label
  private labelKey:string = 'label';

  // option to diable internal filtering. can be used to show the full list returned
  // from an async operation (or allows a custom filter function to be used - in future)
  private disableSearch:boolean = false;

  // option to limit the number of items shown in the pop-up menu
  private maxItems:number = -1;

  // optional function to format the selected item before inserting the text
  private mentionSelect: (item: any) => (string) = (item: any) => this.triggerChar + item[this.labelKey];

  searchString: string;
  startPos: number;
  items: any[];
  startNode;
  searchList: MentionListComponent;
  stopSearch: boolean;
  iframe: any; // optional
  keyCodeSpecified: boolean;

  constructor(
    private _element: ElementRef,
    private _componentResolver: ComponentFactoryResolver,
    private _viewContainerRef: ViewContainerRef
  ) {}

  ngOnInit() {
    if (this.items && this.items.length>0) {
      if (typeof this.items[0] == 'string') {
        // convert strings to objects
        const me = this;
        this.items = this.items.map(function(label){
          let object = {};
          object[me.labelKey] = label;
          return object;
        });
      }
      // remove items without an labelKey (as it's required to filter the list)
      this.items = this.items.filter(e => e[this.labelKey]);
      this.items.sort((a,b)=>a[this.labelKey].localeCompare(b[this.labelKey]));
      if (this.searchList && !this.searchList.hidden) {
        this.updateSearchList();
      }
    }
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes['mention']) {
      this.ngOnInit();
    }
  }

  setIframe(iframe: HTMLIFrameElement) {
    this.iframe = iframe;
  }

  stopEvent(event: any) {
    //if (event instanceof KeyboardEvent) { // does not work for iframe
    if (!event.wasClick) {
      event.preventDefault();
      event.stopPropagation();
      event.stopImmediatePropagation();
    }
  }

  blurHandler(event: any) {
    this.stopEvent(event);
    this.stopSearch = true;
    if (this.searchList) {
      this.searchList.hidden = true;
    }
  }

  keyHandler(event: any, nativeElement: HTMLInputElement = this._element.nativeElement) {
    let val: string = getValue(nativeElement);
    let pos = getCaretPosition(nativeElement, this.iframe);
    let charPressed = this.keyCodeSpecified ? event.keyCode : event.key;
    if (!charPressed) {
{'fraction_non_alphanumeric': 0.11791437455154269, 'fraction_numerical': 0.0071753169098301844, 'mean_word_length': 3.479378682378147, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 17, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4647499', 'n_tokens_mistral': 2587, 'n_tokens_neox': 2483, 'n_words': 708}