- Posts: 175
- Thank you received: 28
Ask the community, share ideas, and connect with other LimeSurvey users!
<!-- Button for starting the recording --><button id="startBtn" style="background-color: green; color: white;" type="button">Click here to use your microphone to answer</button> <!-- Modal HTML --></p> <div id="countdownModal" style="display:none; position:fixed; left:0; top:0; width:100vw; height:100vh; background:rgba(0,0,0,0.5); z-index:1050; align-items:center; justify-content:center;"> <div style="background:white; padding:30px; border-radius:10px; text-align:center; min-width: 240px;"> <h2>Get Ready!</h2> <p>Starting in <span id="countdownValue">3</span>...</p> </div> </div> <script> $(document).ready(function() { const startButton = $('#startBtn'); const answerTextarea = $('#answer947655X225X9377'); const modal = $('#countdownModal'); const countdownEl = $('#countdownValue'); let startedOnce = false; let isRecording = false; let lastManualValue = ""; // Keeps manual edits and previous result let recognitionActiveSessionTranscript = ""; // Keeps what is added in the present session if ("webkitSpeechRecognition" in window) { const recognition = new webkitSpeechRecognition(); recognition.continuous = true; recognition.interimResults = true; recognition.lang = "en-US"; let interimTranscript = ""; let pauseTimeout; // Helper: Capitalize after punctuation const capitalizeAfterPunctuation = (text) => { return text.replace(/(?:^|\. )(\w)/g, (match, p1) => match.replace(p1, p1.toUpperCase())); }; // Handle user edits answerTextarea.on('input propertychange', function(){ if (!isRecording) { lastManualValue = answerTextarea.val(); } }); // Start speech recognition and sync with edits const startRecognition = () => { // Always take the CURRENT textarea contents as base lastManualValue = answerTextarea.val(); recognitionActiveSessionTranscript = ""; recognition.start(); }; const stopRecognition = () => { recognition.stop(); }; recognition.onstart = () => { isRecording = true; startButton.text("Stop and edit my answer").css({ "background-color": "red", "color": "white" }); }; recognition.onend = () => { isRecording = false; // Update manual value in case user typed something after last pause lastManualValue = answerTextarea.val(); startButton.text("Resume recording").css({ "background-color": "green", "color": "white" }); clearTimeout(pauseTimeout); }; recognition.onresult = (event) => { interimTranscript = ""; clearTimeout(pauseTimeout); for (let i = event.resultIndex; i < event.results.length; i++) { const transcript = event.results[i][0].transcript; if (event.results[i].isFinal) { recognitionActiveSessionTranscript += transcript; } else { interimTranscript += transcript; } } // Compose up-to-date value: always prepend latest manual edits! let finalText = lastManualValue + (recognitionActiveSessionTranscript ? " " + capitalizeAfterPunctuation(recognitionActiveSessionTranscript.trim()) : "") + (interimTranscript ? " " + interimTranscript : ""); answerTextarea.val(finalText.trim()); // After a pause: finalize what's been heard pauseTimeout = setTimeout(() => { recognitionActiveSessionTranscript = recognitionActiveSessionTranscript.trim() + ". "; recognitionActiveSessionTranscript = capitalizeAfterPunctuation(recognitionActiveSessionTranscript); let finalVal = lastManualValue + (recognitionActiveSessionTranscript ? " " + recognitionActiveSessionTranscript.trim() : ""); answerTextarea.val(finalVal.trim()); }, 1000); }; // Modal logic function showCountdownModal(seconds, callback) { countdownEl.text(seconds); modal.css('display', 'flex'); let left = seconds; const countdownInterval = setInterval(() => { left--; countdownEl.text(left); if (left <= 0) { clearInterval(countdownInterval); modal.hide(); callback(); } }, 1000); } // Button click logic startButton.on('click', function() { if (isRecording) { stopRecognition(); } else if (!startedOnce) { startedOnce = true; showCountdownModal(3, function() { startRecognition(); }); } else { startRecognition(); } }); } else { answerTextarea.val("Web Speech API not supported in this browser."); } }); </script>
Please Log in to join the conversation.