core/resources/texttospeech/texttospeech.src.js

Summary

Maintainability
C
7 hrs
Test Coverage
(function($) {
    $.textToSpeech = function(options) {
        var settings = $.extend(
            {
                text: '',
                playEvent: 'textToSpeech:play',
                pauseEvent: 'textToSpeech:pause',
                resumeEvent: 'textToSpeech:resume',
                stopEvent: 'textToSpeech:stop',
                errorEvent: 'textToSpeech:error',
                finishedPlayingEvent: 'textToSpeech:finished',
                eventSelector: 'document',
                language: 'en',
                favoriteVoice: ''
            },
            options
        );

        if ('speechSynthesis' in window)
            with (speechSynthesis) {
            return {
                utterance: null,
                isPaused: false,
                checkIfSpeakingInterval: null,

                play() {
                    if (this.isPaused) {
                        return this.resume()
                    }

                    this.utterance = new SpeechSynthesisUtterance(settings.text);

                    this.utterance.onerror = (e) => {
                        console.error(e)
                        this.stop()
                        $(settings.eventSelector).trigger(settings.errorEvent)
                    }

                    /* stop playback in chrome on window close */
                    $(window).on('beforeunload', function() {
                        window.speechSynthesis.cancel();
                    });

                    try {
                        /* cancel is needed for chrome sometimes */
                        window.speechSynthesis.cancel();

                        /* getVoices could be async */
                        const allVoicesObtained = new Promise(function(resolve, reject) {
                            let voices = window.speechSynthesis.getVoices();
                            if (voices.length !== 0) {
                                resolve(voices);
                            } else {
                                window.speechSynthesis.addEventListener('voiceschanged', function() {
                                    voices = window.speechSynthesis.getVoices();
                                    resolve(voices);
                                });
                            }
                        });

                        allVoicesObtained.then(voices => {
                            if (this.utterance) {
                                /* set standard voice */
                                this.utterance.voice = voices.filter(function(voice) {
                                    return voice.lang === settings.language;
                                })[0];

                                /* search for german "google" voice (=higher quality) if available */
                                this.utterance.voice = voices.filter(function(voice) {
                                    return voice.name === settings.favoriteVoice;
                                })[0];

                                // set voice default values
                                this.utterance.volume = 1;
                                this.utterance.rate = 1;
                                this.utterance.pitch = 1;
                                this.utterance.lang = settings.language;

                                this.checkIfSpeaking()
                                window.speechSynthesis.speak(this.utterance);
                                $(settings.eventSelector).trigger(settings.playEvent);
                            }
                        });
                    } catch(e) {
                        console.warn(e)
                        this.stop()
                    }
                },

                pause() {
                    /* pause narration */
                    this.isPaused = true;
                    window.speechSynthesis.pause();
                    $(settings.eventSelector).trigger(settings.pauseEvent);
                },

                resume() {
                    if (this.isPaused) {
                        this.isPaused = false;
                        window.speechSynthesis.resume();
                        $(settings.eventSelector).trigger(settings.resumeEvent);
                    }
                },

                stop() {
                    if (this.checkIfSpeakingInterval) {
                        clearInterval(this.checkIfSpeakingInterval);
                    }

                    this.isPaused = false;
                    window.speechSynthesis.cancel();
                    $(settings.eventSelector).trigger(settings.stopEvent);
                },

                checkIfSpeaking() {
                    this.checkIfSpeakingInterval = setInterval(() => {
                        if (this.utterance && !this.isPaused && !window.speechSynthesis.speaking) {
                            this.stop()
                        }
                    }, 500);
                },

                setText(text) {
                    settings.text = text
                },

                getText() {
                    return settings.text
                }

            }
        } else {
            return false
        }
    };
})(jQuery);