<commit_before>/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.io/license
 */

import {QueryList} from '@angular/core';
import {Subject, Subscription} from 'rxjs';
import {
  UP_ARROW,
  DOWN_ARROW,
  LEFT_ARROW,
  RIGHT_ARROW,
  TAB,
  A,
  Z,
  ZERO,
  NINE,
  hasModifierKey,
  HOME,
  END,
} from '@angular/cdk/keycodes';
import {debounceTime, filter, map, tap} from 'rxjs/operators';

/** This interface is for items that can be passed to a ListKeyManager. */
export interface ListKeyManagerOption {
  /** Whether the option is disabled. */
  disabled?: boolean;

  /** Gets the label for this option. */
  getLabel?(): string;
}

/** Modifier keys handled by the ListKeyManager. */
export type ListKeyManagerModifierKey = 'altKey' | 'ctrlKey' | 'metaKey' | 'shiftKey';

/**
 * This class manages keyboard events for selectable lists. If you pass it a query list
 * of items, it will set the active item correctly when arrow events occur.
 */
export class ListKeyManager<T extends ListKeyManagerOption> {
  private _activeItemIndex = -1;
  private _activeItem: T | null = null;
  private _wrap = false;
  private readonly _letterKeyStream = new Subject<string>();
  private _typeaheadSubscription = Subscription.EMPTY;
  private _vertical = true;
  private _horizontal: 'ltr' | 'rtl' | null;
  private _allowedModifierKeys: ListKeyManagerModifierKey[] = [];
  private _homeAndEnd = false;

  /**
   * Predicate function that can be used to check whether an item should be skipped
   * by the key manager. By default, disabled items are skipped.
   */
  private _skipPredicateFn = (item: T) => item.disabled;

  // Buffer for the letters that the user has pressed when the typeahead option is turned on.
  private _pressedLetters: string[] = [];

  constructor(private _items: QueryList<T> | T[]) {
    // We allow for the items to be an array because, in some cases, the consumer may
    // not have access to a QueryList of the items they want to manage (e.g. when the
    // items aren't being collected via `ViewChildren` or `ContentChildren`).
    if (_items instanceof QueryList) {
      _items.changes.subscribe((newItems: QueryList<T>) => {
        if (this._activeItem) {
          const itemArray = newItems.toArray();
          const newIndex = itemArray.indexOf(this._activeItem);

          if (newIndex !== this._activeItemIndex) {
            // Timeout is required to avoid "changed after checked" errors.
            setTimeout(() => {
              this.updateActiveItem(newIndex > -1 ? newIndex : this._activeItemIndex);
            }, 0);
          }
        }
      });
    }
  }

  /**
   * Stream that emits any time the TAB key is pressed, so components can react
   * when focus is shifted off of the list.
   */
  readonly tabOut = new Subject<void>();

  /** Stream that emits whenever the active item of the list manager changes. */
  readonly change = new Subject<number>();

  /**
   * Sets the predicate function that determines which items should be skipped by the
   * list key manager.
   * @param predicate Function that determines whether the given item should be skipped.
   */
  skipPredicate(predicate: (item: T) => boolean): this {
    this._skipPredicateFn = predicate;
    return this;
  }

  /**
   * Configures wrapping mode, which determines whether the active item will wrap to
   * the other end of list when there are no more items in the given direction.
   * @param shouldWrap Whether the list should wrap when reaching the end.
   */<commit_msg>refactor(cdk/a11y): use correct method when updating active item (#24232)<commit_after>/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.io/license
 */

import {QueryList} from '@angular/core';
import {Subject, Subscription} from 'rxjs';
import {
  UP_ARROW,
  DOWN_ARROW,
  LEFT_ARROW,
  RIGHT_ARROW,
  TAB,
  A,
  Z,
  ZERO,
  NINE,
  hasModifierKey,
  HOME,
  END,
} from '@angular/cdk/keycodes';
import {debounceTime, filter, map, tap} from 'rxjs/operators';

/** This interface is for items that can be passed to a ListKeyManager. */
export interface ListKeyManagerOption {
  /** Whether the option is disabled. */
  disabled?: boolean;

  /** Gets the label for this option. */
  getLabel?(): string;
}

/** Modifier keys handled by the ListKeyManager. */
export type ListKeyManagerModifierKey = 'altKey' | 'ctrlKey' | 'metaKey' | 'shiftKey';

/**
 * This class manages keyboard events for selectable lists. If you pass it a query list
 * of items, it will set the active item correctly when arrow events occur.
 */
export class ListKeyManager<T extends ListKeyManagerOption> {
  private _activeItemIndex = -1;
  private _activeItem: T | null = null;
  private _wrap = false;
  private readonly _letterKeyStream = new Subject<string>();
  private _typeaheadSubscription = Subscription.EMPTY;
  private _vertical = true;
  private _horizontal: 'ltr' | 'rtl' | null;
  private _allowedModifierKeys: ListKeyManagerModifierKey[] = [];
  private _homeAndEnd = false;

  /**
   * Predicate function that can be used to check whether an item should be skipped
   * by the key manager. By default, disabled items are skipped.
   */
  private _skipPredicateFn = (item: T) => item.disabled;

  // Buffer for the letters that the user has pressed when the typeahead option is turned on.
  private _pressedLetters: string[] = [];

  constructor(private _items: QueryList<T> | T[]) {
    // We allow for the items to be an array because, in some cases, the consumer may
    // not have access to a QueryList of the items they want to manage (e.g. when the
    // items aren't being collected via `ViewChildren` or `ContentChildren`).
    if (_items instanceof QueryList) {
      _items.changes.subscribe((newItems: QueryList<T>) => {
        if (this._activeItem) {
          const itemArray = newItems.toArray();
          const newIndex = itemArray.indexOf(this._activeItem);

          if (newIndex !== this._activeItemIndex) {
            // Timeout is required to avoid "changed after checked" errors.
            setTimeout(() => {
              this.setActiveItem(newIndex > -1 ? newIndex : this._activeItemIndex);
            }, 0);
          }
        }
      });
    }
  }

  /**
   * Stream that emits any time the TAB key is pressed, so components can react
   * when focus is shifted off of the list.
   */
  readonly tabOut = new Subject<void>();

  /** Stream that emits whenever the active item of the list manager changes. */
  readonly change = new Subject<number>();

  /**
   * Sets the predicate function that determines which items should be skipped by the
   * list key manager.
   * @param predicate Function that determines whether the given item should be skipped.
   */
  skipPredicate(predicate: (item: T) => boolean): this {
    this._skipPredicateFn = predicate;
    return this;
  }

  /**
   * Configures wrapping mode, which determines whether the active item will wrap to
   * the other end of list when there are no more items in the given direction.
   * @param shouldWrap Whether the list should wrap when reaching the end.
   */
{'fraction_non_alphanumeric': 0.09556918882072256, 'fraction_numerical': 0.0017723244717109748, 'mean_word_length': 3.206422018348624, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 25, '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': '4814030', 'n_tokens_mistral': 2076, 'n_tokens_neox': 2023, 'n_words': 828}