Source: managers/PageSpeechManager.js

import Cookies from 'js-cookie';

import HT from '../HT';

/** Abstração de speechSynthesis - Objeto nativo do browser */
class PageSpeechManager {

  ht = null;
  static defaultLang = 'pt-BR';
  static activeMessage = 'Leitor de sites ativado.';
  static desactiveMessage = 'Leitor de sites desativado.';
  static welcomeMessage = 'Leitor de sites ativado, clique sobre um texto para ouvi-lo.';
  static errorMessage = 'Seu navegador não suporta a conversão de texto para voz.';

  /** Sintetizador */
  synth = null;

  firstActivation = null;

  _activated = false;
  get activated() { return this._activated; }
  set activated(value) {
    if (value) {
      this._activated = value;

      // Mensagem de boas vindas
      const text = this.firstActivation ? PageSpeechManager.welcomeMessage : PageSpeechManager.activeMessage;
      this.speak(text);

      // 4 segundos para o texto introdutorio ou 3 para o texto padrão
      this.ht.drawer.showSpeechTextDialog(text, this.firstActivation? 4500 : 3000);

      // Cookie para primeira ativacao do speech
      if (this.firstActivation) {
        Cookies.set(FIRST_ACTIVATION_SPEECH_COOKIE_NAME, false, { expires: 7 });
        this.firstActivation = false;
      }
    } else {
      this.speak(PageSpeechManager.desactiveMessage);
      // Calculamos o tempo em que o modal ficará aberto baseado no tamanho do texto
      this.ht.drawer.showSpeechTextDialog(PageSpeechManager.desactiveMessage, 3000);
      this._activated = value;
    }
    this.ht.textManager.activated = !this.ht.textManager.activated;
  }

  onError = () => {
    this.ht.logger.warn(PageSpeechManager.errorMessage);
    this.ht.drawer.lockPageSpeechButton();
  }

  constructor(ht) {
    this.ht = ht;
    // Verifica se o navegador tem suporte a speechSynthesis com a abordagem implementada
    if(typeof window.speechSynthesis == 'undefined' || typeof window.SpeechSynthesisUtterance == 'undefined') 
      return this.onError();

    this.synth = window.speechSynthesis;

    // Captura o cookie para exibir ou não a mensagem de boas vindas
    this.firstActivation = Cookies.get(FIRST_ACTIVATION_SPEECH_COOKIE_NAME) !== 'false';

    // Quando recarregamos a pagina, o sintetizador continua falando, damos o stop() para resolver esse problema.
    this.stop();

    // Prepara o objeto de requisição
    this.prepareUtterance();

    // Ouve os cliques
    this.ht.textManager.on('validElementClicked', this.onValidElementClicked);
    // Ouve o hover
    this.ht.textManager.on('validElementOver', this.onValidElementOver);
    // Ouve o mouse out
    this.ht.textManager.on('validElementOut', this.onValidElementOut);
  }

  /**
   * Prepara a requisição de fala (utterrance)
   * @param text - Texto a ser falado
   */
  prepareUtterance = (text) => {
    let utterance = null;
    utterance = new SpeechSynthesisUtterance();
    utterance.lang = PageSpeechManager.defaultLang;
    utterance.text = text;
    return utterance;
  }

  /** 
   * Quando um elemento com o texto compativel for clicado
   * @param e - Evento
   * @param text - Texto tratado (plainText)
   */
  onValidElementClicked = (e, text) => {
    if (!this.activated) return;

    this.ht.logger.info('Texto a ser convertido para audio', text);
    this.speak(text);
  }

  /**
   * Quando o mouse/touch foca em um elemento com texto compativel
   * @param elem - Elemento que recebeu foco
   */
  onValidElementOver = (elem) => {
    if (this.activated && !HT.deviceInfo.isMobile) elem.classList.add('ht-speech-hover');
  }

  /**
   * Quando o mouse/touch sai de em um elemento com texto compativel
   * @param elem - Elemento que perdeu foco
   */
  onValidElementOut = (elem) => {
    if (this.activated && elem.classList) elem.classList.remove('ht-speech-hover');
  }

  /** Fala um texto */
  speak = (text) => {
    if (!this.activated) return;

    let utterance = this.prepareUtterance(text);

    this.stop();
    this.synth.speak(utterance);
  }

  /** Para o aúdio atual e limpa a fila de espera */
  stop = () => { this.synth.cancel(); }
}
export default PageSpeechManager;