<commit_before>// FIXME: refactor into a single class for srs/free/vocab modes
// @ts-check

import $$, { DomJS, asHtmlElement } from "@lib/dom";
import FlashcardReview from "@app/review/FlashcardReview";
import ReviewPage from "@app/review/ReviewPage";

export default class VocabReview {
  /** @type {TVocabReviewProps} */
  options;

  /** @type {FlashcardReview} */
  oReview;

  /** @type {DomJS<Element>}*/
  $elStats;
  /** @type {HTMLElement} */
  elProgressBar;

  /**
   *
   * @param {TReviewOptions} fcrOptions ... options for FlashcardReview instance
   * @param {TVocabReviewProps} props ... props for Vue component (TBD refactor)
   */
  constructor(fcrOptions, props) {
    // set options
    this.options = props;

    fcrOptions.events = {
      onEndReview: this.onEndReview,
      onFlashcardCreate: this.onFlashcardCreate,
      onFlashcardDestroy: this.onFlashcardDestroy,
      onFlashcardState: this.onFlashcardState,
    };
    fcrOptions.scope = this;

    this.oReview = new FlashcardReview(fcrOptions);

    this.reviewPage = new ReviewPage(this.onAction.bind(this));
    this.reviewPage.addShortcutKey("f", "flip");
    this.reviewPage.addShortcutKey(" ", "flip");
    this.reviewPage.addShortcutKey("b", "back");

    // stats panel
    this.$elStats = $$("#uiFcStats");
    this.elsCount = $$("#uiFcProgressBar .count"); //array
    this.elProgressBar = asHtmlElement($$("#review-progress span")[0]);
  }

  /**
   * Returns an option value
   *
   * @param {keyof TVocabReviewProps} name
   */
  getOption(name) {
    return this.options[name];
  }

  // proxy which *always* returns a valid card
  getFlashcardData() {
    return /**@type {TVocabCardData}*/ (this.oReview.getFlashcardData());
  }

  /**
   * Update the visible stats to the latest server hit,
   * and setup form data for redirection to the Review Summary page.
   *
   */
  onEndReview() {
    //console.log('VocabReview.onEndReview()');
    window.location.href = this.getOption("back_url");
  }

  onFlashcardCreate() {
    console.log("VocabReview.onFlashcardCreate()");

    // Show panels when first card is loaded
    if (this.oReview.getPosition() === 0) {
      this.$elStats.display();
    }

    // Show undo action if available
    $$("#JsBtnBack").display(this.oReview.getPosition() > 0);

    this.updateStatsPanel();

    // set the google search url
    let searchTerm = this.getFlashcardData().compound;
    let searchUrl = "http://www.google.co.jp/search?hl=ja&q=" + encodeURIComponent(searchTerm);
    /**@type{HTMLAnchorElement}*/ ($$("#search-google-jp")[0]).href = searchUrl;
  }

  /**
   * Hide buttons until next card shows up.
   *
   */
  onFlashcardDestroy() {
    $$("#uiFcButtons0").display(false);
    $$("#uiFcButtons1").display(false);
  }

  /** @param {number} iState */
  onFlashcardState(iState) {
    $$("#uiFcButtons0").display(iState === 0);
    $$("#uiFcButtons1").display(iState !== 0);
  }

  /**
   *
   * @param {string} sActionId cf. eventdispatcher
   * @param {Event} oEvent ...
   * @returns
   */
  onAction(sActionId, oEvent) {
    console.log("VocabReview.onAction(%o)", sActionId);

    // flashcard is loading or something..
    if (!this.oReview.getFlashcard()) {
      return false;
    }

    switch (sActionId) {
      case "back":
        if (this.oReview.getPosition() > 0) {
          this.oReview.backward();
        }
        break;

      case "flip":
        if (this.oReview.getFlashcardState() === 0) {
          this.oReview.setFlashcardState(1);
        } else {
          this.oReview.forward();
        }
        break;

      case "search-google-jp":
        break;<commit_msg>(review-vocab): fix the type casting of TCardData<commit_after>// FIXME: refactor into a single class for srs/free/vocab modes
// @ts-check

import $$, { DomJS, asHtmlElement } from "@lib/dom";
import FlashcardReview from "@app/review/FlashcardReview";
import ReviewPage from "@app/review/ReviewPage";

export default class VocabReview {
  /** @type {TVocabReviewProps} */
  options;

  /** @type {FlashcardReview} */
  oReview;

  /** @type {DomJS<Element>}*/
  $elStats;
  /** @type {HTMLElement} */
  elProgressBar;

  /**
   *
   * @param {TReviewOptions} fcrOptions ... options for FlashcardReview instance
   * @param {TVocabReviewProps} props ... props for Vue component (TBD refactor)
   */
  constructor(fcrOptions, props) {
    // set options
    this.options = props;

    fcrOptions.events = {
      onEndReview: this.onEndReview,
      onFlashcardCreate: this.onFlashcardCreate,
      onFlashcardDestroy: this.onFlashcardDestroy,
      onFlashcardState: this.onFlashcardState,
    };
    fcrOptions.scope = this;

    this.oReview = new FlashcardReview(fcrOptions);

    this.reviewPage = new ReviewPage(this.onAction.bind(this));
    this.reviewPage.addShortcutKey("f", "flip");
    this.reviewPage.addShortcutKey(" ", "flip");
    this.reviewPage.addShortcutKey("b", "back");

    // stats panel
    this.$elStats = $$("#uiFcStats");
    this.elsCount = $$("#uiFcProgressBar .count"); //array
    this.elProgressBar = asHtmlElement($$("#review-progress span")[0]);
  }

  /**
   * Returns an option value
   *
   * @param {keyof TVocabReviewProps} name
   */
  getOption(name) {
    return this.options[name];
  }

  /**
   * proxy which *always* returns a valid card
   *
   * @return {TVocabCardData}
   */
  getFlashcardData() {
    return /**@type {any}*/ (this.oReview.getFlashcardData());
  }

  /**
   * Update the visible stats to the latest server hit,
   * and setup form data for redirection to the Review Summary page.
   *
   */
  onEndReview() {
    //console.log('VocabReview.onEndReview()');
    window.location.href = this.getOption("back_url");
  }

  onFlashcardCreate() {
    console.log("VocabReview.onFlashcardCreate()");

    // Show panels when first card is loaded
    if (this.oReview.getPosition() === 0) {
      this.$elStats.display();
    }

    // Show undo action if available
    $$("#JsBtnBack").display(this.oReview.getPosition() > 0);

    this.updateStatsPanel();

    // set the google search url
    let searchTerm = this.getFlashcardData().compound;
    let searchUrl = "http://www.google.co.jp/search?hl=ja&q=" + encodeURIComponent(searchTerm);
    /**@type{HTMLAnchorElement}*/ ($$("#search-google-jp")[0]).href = searchUrl;
  }

  /**
   * Hide buttons until next card shows up.
   *
   */
  onFlashcardDestroy() {
    $$("#uiFcButtons0").display(false);
    $$("#uiFcButtons1").display(false);
  }

  /** @param {number} iState */
  onFlashcardState(iState) {
    $$("#uiFcButtons0").display(iState === 0);
    $$("#uiFcButtons1").display(iState !== 0);
  }

  /**
   *
   * @param {string} sActionId cf. eventdispatcher
   * @param {Event} oEvent ...
   */
  onAction(sActionId, oEvent) {
    console.log("VocabReview.onAction(%o)", sActionId);

    // flashcard is loading or something..
    if (!this.oReview.getFlashcard()) {
      return false;
    }

    switch (sActionId) {
      case "back":
        if (this.oReview.getPosition() > 0) {
          this.oReview.backward();
        }
        break;

      case "flip":
        if (this.oReview.getFlashcardState() === 0) {
          this.oReview.setFlashcardState(1);
        } else {
          this.oReview.forward();
        }
        break;

      case "search-google-jp":
        break;
{'fraction_non_alphanumeric': 0.15619902120717782, 'fraction_numerical': 0.0035345296356715608, 'mean_word_length': 2.9575040344271115, 'pattern_counts': {'":': 6, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '1200231', 'n_tokens_mistral': 2484, 'n_tokens_neox': 2382, 'n_words': 486}