PageSourceSearch

https://museudofutebol.org.br/wp-content/plugins/universal-voice-s…/universal-voice-search.js?ver=1790847073

js museudofutebol.org.br collected 2026-10-01 11:58:00 UTC 82,781 bytes, 1,706 lines download raw bytes

1// *****************************************************************************************************
2// *******              speak2web UNIVERSAL VOICE SEARCH                                     ***********
3// *******               Get your subscription at                                            ***********
4// *******                    https://speak2web.com/plugin#plans                             ***********
5// *******               Need support? https://speak2web.com/support                         ***********
6// *******               Licensed GPLv2+                                                     ***********
7//******************************************************************************************************
8window.onload = (event) => {
9    (function () {
10        'use strict';
11
12        // Auto timeout duration to stop listening Mic
13        var uvsMicListenAutoTimeoutDuration = null;
14
15        if (typeof (vs.uvsMicListenTimeoutDuration) != 'undefined' && vs.uvsMicListenTimeoutDuration !== null) {
16            uvsMicListenAutoTimeoutDuration = parseInt(vs.uvsMicListenTimeoutDuration);
17            uvsMicListenAutoTimeoutDuration = isNaN(uvsMicListenAutoTimeoutDuration) ? 8 : uvsMicListenAutoTimeoutDuration;
18        } else {
19            uvsMicListenAutoTimeoutDuration = 8;
20        }
21
22        uvsMicListenAutoTimeoutDuration = (uvsMicListenAutoTimeoutDuration < 8) ? 8 : uvsMicListenAutoTimeoutDuration;
23        uvsMicListenAutoTimeoutDuration = (uvsMicListenAutoTimeoutDuration > 20) ? 20 : uvsMicListenAutoTimeoutDuration;
24        uvsMicListenAutoTimeoutDuration = uvsMicListenAutoTimeoutDuration * 1000;
25
26        // Function to clear mic reset timeout
27        function uvsClearMicResetTimeout() {
28            try {
29                if (window.uvsMicTimeoutIdentifier) {
30                    clearTimeout(window.uvsMicTimeoutIdentifier);
31                    window.uvsMicTimeoutIdentifier = null;
32                }
33            } catch (err) {
34                // Do nothing for now
35            }
36        }
37
38        // sanitize alpha-numeric css values to get numeric value
39        function getNumber(number) {
40            number = parseInt(number, 10);
41            return isNaN(number) || number === null || typeof (number) === 'undefined' ? 0 : number;
42        }
43
44        // Function to check if any mic already listening
45        function uvsAnyOtherMicListening(uvsExceptionBtnId = null) {
46            var uvsOneOfMicListening = false;
47            try {
48                var uvsAllMicButtons = document.querySelectorAll('button.universal-voice-search-button');
49
50                if (typeof (uvsAllMicButtons) == 'undefined'
51                    || uvsAllMicButtons === null
52                    || uvsExceptionBtnId == null) { return uvsOneOfMicListening; }
53
54                for (var uvsI = 0; uvsI < uvsAllMicButtons.length; uvsI++) {
55                    var uvsClassNames = uvsAllMicButtons[uvsI].className;
56                    var uvsBtnId = uvsAllMicButtons[uvsI].getAttribute('id');
57
58                    if (!(typeof (uvsClassNames) != 'undefined' && uvsClassNames.trim() != '')) continue;
59
60                    if (uvsClassNames.indexOf('listening') != -1 && uvsExceptionBtnId != uvsBtnId) {
61                        uvsOneOfMicListening = true;
62                        break;
63                    }
64                }
65            } catch (err) {
66                uvsOneOfMicListening = false;
67            }
68
69            return uvsOneOfMicListening;
70        }
71
72        // Clear any pre-existing timeouts
73        uvsClearMicResetTimeout();
74
75        var inputWrapperSelectorsToSeek = [
76            'form[role=search]',
77            'form[class=searchform]',
78            'form[class=search_form]',
79            'form[class=search-form]',
80            'form[class=searchForm]'
81        ];
82        var searchInputSelectorsToSeek = [
83            'input[name=s]',
84            'input[name=search]',
85            'input[name=find]',
86            'input[type=search]',
87            'input[class=search-field]',
88            'input[class=search_field]',
89            'input[class=searchfield]',
90            'input[class=searchField]',
91            'input[id=search]',
92            'input[id=search-field]',
93            'input[id=search_field]',
94            'input[id=searchfield]',
95            'input[id=searchField]'
96        ];
97
98        var uvsMicEventToListen = 'click';
99
100        // Detect Android OS
101        var ua = navigator.userAgent.toLowerCase();
102        var isAndroid = ua.indexOf("android") > -1;
103
104        var recordTimer = null;
105
106        var uvsAllFormsOnPage = document.querySelectorAll('form');// Get all forms on a page
107        var speechInputWrappers = [];
108
109        // Seek and get forms with search ability
110        try {
111            for (var vdnI = 0; vdnI < inputWrapperSelectorsToSeek.length; vdnI++) {
112                speechInputWrappers = document.querySelectorAll(inputWrapperSelectorsToSeek[vdnI]);
113
114                if (speechInputWrappers.length > 0) { break; }
115            }
116        } catch (err) { speechInputWrappers = []; }
117
118        // Override 'speechInputWrappers' to cover missing forms from page
119        if (speechInputWrappers.length < uvsAllFormsOnPage.length) {
120            speechInputWrappers = null;
121            speechInputWrappers = uvsAllFormsOnPage;
122        }
123
124        let formElementForWidget = null;
125
126        [].forEach.call(speechInputWrappers, function (speechInputWrapper, index) {
127            var inputEl = null;
128            var recognizing = false;
129
130            try {
131                // Preserve first form on page and it's input element for widget
132                if (index == 0) {
133                    formElementForWidget = speechInputWrapper;
134                }
135
136                // Get input field intented for search feature on page
137                for (var uvsI = 0; uvsI < searchInputSelectorsToSeek.length; uvsI++) {
138                    inputEl = speechInputWrapper.querySelector(searchInputSelectorsToSeek[uvsI]);
139
140                    if (inputEl !== null) { break; }
141                }
142
143                // Get submit button
144                let formSubmitBtnEl = speechInputWrapper.querySelector("input[type=submit]");
145
146                if (formSubmitBtnEl === null) {
147                    formSubmitBtnEl = speechInputWrapper.querySelector("button[type=submit]");
148                }
149
150                if (formSubmitBtnEl !== null) {
151                    speechInputWrapper.addEventListener('submit', function (submitEvent) {
152
153                        // If mic is listening then abort form submition
154                        if (recognizing == true) {
155                            submitEvent.preventDefault();
156                        }
157                    }, false);
158
159                    // Remove any overlapping icon from submit button of search form                   
160                    try {
161                        let submitButtonChildNodes = formSubmitBtnEl.querySelectorAll('img, svg');
162
163                        for (let j = 0; j < submitButtonChildNodes.length; j++) {
164                            let submitBtnChildNode = submitButtonChildNodes[j];
165                            submitBtnChildNode.classList.add('uvs-hide-element');
166                        }
167                    } catch (err) {
168                        // do nothing for now
169                    }
170                }
171            } catch (err) { inputEl = null; }
172
173            // If search input field not found then continue
174            if (null === inputEl) { return; }
175
176            try {
177                // Try to show the form temporarily so we can calculate the sizes
178                var speechInputWrapperStyle = speechInputWrapper.getAttribute('style');
179                var havingInlineStyle = (typeof (speechInputWrapperStyle) != 'undefined'
180                    && speechInputWrapperStyle !== null && speechInputWrapperStyle.trim() != '') ? true : false;
181                speechInputWrapperStyle = (havingInlineStyle) ? speechInputWrapperStyle + ';' : '';
182                speechInputWrapper.setAttribute('style', speechInputWrapperStyle + 'display: block !important');
183                //speechInputWrapper.classList.add('universal-voice-search-wrapper');
184                speechInputWrapper.classList.add('uvs-sanitize-form-wrapper');
185
186                // Add some markup as a button to the search form
187                var micBtn = document.createElement('button');
188                micBtn.setAttribute('type', 'button');
189                micBtn.setAttribute('class', 'universal-voice-search-button');
190                micBtn.setAttribute('id', 'universal-voice-search-button' + index);
191                micBtn.appendChild(document.createTextNode(universal_voice_search.button_message));
192
193                // Add mic image icon
194                var uvsMicIcon = document.createElement('img');
195                uvsMicIcon.setAttribute('src', vs.uvsImagesPath + 'uvs_mic.svg');
196                uvsMicIcon.setAttribute('class', 'uvs-mic-image');
197
198                micBtn.appendChild(uvsMicIcon);
199
200                var inputHeight = getNumber(inputEl.offsetHeight);// Get search input height
201                var buttonSize = getNumber(0.8 * inputHeight);
202
203                // Set default mic button size to 35px when button size c
203alculated to 0 or unknown
204                if (getNumber(buttonSize) == 0) { inputHeight = buttonSize = 35; }
205
206                var micbtnPositionTop = getNumber(0.1 * inputHeight);
207
208                // Size and position of complete mic button
209                var inlineStyle = 'top: ' + micbtnPositionTop + 'px; ';
210                inlineStyle += 'height: ' + buttonSize + 'px !important; ';
211                inlineStyle += 'width: ' + buttonSize + 'px !important; ';
212                inlineStyle += 'z-index: 999 !important; margin-left: 3px !important; border-radius: 50% !important;  border: 2px solid #ffff !important;';
213                micBtn.setAttribute('style', inlineStyle);
214
215                // Create Wrapper to wrap around input search field like a elastic band
216                var wrapper = document.createElement('div');
217                wrapper.setAttribute('style', speechInputWrapperStyle + 'display: inline-block !important');
218                let inputCurrentStyle = window.getComputedStyle(inputEl);
219                wrapper.setAttribute('class', 'uvs-mic-band');
220                wrapper.setAttribute('onclick', 'return false');
221                wrapper.style.width = inputCurrentStyle.width;
222                inputEl.insertAdjacentElement('beforebegin', wrapper);
222// Place wrapper before input search field
223
224                // Set parent element's (parent of inputEl) display stack order higher 
225                // To handle overlapped submit button on mic icon
226                var parentEl = inputEl.parentNode.nodeName;
227
228                if (typeof (parentEl) != 'undefined' && parentEl !== null && parentEl.length != 0) {
229                    parentEl = parentEl.toLowerCase();
230
231                    if (parentEl != 'form') {
232                        inputEl.parentNode.style.zIndex = 1;
233                    }
234                }
235
236                // Append search input field element inside a wrapper band
237                wrapper.appendChild(inputEl);
238
239                // Place mic button/icon exact before search input field element
240                inputEl.insertAdjacentElement('beforebegin', micBtn);
241                inputEl.setAttribute('style', speechInputWrapperStyle + 'width: 100% !important;');
242                inputEl.classList.add('uvs-mic-band');
243
244                // Reset form style again
245                speechInputWrapper.setAttribute('style', speechInputWrapperStyle);
246
247                // Setup recognition
248                var finalTranscript = '';
249                var final_transcript = "";
250                var ignore_onend;
251
252                if ('webkitSpeechRecognition' in window && uvsClientInfo['chrome'] === true) {
253                    var recognition = new webkitSpeechRecognition();
254                    recognition.continuous = true;
255                    recognition.interimResults = true;
256
257                    recognition.onstart = function () {
258                        recognizing = true;
259                    };
260
261                    recognition.onerror = function (event) {
262                        micBtn.classList.remove('listening');
263                        recognizing = false;
264
265                        if (event.error == 'no-speech') {
266                            inputEl.placeholder = uvsMessages['unableToHear'];
267
268                            // Play 'notAudible' playback
269                            uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
270                            uvsAudioPlayer.play();
271
272                            ignore_onend = true;
273                        }
274                        if (event.error == 'audio-capture') {
275                            uvsAudioPlayer.configure(uvsAlternativeResponse['micConnect']);
276                            uvsAudioPlayer.play();
277
278                            inputEl.placeholder = uvsMessages['micNotAccessible'];
279                            ignore_onend = true;
280                        }
281                        if (event.error == 'not-allowed') {
282                            uvsAudioPlayer.configure(uvsAlternativeResponse['micConnect']);
283                            uvsAudioPlayer.play();
284
285                            inputEl.placeholder = uvsMessages['browserDenyMicAccess'];
286                            micBtn.style.setProperty("color", "white");
287                            ignore_onend = true;
288                        }
289                    };
290
291                    function processEnd() {
292                        recognizing = false;
293
294                        if (ignore_onend) { return; }
295
296                        finalTranscript = final_transcript;
297                        micBtn.classList.remove('listening');
298                        micBtn.style.setProperty("color", "white");
299
300                        if (typeof (finalTranscript) != 'undefined' && finalTranscript.length != 0) {
301                            inputEl.value = final_transcript;
302
303                            // Play 'basic' playback
304                            uvsAudioPlayer.configure(uvsAlternativeResponse['basic'], function () { speechInputWrapper.submit(); });
305                            uvsAudioPlayer.play();
306                        } else {
307                            inputEl.placeholder = uvsMessages['ask'];
308                        }
309                    };
310
311                    recognition.onend = function () {
312                        if (isAndroid) {
313                            processEnd();
314                        }
315                    };
316
317                    recognition.onresult = function (event) {
318                        let interim_transcript = '';
319
320                        if (typeof (event.results) == 'undefined') {
321                            recognition.onend = null;
322                            recognition.stop();
323                            inputEl.placeholder = uvsMessages['unableToHear'];
324
325                            // Play 'micConnect' playback
326                            uvsAudioPlayer.configure(uvsAlternativeResponse['micConnect']);
327                            uvsAudioPlayer.play();
328
329                            return;
330                        }
331
332                        for (var i = event.resultIndex; i < event.results.length; ++i) {
333                            if (event.results[i].isFinal) {
334                                final_transcript = event.results[i][0].transcript;
335
336                                if (isAndroid == false) {
337                                    processEnd();
338                                    recognition.stop();
339                                }
340                            } else {
341                                interim_transcript += event.results[i][0].transcript;
342                                inputEl.value = interim_transcript;
343                            }
344                        }
345                    };
346
347                    micBtn.addEventListener(uvsMicEventToListen, function (event) {
348                        // micBtn.onclick = function (event) {
349                        if (uvsAnyOtherMicListening(micBtn.getAttribute('id')) === true) return;
350
351                        if (recognizing) {
352                            // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
353                            uvsClearMicResetTimeout();
354
355                            // Stop ongoing playback if nay
356                            if (uvsAudioPlayer.isPlaying()) {
357                                uvsAudioPlayer.stop();
358                            }
359
360                            if (isAndroid == false) {
361                                processEnd();
362                                recognition.stop();
363                            }
364                        } else {
365                            micBtn.classList.add('listening');
366                            event.preventDefault();
367
368                            // Stop ongoing playback if nay
369                            if (uvsAudioPlayer.isPlaying()) {
370                                uvsAudioPlayer.stop();
371                            }
372
373                            inputEl.value = finalTranscript = '';
374                            recognizing = true;
375                            recognition.lang = !!uvsSttLanguageContext['gcp']['stt'] ? uvsSttLanguageContext['gcp']['langCode'] : 'en-US';;
376                            recognition.start();
377                            ignore_onend = false;
378
379                            // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
380                            uvsClearMicResetTimeout();
381
382                            // To set new mic reset timeout. (Based on duration from settings)
383                            window.uvsMicTimeoutIdentifier = setTimeout(function () {
384                                let updatedClassList = micBtn.classList;
385
386                                if (updatedClassList && updatedClassList.contains('listening')) {
387                                    micBtn.click();
388                                }
389                            }, uvsMicListenAutoTimeoutDuration);
390                        }
391                    });
392                } else {
393                    //CODE FOR BROWSERS THAT DO NOT SUPPORT STT NATIVLY
394                    // MUST USE THE BUILT IN MICROPHONE
395                    micBtn.addEventListener(uvsMicEventToListen, function (event) {
396                        /**
397                         * Audio element's play method must be invoked in exact influence of user gesture to avoid auto play restriction
398                         * 
399                         */
400                        if (
401                            uvsClientInfo.ios === true
402                            || (uvsClientInfo.iosSafari && !uvsClientInfo.chrome && !uvsClientInfo.firefox && !uvsClientInfo.edge)
403                            || (uvsClientInfo.windows && uvsClientInfo.firefox)
404                        ) {
405                            uvsAudioPlayer.configure(uvsSilenceSoundPath);
406                            uvsAudioPlayer.play();
407                        }
408
409                        if (uvsAnyOtherMicListening(micBtn.getAttribute('id')) === true) return;
410
411                        // Deny recording if microphone is not accessible
412                        if (!uvsAudioRecorder || !uvsAudioContext) {
413                            uvsInitAudio(function (a) {
414                                if (!uvsAudioRecorder || !uvsAudioContext) {
415                                    alert(uvsMessages['cantAccessMicrophone']);
416                                    return false;
417                                } else {
418                                    listenEvent();
419                                }
420                            });
421                        } else {
422                            listenEvent();
423                        }
424
425                        function listenEvent() {
426                            // If API system key is unavailable then acknowledge service unavailability and stop voice navigation.
427                            if (!(typeof (vs.uvsXApiKey) != 'undefined' && vs.uvsXApiKey !== null)) {
428                                // Play 'unavailable' playback
429                                uvsAudioPlayer.configure(uvsAlternativeResponse['unavailable']);
430                                uvsAudioPlayer.play();
431
432                                return false;
433                            }
434
435                            // User ending recording by clicking back mic
436                            if (recognizing) {
437                                // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
438                                uvsClearMicResetTimeout();
439
440                                // Stop recorder
441                                uvsAudioRecorder.stop();
442
443                                // Stop access to audio resource
444                                uvsStopAudio();
445
446                                // Stop ongoing playback if nay
447                                if (uvsAudioPlayer.isPlaying()) {
448                                    uvsAudioPlayer.stop();
449                                }
450
451                                //replace recording with mic icon
452                                micBtn.classList.remove('listening');
453
454                                micBtn.style.setProperty("color", "white");
455                                inputEl.placeholder = uvsMessages['transcribeText'];
456
457                                uvsAudioRecorder.getBuffers(function (buffers) {
458                                    if (!!uvsSttLanguageContext['gcp']['stt']) {
459                                        uvsAudioRecorder.exportMonoWAV(function (blob) {
460                                            uvsAudioRecorder.convertBlobToBase64(blob).then(function (resultedBase64) {
461                                                uvsGcpStt(resultedBase64).then(function (transcriptResult) {
462                                                    inputEl.value = transcriptResult;
463
464                                                    // Play 'basic' playback
465                                                    uvsAudioPlayer.configure(uvsAlternativeResponse['basic'], function () {
466                                                        speechInputWrapper.submit();
467                                                    });
468                                                    uvsAudioPlayer.play();
469                                                }).catch(function (error) {
470                                                    // Play 'notAudible' playback
471                                                    uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
472                                                    uvsAudioPlayer.play();
473
474                                                    inputEl.placeholder = uvsMessages['ask'];
475                                                })
476                                            }).catch(function (error) {
477                                                // Play 'notAudible' playback
478                                                uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
479                                                uvsAudioPlayer.play();
480
481                                                inputEl.placeholder = uvsMessages['ask'];
482                                            });
483                                        });
484                                    } else {
485                                        // Play 'notAudible' playback
486                                        uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
487                                        uvsAudioPlayer.play();
488
489                                        inputEl.placeholder = uvsMessages['ask'];
490                                    }
491                                });
492
493                                recognizing = false;
494                                return;
495
496                            } else {// User started recording by clicking mic
497                                micBtn.classList.add('listening');
498                                event.preventDefault();
499
500                                // Stop ongoing playback if nay
501                                if (uvsAudioPlayer.isPlaying()) {
502                                    uvsAudioPlayer.stop();
503                                }
504
505                                inputEl.value = finalTranscript = '';
506
507                                recognizing = true;
508                                uvsAudioRecorder.clear();
509                                uvsAudioRecorder.record(micBtn);
510
511                                // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
512                                uvsClearMicResetTimeout();
513
514                                // To set new mic reset timeout. (Based on duration from settings)
515                                window.uvsMicTimeoutIdentifier = setTimeout(function () {
516                                    let updatedClassList = micBtn.classList;
517
518                                    if (updatedClassList && updatedClassList.contains('listening')) {
519                                        micBtn.click();
520                                    }
521                                }, uvsMicListenAutoTimeoutDuration);
522                            }
523                        }
524                    }, false);
525                }
526            } catch (err) {  /* do nothing */ }
527        });
528
529        // Load floating mic with search bar
530        //############################# Floating mic - Widget ###################################
531        let uvsDocFragment = document.createDocumentFragment();
532        // Create root/widget wrapper
533        let uvsWidgetWrapper = document.createElement('div');
534
535        let uvsWrapperMicPositionClass = 'uvs-widget-wrapper-middle-right';
536        let uvsChatWrapperMicPositionClass = 'uvs-widget-chat-wrapper-middle-right';
537        let uvsMicPosition = vs.uvsSelectedMicPosition ? vs.uvsSelectedMicPosition.toLowerCase() : 'middle right';
538
539        switch (uvsMicPosition) {
540            case 'middle left':
541                uvsWrapperMicPositionClass = 'uvs-widget-wrapper-middle-left';
542                uvsChatWrapperMicPositionClass = 'uvs-widget-chat-wrapper-middle-left';
543                break;
544            case 'top right':
545                uvsWrapperMicPositionClass = 'uvs-widget-wrapper-top-right';
546                uvsChatWrapperMicPositionClass = 'uvs-widget-chat-wrapper-top-right';
547                break;
548            case 'top left':
549                uvsWrapperMicPositionClass = 'uvs-widget-wrapper-top-left';
550                uvsChatWrapperMicPositionClass = 'uvs-widget-chat-wrapper-top-left';
551                break;
552            case 'bottom right':
553                uvsWrapperMicPositionClass = 'uvs-widget-wrapper-bottom-right';
554                uvsChatWrapperMicPositionClass = 'uvs-widget-chat-wrapper-bottom-right';
555                break;
556            case 'bottom left':
557                uvsWrapperMicPositionClass = 'uvs-widget-wrapper-bottom-left';
558                uvsChatWrapperMicPositionClass = 'uvs-widget-chat-wrapper-bottom-left';
559                break;
560            default:
561                uvsWrapperMicPositionClass = 'uvs-widget-wrapper-middle-right';
562                uvsChatWrapperMicPositionClass = 'uvs-widget-chat-wrapper-middle-right';
563        }
564
565        uvsWidgetWrapper.setAttribute('class', 'uvs-widget-wrapper ' + uvsWrapperMicPositionClass + '');
566
567        // Create chat wrapper
568        let uvsWidgetChatWrapper = document.createElement('div');
569        uvsWidgetChatWrapper.setAttribute('class', 'uvs-widget-chat-wrapper ' + uvsChatWrapperMicPositionClass + '');
570
571        // ############################ Widget Fields (Input section) ############################
572        // Create widget text field and mic (Input Section)
573        let uvsWidgetField = document.createElement('div');
574        uvsWidgetField.setAttribute('class', 'uvs-widget-field');
575
576        // Create mic icon wrapper
577        let uvsWidgetMic = document.createElement('a');
578        uvsWidgetMic.setAttribute('id', 'uvsWidgetMic');
579        uvsWidgetMic.setAttribute('class', 'uvs-widget-button');
580
581        // Create and append mic icon/image to mic wrapper
582        let uvsWidgetMicImg = document.createElement('img');
583        uvsWidgetMicImg.setAttribute('src', vs.uvsImagesPath + 'uvs-widget-mic-black.svg');
584        uvsWidgetMic.appendChild(uvsWidgetMicImg);
585
586        // Create button wrapper next to input text field
587        let uvsWidgetSearchBtn = document.createElement('a');
588        uvsWidgetSearchBtn.setAttribute('id', 'uvsWidgetSearchBtn');
589
590        // Create and append search button to button wrapper
591        let uvsWidgetSearchBtnEl = document.createElement('button');
592        uvsWidgetSearchBtnEl.setAttribute('class', 'uvs-widget-form-submit-btn');
593        uvsWidgetSearchBtnEl.setAttribute('type', 'submit');
594        uvsWidgetSearchBtnEl.setAttribute('alt', 'Go');
595        uvsWidgetSearchBtnEl.setAttribute('title', 'Search');
596        uvsWidgetSearchBtn.appendChild(uvsWidgetSearchBtnEl);
597
598        // Create form for widget
599        let uvsWidgetForm = document.createElement('form');
600        uvsWidgetForm.setAttribute("class", "uvs-widget-form");
601
602        if (formElementForWidget !== null) {
603            uvsWidgetForm.action = formElementForWidget.action;
604            uvsWidgetForm.method = formElementForWidget.method;
605        } else {
606            uvsWidgetForm.action = uvsGetCurrentHostURL() + '/';
607            uvsWidgetForm.method = "get";
608        }
609
610        // Create input text field 
611        let uvsWidgetSearch = document.createElement('input');
612        uvsWidgetSearch.setAttribute('id', 'uvsWidgetSearch');
613        uvsWidgetSearch.setAttribute('class', 'uvs-widget-search uvs-widget-search-text');
614        uvsWidgetSearch.setAttribute('name', 'uvs-widget-search');
615        uvsWidgetSearch.setAttribute('placeholder', uvsWidgetMessages['placeholder']);
616        uvsWidgetSearch.setAttribute('name', 's');
617
618        uvsWidgetForm.appendChild(uvsWidgetSearch);
619        uvsWidgetForm.appendChild(uvsWidgetSearchBtn);
620
621        // Append mic and form to widget field section (input section)
622        uvsWidgetField.appendChild(uvsWidgetMic);
623        uvsWidgetField.appendChild(uvsWidgetForm);
624
625        // Append chat header, chat conversation and input fields to widget chat wrapper
626        uvsWidgetChatWrapper.appendChild(uvsWidgetField);
627
628        // ################################ Widget Toggle button #########################
629        // Create a widget toggle button wrapper
630        let uvsWidgetToggleButton = document.createElement('a');
631
632        // Create toggle button icon element
633        let uvsWidgetIcon = document.createElement('div');
634
635        // Create a pulse effect it's show when user trigger stt
636        let uvsWidgetPulseEffect = document.createElement('span');
637        uvsWidgetPulseEffect.setAttribute('id', 'uvsWidgetPulseEffect');
638
639        if (vs.uvsFloatingMic && vs.uvsFloatingMic === 'yes') {
640            uvsWidgetToggleButton.setAttribute('id', 'uvsWidgetToggleButton');
641            uvsWidgetToggleButton.setAttribute('class', 'uvs-widget-button');
642            uvsWidgetIcon.setAttribute('class', 'uvs-widget-icon uvs-widget-toggle-button uvs-toggle-btn-mic');
643            // Append toggle button icon to toggle button wrapper
644            uvsWidgetToggleButton.appendChild(uvsWidgetIcon);
645        }
646
647        // Append chat wrapper and toggle button to widget wrapper
648        uvsWidgetWrapper.appendChild(uvsWidgetChatWrapper);
649        uvsWidgetWrapper.appendChild(uvsWidgetPulseEffect);
650        uvsWidgetWrapper.appendChild(uvsWidgetToggleButton);
651
652        // Append widget to body
653        uvsDocFragment.appendChild(uvsWidgetWrapper);
654        document.body.appendChild(uvsDocFragment);
655
656        // Listen event to show/hide widget
657        uvsWidgetToggleButton.addEventListener('click', function (event) {
658            uvsToggleWidgetElements();
659        });
660
661        /*############################# Widget mic handling ################################*/
662        // Setup recognition
663        let widgetFinalTranscript = '';
664        let widgetRecognizing = false;
665        let widget_final_transcript = "";
666        let widget_ignore_onend;
667
668        /**
669         * Function for add pulse animation in elementor mic
670         *
671         */
672        function uvsElementorMicPulseAnimation(uvsElementorMicElement) {
673            let size = 0, left = 0;
674            if (uvsElementorMicElement.clientHeight >= 80) {
675                size = uvsElementorMicElement.clientHeight + 15;
676                left = -(size / 6);
677            } if (uvsElementorMicElement.clientHeight >= 60) {
678                size = uvsElementorMicElement.clientHeight + 12;
679                left = -(size / 5);
680            } else if (uvsElementorMicElement.clientHeight >= 30) {
681                size = uvsElementorMicElement.clientHeight + 10;
682                left = -(size / 4);
683            } else {
684                size = uvsElementorMicElement.clientHeight + 8;
685                left = -(size / 3.5);
686            }
687
688
689            const uvsPulse = document.createElement('div');
690            uvsPulse.setAttribute('id', 'pulse');
691            uvsPulse.setAttribute('class', 'pulse-color');
692            uvsPulse.style.width = size + 'px';
693            uvsPulse.style.height = size + 'px';
694            uvsPulse.style.left = left + 'px';
695
696            const uvsPulseRate = document.createElement('div');
697            uvsPulseRate.setAttribute('id', 'pulse-rate');
698            uvsPulseRate.setAttribute('class', 'pulse-color');
699            uvsPulseRate.style.width = size + 'px';
700            uvsPulseRate.style.height = size + 'px';
701            uvsPulseRate.style.left = left + 'px';
702
703            return { uvsPulse, uvsPulseRate };
704        }
705
706        function enableElementor() {
707            const uvsFloatingMic = document.getElementById('flt-mic')
708            if (uvsFloatingMic != null) {
709                const uvsElementorMicColor = uvsFloatingMic.getElementsByClassName('my-icon-wrapper')[0].getElementsByTagName('i')[0];
710                const uvsPulseItem = uvsElementorMicPulseAnimation(uvsElementorMicColor);
711                if ('webkitSpeechRecognition' in window && uvsClientInfo['chrome'] === true) {
712                    let widgetRecognition = new webkitSpeechRecognition();
713                    widgetRecognition.continuous = true;
714                    widgetRecognition.interimResults = true;
715
716                    widgetRecognition.onstart = function () {
717                        widgetRecognizing = true;
718                    };
719
720                    widgetRecognition.onerror = function (event) {
721                        uvsFloatingMic.classList.remove('listening');
722                        widgetRecognizing = false;
723                        uvsElementorMicColor.classList.remove('my-icon-animation-wrapper');
724                        uvsElementorMicColor.removeChild(uvsPulseItem['uvsPulse']);
725                        uvsElementorMicColor.removeChild(uvsPulseItem['uvsPulseRate']);
726
727                        if (event.error == 'no-speech') {
728                            // Play feature unavailable playback
729                            uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
730                            uvsAudioPlayer.play();
731
732                            widget_ignore_onend = true;
733                            uvsWidgetSearch.placeholder = uvsMessages['unableToHear'];
734                        }
735
736                        if (event.error == 'audio-capture') {
737                            uvsAudioPlayer.configure(uvsAlternativeResponse['micConnect']);
738                            uvsAudioPlayer.play();
739
740                            widget_ignore_onend = true;
741                            uvsWidgetSearch.placeholder = uvsMessages['micNotAccessible'];
742                        }
743
744                        if (event.error == 'not-allowed') {
745                            uvsAudioPlayer.configure(uvsAlternativeResponse['micConnect']);
746                            uvsAudioPlayer.play();
747
748                            widget_ignore_onend = true;
749                            uvsWidgetSearch.placeholder = uvsMessages['browserDenyMicAccess'];
750                        }
751                    };
752
753                    function widgetProcessEnd() {
754                        widgetRecognizing = false;
755
756                        if (widget_ignore_onend) { return; }
757
758                        widgetFinalTranscript = widget_final_transcript;
759                        uvsFloatingMic.classList.remove('listening');
760                        uvsElementorMicColor.classList.remove('my-icon-animation-wrapper');
761                        uvsElementorMicColor.removeChild(uvsPulseItem['uvsPulse']);
762                        uvsElementorMicColor.removeChild(uvsPulseItem['uvsPulseRate']);
763
764                        if (typeof (widgetFinalTranscript) != 'undefined' && widgetFinalTranscript.length != 0) {
765                            uvsWidgetSearch.value = widgetFinalTranscript;
766
767                            // Play 'basic' playback
768                            uvsAudioPlayer.configure(uvsAlternativeResponse['basic'], function () {
769                            });
770                            uvsAudioPlayer.play();
771                            setTimeout(() => {
772                                uvsWidgetForm.submit();
773                            }, 2000);
774                        } else {
775                            // Play 'notAudible' playback
776                            uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
777                            uvsAudioPlayer.play();
778
779                            uvsWidgetSearch.placeholder = uvsMessages['ask'];
780                        }
781
782                    }
783
784                    widgetRecognition.onend = function () {
785                        if (isAndroid) { widgetProcessEnd(); }
786                    };
787
788                    widgetRecognition.onresult = function (event) {
789                        let interim_transcript = '';
790
791                        if (typeof (event.results) == 'undefined') {
792                            widgetRecognition.onend = null;
793                            widgetRecognition.stop();
794                            uvsWidgetSearch.placeholder = uvsMessages['unableToHear'];
795
796                            // Play 'micConnect' playback
797                            uvsAudioPlayer.configure(uvsAlternativeResponse['micConnect']);
798                            uvsAudioPlayer.play();
799
800                            return;
801                        }
802
803                        let eventResultsLength = event.results.length;
804
805                        for (let i = event.resultIndex; i < eventResultsLength; ++i) {
806                            if (event.results[i].isFinal) {
807                                widget_final_transcript = event.results[i][0].transcript;
808
809                                if (isAndroid == false) {
810                                    widgetProcessEnd();
811                                    widgetRecognition.stop();
812                                }
813                            } else {
814                                interim_transcript += event.results[i][0].transcript;
815                            }
816                        }
817                    };
818
819                    uvsFloatingMic.addEventListener(uvsMicEventToListen, function (event) {
820                        if (uvsAnyOtherMicListening(uvsFloatingMic.getAttribute('id'), uvsFloatingMic) === true) return;
821
822                        if (widgetRecognizing) {
823                            // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
824                            uvsClearMicResetTimeout();
825
826                            // Stop ongoing playback if nay
827                            if (uvsAudioPlayer.isPlaying()) {
828                                uvsAudioPlayer.stop();
829                            }
830
831                            if (isAndroid == false) {
832                                widgetProcessEnd();
833                                widgetRecognition.stop();
834                            }
835                        } else {
836                            uvsFloatingMic.classList.add('listening');
837                            uvsElementorMicColor.classList.add('my-icon-animation-wrapper');
838                            uvsElementorMicColor.appendChild(uvsPulseItem['uvsPulse']);
839                            uvsElementorMicColor.appendChild(uvsPulseItem['uvsPulseRate']);
840
841                            event.preventDefault();
842
843                            // Stop ongoing playback if nay
844                            if (uvsAudioPlayer.isPlaying()) {
845                                uvsAudioPlayer.stop();
846                            }
847
848                            widgetFinalTranscript = '';
849                            widgetRecognizing = true;
850                            widgetRecognition.lang = !!uvsSttLanguageContext['gcp']['stt'] ? uvsSttLanguageContext['gcp']['langCode'] : 'en-US';
851                            widgetRecognition.start();
852                            widget_ignore_onend = false;
853
854                            // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
855                            uvsClearMicResetTimeout();
856
857                            // To set new mic reset timeout. (Based on duration from settings)
858                            window.uvsMicTimeoutIdentifier = setTimeout(function () {
859                                let updatedClassList = uvsFloatingMic.classList;
860
861                                if (updatedClassList && updatedClassList.contains('listening')) {
862                                    uvsFloatingMic.click();
863                                }
864                            }, uvsMicListenAutoTimeoutDuration);
865                        }
866                    });
867                } else {
868                    //CODE FOR BROWSERS THAT DO NOT SUPPORT STT NATIVLY
869                    // MUST USE THE BUILT IN MICROPHONE
870                    uvsFloatingMic.addEventListener(uvsMicEventToListen, function (event) {
871
872                        /**
873                         * Audio element's play method must be invoked in exact influence of user gesture to avoid auto play restriction
874                         * 
875                         */
876                        if (
877                            uvsClientInfo.ios === true
878                            || (uvsClientInfo.iosSafari && !uvsClientInfo.chrome && !uvsClientInfo.firefox && !uvsClientInfo.edge)
879                            || (uvsClientInfo.windows && uvsClientInfo.firefox)
880                        ) {
881                            uvsAudioPlayer.configure(uvsSilenceSoundPath);
882                            uvsAudioPlayer.play();
883                        }
884
885                        if (uvsAnyOtherMicListening(uvsFloatingMic.getAttribute('id'), uvsFloatingMic) === true) return;
886
887                        // Deny recording if microphone is not accessible
888                        if (!uvsAudioRecorder || !uvsAudioContext) {
889                            uvsInitAudio(function (a) {
890                                if (!uvsAudioRecorder || !uvsAudioContext) {
891                                    uvsWidgetSearch.placeholder = uvsMessages['micNotAccessible'];
892                                    return false;
893                                } else {
894                                    widgetListenEvent();
895                                }
896                            });
897                        } else {
898                            widgetListenEvent();
899                        }
900
901                        function widgetListenEvent() {
902                            // If API system key is unavailable then acknowledge service unavailability and stop voice navigation.
903                            if (!(typeof (vs.uvsXApiKey) != 'undefined' && vs.uvsXApiKey !== null)) {
904                                // Play 'unavailable' playback
905                                uvsAudioPlayer.configure(uvsAlternativeResponse['unavailable']);
906                                uvsAudioPlayer.play();
907
908                                return false;
909                            }
910
911                            // User ending recording by clicking back mic
912                            if (widgetRecognizing) {
913                                // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
914                                uvsClearMicResetTimeout();
915
916                                // Stop recorder
917                                uvsAudioRecorder.stop();
918
919                                // Stop access to audio resource
920                                uvsStopAudio();
921
922                                // Stop ongoing playback if nay
923                                if (uvsAudioPlayer.isPlaying()) {
924                                    uvsAudioPlayer.stop();
925                                }
926
927                                //replace recording with mic icon
928                                uvsFloatingMic.classList.remove('listening');
929                                uvsElementorMicColor.classList.remove('my-icon-animation-wrapper');
930                                uvsElementorMicColor.removeChild(uvsPulseItem['uvsPulse']);
931                                uvsElementorMicColor.removeChild(uvsPulseItem['uvsPulseRate']);
932
933                                uvsWidgetSearch.placeholder = uvsMessages['transcribeText'];
934
935                                uvsAudioRecorder.getBuffers(function (buffers) {
936                                    if (!!uvsSttLanguageContext['gcp']['stt']) {
937                                        uvsAudioRecorder.exportMonoWAV(function (blob) {
938                                            uvsAudioRecorder.convertBlobToBase64(blob).then(function (resultedBase64) {
939                                                uvsGcpStt(resultedBase64).then(function (transcriptResult) {
940                                                    uvsWidgetSearch.value = transcriptResult;
941
942                                                    // Play 'basic' playback
943                                                    uvsAudioPlayer.configure(uvsAlternativeResponse['basic'], function () {
944                                                    });
945                                                    uvsAudioPlayer.play();
946                                                    setTimeout(() => {
947                                                        uvsWidgetForm.submit();
948                                                    }, 2000);
949                                                }).catch(function (error) {
950                                                    // Play 'notAudible' playback
951                                                    uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
952                                                    uvsAudioPlayer.play();
953
954                                                    uvsWidgetSearch.placeholder = uvsMessages['ask'];
955                                                })
956                                            }).catch(function (error) {
957                                                // Play 'notAudible' playback
958                                                uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
959                                                uvsAudioPlayer.play();
960
961                                                uvsWidgetSearch.placeholder = uvsMessages['ask'];
962                                            });
963                                        });
964                                    } else {
965                                        // Play 'notAudible' playback
966                                        uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
967                                        uvsAudioPlayer.play();
968
969                                        uvsWidgetSearch.placeholder = uvsMessages['ask'];
970                                    }
971                                });
972
973                                widgetRecognizing = false;
974                                return;
975                            } else {// User started recording by clicking mic
976                                uvsFloatingMic.classList.add('listening');
977                                uvsElementorMicColor.classList.add('my-icon-animation-wrapper');
978                                uvsElementorMicColor.appendChild(uvsPulseItem['uvsPulse']);
979                                uvsElementorMicColor.appendChild(uvsPulseItem['uvsPulseRate']);
980
981                                event.preventDefault();
982
983                                // Stop ongoing playback if nay
984                                if (uvsAudioPlayer.isPlaying()) {
985                                    uvsAudioPlayer.stop();
986                                }
987
988                                widgetFinalTranscript = '';
989
990                                widgetRecognizing = true;
991                                uvsAudioRecorder.clear();
992                                uvsAudioRecorder.record(uvsFloatingMic);
993
994                                // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
995                                uvsClearMicResetTimeout();
996
997                                // To set new mic reset timeout. (Based on duration from settings)
998                                window.uvsMicTimeoutIdentifier = setTimeout(function () {
999                                    let updatedClassList = uvsFloatingMic.classList;
1000
1001                                    if (updatedClassList && updatedClassList.contains('listening')) {
1002                                        uvsFloatingMic.click();
1003                                    }
1004                                }, uvsMicListenAutoTimeoutDuration);
1005                            }
1006                        }
1007                    }, false);
1008                }
1009            }
1010        }
1011
1012        /**
1013         * Function for provide simplicity to interct with floating mic using keyboard key between a-z
1014         * 
1015         * @param clickType: single or double
1016         */
1017        function uvsFloatingMicKeyBoardAccess(clickType) {
1018            if (vs.uvsFloatingMic && vs.uvsFloatingMic === 'yes') {
1019                var keyFormSetting = vs.uvsKeyboardSpecialKey == 'OtherKey' ? vs.uvsKeyboardMicSwitch : vs.uvsKeyboardSpecialKey == 'Space' ? ' ' : vs.uvsKeyboardSpecialKey;
1020                var spaceCount = 0;
1021                window.addEventListener('keydown', (event) => {
1022                    let target = event.target;
1023
1024                    // Check if the event originated from an input field
1025                    if (target.tagName === 'INPUT') {
1026                        // Ignore keyboard events on input fields
1027                        return;
1028                    }
1029
1030                    if (event.key == keyFormSetting) {
1031                        spaceCount++;
1032                        event.preventDefault();
1033                        if (spaceCount == 2) {
1034                            if (clickType == 'single') {
1035                                uvsWidgetToggleButton.click();
1036                            } else if (clickType == 'double') {
1037                                if (uvsWidgetChatWrapper.classList.contains('uvs-widget-visible')) {
1038                                    uvsWidgetMic.click();
1039                                } else {
1040                                    uvsWidgetToggleButton.click();
1041                                    uvsWidgetMic.click();
1042                                }
1043                            }
1044                            spaceCount = 0;
1045                        }
1046                    }
1047                });
1048            }
1049        }
1050
1051        /**
1052         * Function for made a indication on single click
1053         * 
1054         * @param action: add for add indication or remove for remove indication
1055         */
1056        function uvsSingleClickMicEffect(action) {
1057            if (action == 'add') {
1058                uvsWidgetToggleButton.classList.add('listening');
1059                uvsWidgetToggleButton.classList.add('singleClick');
1060                uvsWidgetPulseEffect.classList.add('singleClick');
1061            } else if (action == 'remove') {
1062                uvsWidgetToggleButton.classList.remove('listening');
1063                uvsWidgetToggleButton.classList.remove('singleClick');
1064                uvsWidgetPulseEffect.classList.remove('singleClick');
1065            }
1066        }
1067
1068        function enableSingleClick() {
1069            uvsWidgetWrapper.classList.remove('uvsWidgetChatWrapper');
1070            if ('webkitSpeechRecognition' in window && uvsClientInfo['chrome'] === true) {
1071                let widgetRecognition = new webkitSpeechRecognition();
1072                widgetRecognition.continuous = true;
1073                widgetRecognition.interimResults = true;
1074
1075                widgetRecognition.onstart = function () {
1076                    widgetRecognizing = true;
1077                };
1078
1079                widgetRecognition.onerror = function (event) {
1080                    uvsSingleClickMicEffect('remove');
1081                    widgetRecognizing = false;
1082
1083                    if (event.error == 'no-speech') {
1084                        // Play feature unavailable playback
1085                        uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
1086                        uvsAudioPlayer.play();
1087
1088                        widget_ignore_onend = true;
1089                        uvsWidgetSearch.placeholder = uvsMessages['unableToHear'];
1090                    }
1091
1092                    if (event.error == 'audio-capture') {
1093                        uvsAudioPlayer.configure(uvsAlternativeResponse['micConnect']);
1094                        uvsAudioPlayer.play();
1095
1096                        widget_ignore_onend = true;
1097                        uvsWidgetSearch.placeholder = uvsMessages['micNotAccessible'];
1098                    }
1099
1100                    if (event.error == 'not-allowed') {
1101                        uvsAudioPlayer.configure(uvsAlternativeResponse['micConnect']);
1102                        uvsAudioPlayer.play();
1103
1104                        widget_ignore_onend = true;
1105                        uvsWidgetSearch.placeholder = uvsMessages['browserDenyMicAccess'];
1106                    }
1107                };
1108
1109                function widgetProcessEnd() {
1110                    widgetRecognizing = false;
1111
1112                    if (widget_ignore_onend) { return; }
1113
1114                    widgetFinalTranscript = widget_final_transcript;
1115                    uvsSingleClickMicEffect('remove');
1116
1117                    if (typeof (widgetFinalTranscript) != 'undefined' && widgetFinalTranscript.length != 0) {
1118                        uvsWidgetSearch.value = widgetFinalTranscript;
1119
1120                        // Play 'basic' playback
1121                        uvsAudioPlayer.configure(uvsAlternativeResponse['basic'], function () {
1122                        });
1123                        uvsAudioPlayer.play();
1124                        setTimeout(() => {
1125                            uvsWidgetForm.submit();
1126                        }, 2000);
1127                    } else {
1128                        // Play 'notAudible' playback
1129                        uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
1130                        uvsAudioPlayer.play();
1131
1132                        uvsWidgetSearch.placeholder = uvsMessages['ask'];
1133                    }
1134
1135                }
1136
1137                widgetRecognition.onend = function () {
1138                    if (isAndroid) { widgetProcessEnd(); }
1139                };
1140
1141                widgetRecognition.onresult = function (event) {
1142                    let interim_transcript = '';
1143
1144                    if (typeof (event.results) == 'undefined') {
1145                        widgetRecognition.onend = null;
1146                        widgetRecognition.stop();
1147                        uvsWidgetSearch.placeholder = uvsMessages['unableToHear'];
1148
1149                        // Play 'micConnect' playback
1150                        uvsAudioPlayer.configure(uvsAlternativeResponse['micConnect']);
1151                        uvsAudioPlayer.play();
1152
1153                        return;
1154                    }
1155
1156                    let eventResultsLength = event.results.length;
1157
1158                    for (let i = event.resultIndex; i < eventResultsLength; ++i) {
1159                        if (event.results[i].isFinal) {
1160                            widget_final_transcript = event.results[i][0].transcript;
1161
1162                            if (isAndroid == false) {
1163                                widgetProcessEnd();
1164                                widgetRecognition.stop();
1165                            }
1166                        } else {
1167                            interim_transcript += event.results[i][0].transcript;
1168                        }
1169                    }
1170                };
1171
1172                uvsWidgetToggleButton.addEventListener(uvsMicEventToListen, function (event) {
1173                    if (uvsAnyOtherMicListening(uvsWidgetMic.getAttribute('id'), uvsWidgetMic) === true) return;
1174
1175                    if (widgetRecognizing) {
1176                        // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
1177                        uvsClearMicResetTimeout();
1178
1179                        // Stop ongoing playback if nay
1180                        if (uvsAudioPlayer.isPlaying()) {
1181                            uvsAudioPlayer.stop();
1182                        }
1183
1184                        if (isAndroid == false) {
1185                            widgetProcessEnd();
1186                            widgetRecognition.stop();
1187                        }
1188                    } else {
1189                        uvsSingleClickMicEffect('add');
1190                        event.preventDefault();
1191
1192                        // Stop ongoing playback if nay
1193                        if (uvsAudioPlayer.isPlaying()) {
1194                            uvsAudioPlayer.stop();
1195                        }
1196
1197                        widgetFinalTranscript = '';
1198                        widgetRecognizing = true;
1199                        widgetRecognition.lang = !!uvsSttLanguageContext['gcp']['stt'] ? uvsSttLanguageContext['gcp']['langCode'] : 'en-US';
1200                        widgetRecognition.start();
1201                        widget_ignore_onend = false;
1202
1203                        // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
1204                        uvsClearMicResetTimeout();
1205
1206                        // To set new mic reset timeout. (Based on duration from settings)
1207                        window.uvsMicTimeoutIdentifier = setTimeout(function () {
1208                            let updatedClassList = uvsWidgetToggleButton.classList;
1209
1210                            if (updatedClassList && updatedClassList.contains('listening')) {
1211                                uvsWidgetToggleButton.click();
1212                            }
1213                        }, uvsMicListenAutoTimeoutDuration);
1214                    }
1215                });
1216            } else {
1217                //CODE FOR BROWSERS THAT DO NOT SUPPORT STT NATIVLY
1218                // MUST USE THE BUILT IN MICROPHONE
1219                uvsWidgetToggleButton.addEventListener(uvsMicEventToListen, function (event) {
1220                    /**
1221                     * Audio element's play method must be invoked in exact influence of user gesture to avoid auto play restriction
1222                     * 
1223                     */
1224                    if (
1225                        uvsClientInfo.ios === true
1226                        || (uvsClientInfo.iosSafari && !uvsClientInfo.chrome && !uvsClientInfo.firefox && !uvsClientInfo.edge)
1227                        || (uvsClientInfo.windows && uvsClientInfo.firefox)
1228                    ) {
1229                        uvsAudioPlayer.configure(uvsSilenceSoundPath);
1230                        uvsAudioPlayer.play();
1231                    }
1232
1233                    if (uvsAnyOtherMicListening(uvsWidgetToggleButton.getAttribute('id'), uvsWidgetMic) === true) return;
1234
1235                    // Deny recording if microphone is not accessible
1236                    if (!uvsAudioRecorder || !uvsAudioContext) {
1237                        uvsInitAudio(function (a) {
1238                            if (!uvsAudioRecorder || !uvsAudioContext) {
1239                                uvsWidgetSearch.placeholder = uvsMessages['micNotAccessible'];
1240                                return false;
1241                            } else {
1242                                widgetListenEvent();
1243                            }
1244                        });
1245                    } else {
1246                        widgetListenEvent();
1247                    }
1248
1249                    function widgetListenEvent() {
1250                        // If API system key is unavailable then acknowledge service unavailability and stop voice navigation.
1251                        if (!(typeof (vs.uvsXApiKey) != 'undefined' && vs.uvsXApiKey !== null)) {
1252                            // Play 'unavailable' playback
1253                            uvsAudioPlayer.configure(uvsAlternativeResponse['unavailable']);
1254                            uvsAudioPlayer.play();
1255
1256                            return false;
1257                        }
1258
1259                        // User ending recording by clicking back mic
1260                        if (widgetRecognizing) {
1261                            // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
1262                            uvsClearMicResetTimeout();
1263
1264                            // Stop recorder
1265                            uvsAudioRecorder.stop();
1266
1267                            // Stop access to audio resource
1268                            uvsStopAudio();
1269
1270                            // Stop ongoing playback if nay
1271                            if (uvsAudioPlayer.isPlaying()) {
1272                                uvsAudioPlayer.stop();
1273                            }
1274
1275                            //replace recording with mic icon
1276                            uvsSingleClickMicEffect('remove');
1277
1278                            uvsWidgetSearch.placeholder = uvsMessages['transcribeText'];
1279
1280                            uvsAudioRecorder.getBuffers(function (buffers) {
1281                                if (!!uvsSttLanguageContext['gcp']['stt']) {
1282                                    uvsAudioRecorder.exportMonoWAV(function (blob) {
1283                                        uvsAudioRecorder.convertBlobToBase64(blob).then(function (resultedBase64) {
1284                                            uvsGcpStt(resultedBase64).then(function (transcriptResult) {
1285                                                uvsWidgetSearch.value = transcriptResult;
1286
1287                                                // Play 'basic' playback
1288                                                uvsAudioPlayer.configure(uvsAlternativeResponse['basic'], function () {
1289                                                });
1290                                                uvsAudioPlayer.play();
1291                                                setTimeout(() => {
1292                                                    uvsWidgetForm.submit();
1293                                                }, 2000);
1294                                            }).catch(function (error) {
1295                                                // Play 'notAudible' playback
1296                                                uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
1297                                                uvsAudioPlayer.play();
1298
1299                                                uvsWidgetSearch.placeholder = uvsMessages['ask'];
1300                                            })
1301                                        }).catch(function (error) {
1302                                            // Play 'notAudible' playback
1303                                            uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
1304                                            uvsAudioPlayer.play();
1305
1306                                            uvsWidgetSearch.placeholder = uvsMessages['ask'];
1307                                        });
1308                                    });
1309                                } else {
1310                                    // Play 'notAudible' playback
1311                                    uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
1312                                    uvsAudioPlayer.play();
1313
1314                                    uvsWidgetSearch.placeholder = uvsMessages['ask'];
1315                                }
1316                            });
1317
1318                            widgetRecognizing = false;
1319                            return;
1320                        } else {// User started recording by clicking mic
1321                            uvsSingleClickMicEffect('add');
1322                            event.preventDefault();
1323
1324                            // Stop ongoing playback if nay
1325                            if (uvsAudioPlayer.isPlaying()) {
1326                                uvsAudioPlayer.stop();
1327                            }
1328
1329                            widgetFinalTranscript = '';
1330
1331                            widgetRecognizing = true;
1332                            uvsAudioRecorder.clear();
1333                            uvsAudioRecorder.record(uvsWidgetToggleButton);
1334
1335                            // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
1336                            uvsClearMicResetTimeout();
1337
1338                            // To set new mic reset timeout. (Based on duration from settings)
1339                            window.uvsMicTimeoutIdentifier = setTimeout(function () {
1340                                let updatedClassList = uvsWidgetToggleButton.classList;
1341
1342                                if (updatedClassList && updatedClassList.contains('listening')) {
1343                                    uvsWidgetToggleButton.click();
1344                                }
1345                            }, uvsMicListenAutoTimeoutDuration);
1346                        }
1347                    }
1348                }, false);
1349            }
1350        }
1351
1352        function disableSingleClick() {
1353            if ('webkitSpeechRecognition' in window && uvsClientInfo['chrome'] === true) {
1354                let widgetRecognition = new webkitSpeechRecognition();
1355                widgetRecognition.continuous = true;
1356                widgetRecognition.interimResults = true;
1357
1358                widgetRecognition.onstart = function () {
1359                    widgetRecognizing = true;
1360                };
1361
1362                widgetRecognition.onerror = function (event) {
1363                    uvsWidgetMic.classList.remove('listening');
1364                    widgetRecognizing = false;
1365
1366                    if (event.error == 'no-speech') {
1367                        // Play feature unavailable playback
1368                        uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
1369                        uvsAudioPlayer.play();
1370
1371                        widget_ignore_onend = true;
1372                        uvsWidgetSearch.placeholder = uvsMessages['unableToHear'];
1373                    }
1374
1375                    if (event.error == 'audio-capture') {
1376                        uvsAudioPlayer.configure(uvsAlternativeResponse['micConnect']);
1377                        uvsAudioPlayer.play();
1378
1379                        widget_ignore_onend = true;
1380                        uvsWidgetSearch.placeholder = uvsMessages['micNotAccessible'];
1381                    }
1382
1383                    if (event.error == 'not-allowed') {
1384                        uvsAudioPlayer.configure(uvsAlternativeResponse['micConnect']);
1385                        uvsAudioPlayer.play();
1386
1387                        widget_ignore_onend = true;
1388                        uvsWidgetSearch.placeholder = uvsMessages['browserDenyMicAccess'];
1389                    }
1390                };
1391
1392                function widgetProcessEnd() {
1393                    widgetRecognizing = false;
1394
1395                    if (widget_ignore_onend) { return; }
1396
1397                    widgetFinalTranscript = widget_final_transcript;
1398                    uvsWidgetMic.classList.remove('listening');
1399
1400                    if (typeof (widgetFinalTranscript) != 'undefined' && widgetFinalTranscript.length != 0) {
1401                        uvsWidgetSearch.value = widgetFinalTranscript;
1402
1403                        // Play 'basic' playback
1404                        uvsAudioPlayer.configure(uvsAlternativeResponse['basic'], function () {
1405                        });
1406                        uvsAudioPlayer.play();
1407                        setTimeout(() => {
1408                            uvsWidgetForm.submit();
1409                        }, 2000);
1410                    } else {
1411                        // Play 'notAudible' playback
1412                        uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
1413                        uvsAudioPlayer.play();
1414
1415                        uvsWidgetSearch.placeholder = uvsMessages['ask'];
1416                    }
1417
1418                }
1419
1420                widgetRecognition.onend = function () {
1421                    if (isAndroid) { widgetProcessEnd(); }
1422                };
1423
1424                widgetRecognition.onresult = function (event) {
1425                    let interim_transcript = '';
1426
1427                    if (typeof (event.results) == 'undefined') {
1428                        widgetRecognition.onend = null;
1429                        widgetRecognition.stop();
1430                        uvsWidgetSearch.placeholder = uvsMessages['unableToHear'];
1431
1432                        // Play 'micConnect' playback
1433                        uvsAudioPlayer.configure(uvsAlternativeResponse['micConnect']);
1434                        uvsAudioPlayer.play();
1435
1436                        return;
1437                    }
1438
1439                    let eventResultsLength = event.results.length;
1440
1441                    for (let i = event.resultIndex; i < eventResultsLength; ++i) {
1442                        if (event.results[i].isFinal) {
1443                            widget_final_transcript = event.results[i][0].transcript;
1444
1445                            if (isAndroid == false) {
1446                                widgetProcessEnd();
1447                                widgetRecognition.stop();
1448                            }
1449                        } else {
1450                            interim_transcript += event.results[i][0].transcript;
1451                        }
1452                    }
1453                };
1454
1455                uvsWidgetMic.addEventListener(uvsMicEventToListen, function (event) {
1456                    if (uvsAnyOtherMicListening(uvsWidgetMic.getAttribute('id'), uvsWidgetMic) === true) return;
1457
1458                    if (widgetRecognizing) {
1459                        // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
1460                        uvsClearMicResetTimeout();
1461
1462                        // Stop ongoing playback if nay
1463                        if (uvsAudioPlayer.isPlaying()) {
1464                            uvsAudioPlayer.stop();
1465                        }
1466
1467                        if (isAndroid == false) {
1468                            widgetProcessEnd();
1469                            widgetRecognition.stop();
1470                        }
1471                    } else {
1472                        uvsWidgetMic.classList.add('listening');
1473                        event.preventDefault();
1474
1475                        // Stop ongoing playback if nay
1476                        if (uvsAudioPlayer.isPlaying()) {
1477                            uvsAudioPlayer.stop();
1478                        }
1479
1480                        widgetFinalTranscript = '';
1481                        widgetRecognizing = true;
1482                        widgetRecognition.lang = !!uvsSttLanguageContext['gcp']['stt'] ? uvsSttLanguageContext['gcp']['langCode'] : 'en-US';
1483                        widgetRecognition.start();
1484                        widget_ignore_onend = false;
1485
1486                        // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
1487                        uvsClearMicResetTimeout();
1488
1489                        // To set new mic reset timeout. (Based on duration from settings)
1490                        window.uvsMicTimeoutIdentifier = setTimeout(function () {
1491                            let updatedClassList = uvsWidgetMic.classList;
1492
1493                            if (updatedClassList && updatedClassList.contains('listening')) {
1494                                uvsWidgetMic.click();
1495                            }
1496                        }, uvsMicListenAutoTimeoutDuration);
1497                    }
1498                });
1499            } else {
1500                //CODE FOR BROWSERS THAT DO NOT SUPPORT STT NATIVLY
1501                // MUST USE THE BUILT IN MICROPHONE
1502                uvsWidgetMic.addEventListener(uvsMicEventToListen, function (event) {
1503                    /**
1504                     * Audio element's play method must be invoked in exact influence of user gesture to avoid auto play restriction
1505                     * 
1506                     */
1507                    if (
1508                        uvsClientInfo.ios === true
1509                        || (uvsClientInfo.iosSafari && !uvsClientInfo.chrome && !uvsClientInfo.firefox && !uvsClientInfo.edge)
1510                        || (uvsClientInfo.windows && uvsClientInfo.firefox)
1511                    ) {
1512                        uvsAudioPlayer.configure(uvsSilenceSoundPath);
1513                        uvsAudioPlayer.play();
1514                    }
1515
1516                    if (uvsAnyOtherMicListening(uvsWidgetMic.getAttribute('id'), uvsWidgetMic) === true) return;
1517
1518                    // Deny recording if microphone is not accessible
1519                    if (!uvsAudioRecorder || !uvsAudioContext) {
1520                        uvsInitAudio(function (a) {
1521                            if (!uvsAudioRecorder || !uvsAudioContext) {
1522                                uvsWidgetSearch.placeholder = uvsMessages['micNotAccessible'];
1523                                return false;
1524                            } else {
1525                                widgetListenEvent();
1526                            }
1527                        });
1528                    } else {
1529                        widgetListenEvent();
1530                    }
1531
1532                    function widgetListenEvent() {
1533                        // If API system key is unavailable then acknowledge service unavailability and stop voice navigation.
1534                        if (!(typeof (vs.uvsXApiKey) != 'undefined' && vs.uvsXApiKey !== null)) {
1535                            // Play 'unavailable' playback
1536                            uvsAudioPlayer.configure(uvsAlternativeResponse['unavailable']);
1537                            uvsAudioPlayer.play();
1538
1539                            return false;
1540                        }
1541
1542                        // User ending recording by clicking back mic
1543                        if (widgetRecognizing) {
1544                            // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
1545                            uvsClearMicResetTimeout();
1546
1547                            // Stop recorder
1548                            uvsAudioRecorder.stop();
1549
1550                            // Stop access to audio resource
1551                            uvsStopAudio();
1552
1553                            // Stop ongoing playback if nay
1554                            if (uvsAudioPlayer.isPlaying()) {
1555                                uvsAudioPlayer.stop();
1556                            }
1557
1558                            //replace recording with mic icon
1559                            uvsWidgetMic.classList.remove('listening');
1560
1561                            uvsWidgetSearch.placeholder = uvsMessages['transcribeText'];
1562
1563                            uvsAudioRecorder.getBuffers(function (buffers) {
1564                                if (!!uvsSttLanguageContext['gcp']['stt']) {
1565                                    uvsAudioRecorder.exportMonoWAV(function (blob) {
1566                                        uvsAudioRecorder.convertBlobToBase64(blob).then(function (resultedBase64) {
1567                                            uvsGcpStt(resultedBase64).then(function (transcriptResult) {
1568                                                uvsWidgetSearch.value = transcriptResult;
1569
1570                                                // Play 'basic' playback
1571                                                uvsAudioPlayer.configure(uvsAlternativeResponse['basic'], function () {
1572                                                });
1573                                                uvsAudioPlayer.play();
1574                                                setTimeout(() => {
1575                                                    uvsWidgetForm.submit();
1576                                                }, 2000);
1577                                            }).catch(function (error) {
1578                                                // Play 'notAudible' playback
1579                                                uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
1580                                                uvsAudioPlayer.play();
1581
1582                                                uvsWidgetSearch.placeholder = uvsMessages['ask'];
1583                                            })
1584                                        }).catch(function (error) {
1585                                            // Play 'notAudible' playback
1586                                            uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
1587                                            uvsAudioPlayer.play();
1588
1589                                            uvsWidgetSearch.placeholder = uvsMessages['ask'];
1590                                        });
1591                                    });
1592                                } else {
1593                                    // Play 'notAudible' playback
1594                                    uvsAudioPlayer.configure(uvsAlternativeResponse['notAudible']);
1595                                    uvsAudioPlayer.play();
1596
1597                                    uvsWidgetSearch.placeholder = uvsMessages['ask'];
1598                                }
1599                            });
1600
1601                            widgetRecognizing = false;
1602                            return;
1603                        } else {// User started recording by clicking mic
1604                            uvsWidgetMic.classList.add('listening');
1605                            event.preventDefault();
1606
1607                            // Stop ongoing playback if nay
1608                            if (uvsAudioPlayer.isPlaying()) {
1609                                uvsAudioPlayer.stop();
1610                            }
1611
1612                            widgetFinalTranscript = '';
1613
1614                            widgetRecognizing = true;
1615                            uvsAudioRecorder.clear();
1616                            uvsAudioRecorder.record(uvsWidgetMic);
1617
1618                            // To clear pre-existing mic reset timeout if any. (Based on duration from settings)
1619                            uvsClearMicResetTimeout();
1620
1621                            // To set new mic reset timeout. (Based on duration from settings)
1622                            window.uvsMicTimeoutIdentifier = setTimeout(function () {
1623                                let updatedClassList = uvsWidgetMic.classList;
1624
1625                                if (updatedClassList && updatedClassList.contains('listening')) {
1626                                    uvsWidgetMic.click();
1627                                }
1628                            }, uvsMicListenAutoTimeoutDuration);
1629                        }
1630                    }
1631                }, false);
1632            }
1633        }
1634
1635        // Elementor
1636        if (uvsIsElementor == true) {
1637            enableElementor();
1638        }
1639        // Singleclick
1640        if (uvsIsSingleClick == true) {
1641            enableSingleClick();
1642            uvsFloatingMicKeyBoardAccess('single');
1643        }
1644        // disable single click
1645        else {
1646            disableSingleClick();
1647            uvsFloatingMicKeyBoardAccess('double');
1648        }
1649
1650
1651        /*###############################################################################*/
1652
1653        /**
1654         * Function to toggle class of the HTML element
1655         *
1656         * @param {elmSelector - String} : CSS Selector
1657         * @param {nameOfClass - String} : Class name to add/remove
1658         */
1659        function uvsToggleClass(elmSelector, nameOfClass) {
1660            if (!(typeof (elmSelector) != 'undefined' && elmSelector != null && elmSelector.length != 0)) return false;
1661
1662            let element = document.querySelector(elmSelector);
1663
1664            if (element.classList) {
1665                element.classList.toggle(nameOfClass);
1666            } else {
1667                // For IE9
1668
1669                let classes = element.className.split(" ");
1670                let i = classes.indexOf(nameOfClass);
1671
1672                if (i >= 0) {
1673                    classes.splice(i, 1);
1674                } else {
1675                    classes.push(nameOfClass);
1676                    element.className = classes.join(" ");
1677                }
1678            }
1679        }
1680
1681        /**
1682         * Function to toggle chat and links
1683         */
1684        function uvsToggleWidgetElements() {
1685            if (uvsIsSingleClick == true) {
1686                uvsToggleClass('.uvs-widget-toggle-button', 'uvs-toggle-btn-mic');
1687                uvsToggleClass('.uvs-widget-toggle-button', 'uvs-toggle-btn-mic');
1688                uvsToggleClass('.uvs-widget-toggle-button', 'uvs-widget-active');
1689                uvsToggleClass('.uvs-widget-toggle-button', 'uvs-widget-visible');
1690                uvsToggleClass('#uvsWidgetToggleButton', 'uvs-widget-float');
1691                uvsToggleClass('.uvs-widget-button', 'uvs-widget-visible');
1692            }
1693            else {
1694                uvsToggleClass('.uvs-widget-toggle-button', 'uvs-toggle-btn-mic');
1695                uvsToggleClass('.uvs-widget-toggle-button', 'uvs-toggle-btn-close');
1696                uvsToggleClass('.uvs-widget-toggle-button', 'uvs-widget-active');
1697                uvsToggleClass('.uvs-widget-toggle-button', 'uvs-widget-visible');
1698                uvsToggleClass('#uvsWidgetToggleButton', 'uvs-widget-float');
1699                uvsToggleClass('.uvs-widget-chat-wrapper', 'uvs-widget-visible');
1700                uvsToggleClass('.uvs-widget-button', 'uvs-widget-visible');
1701            }
1702
1703        }
1704
1705    })();
1706};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.