window.speechSynthesis.speak(msg) not working until button click - javascript

The brief page below does not work. Specifically, "window.speechSynthesis.speak(msg)" does not work until the button has been pressed. If the button has been pressed then the "Hello" message works. If it has not then any calls to "window.speechSynthesis.speak(msg)" do not produce any audible output.
Suspecting that it has something to do with initialization of speechSynthesis - some things have been tried below to ensure that it is initialized when "Hello" is called. None have worked. Although it seems like it should have. It seems like it is getting properly initialized only if it is called from the button press.
The setup of the SpeechSynthesisUtterance itself is the same whether called from the button or the timeout. That setup works when called by the button. But nowhere else until it has been called by the button.
What is wrong here?
<!DOCTYPE html>
<html>
<head>
<title>Voice Test 3</title>
</head>
<body>
<div id="header">User Interface Terminal</div>
<input type="text" id="control_box"></input><br>
<button id="startButton" onclick="voicemessage('Button');">start</button><br>
<script>
function voicemessage(ttstext) {
var msg = new SpeechSynthesisUtterance(ttstext);
msg.volume = 1;
msg.rate = 0.7;
msg.pitch = 1.3;
window.speechSynthesis.speak(msg);
document.getElementById('control_box').value = ttstext;
}
window.speechSynthesis.onvoiceschanged = function() {
document.getElementById('control_box').value = "tts voices recognized";
window.setTimeout(function() {
voicemessage("Hello");
}, 5000);
};
window.addEventListener('load', function () {
var voices = window.speechSynthesis.getVoices();
})
</script>
</body>
</html>

This may be due to the browser itself...
Recent updates in some browsers (Firefox and Chrome) have policies to prevent audio from being accessed unless some user interaction triggers it (like a button click)...

Related

Firefox extension - save boolean to storage

In the Firefox extension, I want to implement a simple toggle switch that will enable/disable an extension. A basic idea is that the change of state will be saved as a boolean into browser (sync) storage. The state should be read every time, so an extension will know if should work or not.
But - my Javascript knowledge is so poor that I came into trouble.
Here is simple HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="styles.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.2/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<form id="form" class="ps-3 mt-3">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="flexSwitch">
<label class="form-check-label" for="flexSwitch">Plugin ON/OFF</label>
</div>
</form>
<label id="test"></label>
<br>
<script src="options.js"></script>
</body>
</html>
And here is a simple JS file:
function CheckAndSave()
{
var state = document.getElementById("flexSwitch");
if(state.checked)
{
document.getElementById('test').innerHTML = 'ON';
browser.storage.sync.set({ delovanje: 1 });
}
else
{
document.getElementById('test').innerHTML = 'OFF';
browser.storage.sync.set({ delovanje: 0 });
}
restoreState();
}
function restoreState()
{
//browser.storage.sync.get("delovanje", function(items) { console.log(items)});
let getting4 = browser.storage.sync.get("delovanje");
getting4.then(setCurrentChoice, onError);
function onError(error) {
console.log(`Error: ${error}`);
}
function setCurrentChoice()
{
var toggle = document.getElementsByName("flexSwitch");
if (result.delovanje === 1)
toggle.checked = true;
else
toggle.checked = false;
}
}
document.addEventListener("DOMContentLoaded", restoreState);
document.getElementById("flexSwitch").addEventListener('change', CheckAndSave);
What is wrong with my code? Is my way of saving Boolean ok?
I tried to write to the console for "debugging", but I don't know how to do it - this is a pop-up after a user press an icon, and nothing is shown in the console.
Most of all you did a mistake here:
function setCurrentChoice(result)
{
var toggle = document.getElementsByName("flexSwitch");
if (result.delovanje === 1)
toggle.checked = true;
else
toggle.checked = false;
}
In this case, toggle will be array like object, but not the element you expect.
You should use document.getElementById("flexSwitch") as previously.
Another issue that you missed an argument in the setCurrentChoice function. It should take settings like this:
function setCurrentChoice(result){...}
I would also suggest to hide the logic of getting element behind the scene by either wrapping it to the function:
const getToggle = () => document.getElementById("flexSwitch")
Or even move it to the separate class and encapsulate all logic there:
class Toggle {
constructor() {
this._el = document.getElementById("flexSwitch");
}
setCheck(value) {
this._el.checked = value;
}
}
Here is the working sample:
function CheckAndSave()
{
var state = document.getElementById("flexSwitch");
if(state.checked)
{
document.getElementById('test').innerHTML = 'ON';
chrome.storage.sync.set({ delovanje: 1 });
}
else
{
document.getElementById('test').innerHTML = 'OFF';
chrome.storage.sync.set({ delovanje: 0 });
}
}
function restoreState()
{
chrome.storage.sync.get("delovanje",setCurrentChoice );
function setCurrentChoice(result)
{
var toggle = document.getElementById("flexSwitch");
if (result.delovanje === 1)
toggle.checked = true;
else
toggle.checked = false;
}
}
document.addEventListener("DOMContentLoaded", restoreState);
document.getElementById("flexSwitch").addEventListener('change', CheckAndSave);
This approach will help you reduce the code and accidental mistakes.
P.S. Here is how I worked with the storage
The code seems okay, while there are some things I would change (for refactoring purposes to match my flavour) I think it should be working without much issue.
In any case verify the following.
The browser.storage.sync API is only available from extensions, so check that the HTML and JS that you are posting are actually part of the extension that you are using.
The manifest.json is what tells the browser what resources can your extension access, verify that you did add the "storage" permission on there here you can read more about it for chrome, though it will be the same for other browsers
For debugging purposes always remember that the browser lets you have great tools. Read more about developer tools, but as a starter I would tell you to open them and put a debugger statement there where you feel like there's something that isn't working as expected. And then with the console start looking for the properties that you are not finding.
To log items to the console use console.log('XXX') and it should show what you want
I think the problem is that the change event is not fired when setting toggle.checked with JavaScript. Just call CheckAndSave(); from the end of setCurrentChoice.

How to detect window close event that was opened using window.open()

I am trying to detect the window close event that I opened using window.open() in javascript. But for some reason, it doesn't seem to work.
Here is my code:
<html>
<head>
<script>
var clicktest = function() {
var newwindow = window.open("https://www.google.com",'myPopupwindow', "height=640,width=960,toolbar=no,menubar=no,scrollbars=no,location=no,status=no");
newwindow.addEventListener("beforeunload", function (e) {
console.log('hey');
});
}
</script>
</head>
<body>
<button onclick="clicktest()">hey</button>
</body>
</html>
I also tried using
newwindow.onbeforeunload = function () {
console.log('hey');
}
instead of window.addeventlistener(), but both didn't work and I did try using window instead of newwindow, still, it didn't work.
For cross-origin documents, the only solution is to poll the .closed property of the popup Window object.
But that is a very ugly thing to do, so please have a second though about why you need that.
To limit the ugliness, you can power your polling using battery friendly requestAnimationFrame:
const popup = window.open('https://google.com');
waitForClose(popup, e=>console.log('closed'));
function waitForClose(win, cb) {
function poll() {
if(win.closed) {
cb();
}
else {
requestAnimationFrame(poll);
}
}
poll();
}
As a fiddle since StackSnippet's iframes don't allow popups.

A simple example using html, javascript and jQuery

I'm starting with javascript, websockets and jQuery developing a simple example. In the html page I only have a button, that, when pressed, has to send its state (ON/OFF for instance). In index html, I have the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"></meta>
<title>First App</title>
<link rel="stylesheet" href="css/style.css">
<script src="js/jquery-3.3.1.min.js"></script>
<script src="js/APP.js"></script>
</head>
<body>
<div id='hello_message'>
Connecting...
</div>
<button id='state'>Turn on</button>
<div id='off'>OFF</div>
<div id='on'>ON</div>
</body>
</html>
My intention is to open a websocket between the client and the server when the page is loaded, and keep it open for any information to be sent between both of them. To this end, I have the following file containing the js code (APP.js):
window.onload = APPStart;
// Page onload event handler
function APPStart() {
state = false;
if ("WebSocket" in window)
{
var ws = new WebSocket("ws://10.30.0.142:8020");
ws.onopen = function()
{
alert ("Connected");
$('#hello_message').text("Connected");
};
ws.onmessage = function (evt)
{
var received_msg = evt.data;
};
ws.onclose = function()
{
alert("Connection is closed...");
};
window.onbeforeunload = function(event) {
socket.close();
};
}
else
{
// The browser doesn't support WebSocket
alert("WebSocket NOT supported by your Browser!");
}}
Now, every time someone clicks on button, I would like to execute the following code:
// program checks if led_state button was clicked
$('#state').click(function() {
alert ("click");
// changes local led state
if (led_state == true){
$('#on').hide();
$('#off').show();
state = false;
ws.send("ON");
}
else{
$('#off').hide();
$('#on').show();
state = true;
ws.send("OFF");
}
});
I've tried to put this part of the code inside the function APPStart, but it doesn't work. I also suspect that jQuery is not working either since messages are not updated. Any suggestion to make it work?
Thanks for the comments. The code works, the problem was in the cache of the browser. Once I noticed it, I cleaned the cache and everything started to work. Silly me.

How to close modal dialog from parent window?

How can I close modal dialog(s) from main page after some time, or when session expires, using JavaScript or jQuery?
Dialog is opened using the following code :
var result = window.showModalDialog("test.aspx" ... );
Dialog must be closed when counter expires like this:
function Discount() {
leftSeconds = leftSeconds - 1;
try { document.getElementById('tbLeft').value = leftSeconds; } catch (ex) { }
if (leftSeconds <= 5) {
clearTimeout(t);
// code for closing modal dialog(s)
} else {
t = setTimeout("Discount()", 1000);
}
}
Modal dialog can be closed from himself, but it's not solution in my case.
While the modal dialog is open, javascript execution on the main page is stopped, because it is waiting for a return value (even though you may not want to return one, or do anything with what it returns).
You can check this with this little example. When you click the button, the page opens, and the timer stops updating. When you close the page, execution is resumed:
<!DOCTYPE html>
<html>
<head>
<script>
var t = 0;
function count() {
document.getElementById('div').innerHTML = ++t;
}
var timer = setInterval(count, 1000);
</script>
</head>
<body>
<div id='div'></div>
<button onclick="window.showModalDialog('http://www.google.es');">Open window</button>
</body>
</html>
So, if you want to close the window automatically, you need to do it from the new document itself. My advice? Implement your timer in the window.load event of your modal page, so it can close itself after the desired time.
window.onload = function() {
setTimeout(function() { window.close(); }, 60000); //close window after 1 minute.
};

Why/how does Chrome treat onbeforeunload differently than other browsers?

Try this in chrome versus firefox/IE:
var cancelPressed = false;
function redirect() {
//window.location = "http://www.google.com";
alert('hi!');
}
window.onbeforeunload = function() {
window.pressedTimer = setInterval("cancelPressed = true; clearInterval(window.pressedTimer);",3000);
window.onbeforeunload = function() {
if (!cancelPressed) {
window.unloadTimer = setTimeout('redirect()',500);
window.onbeforeunload = function() {clearTimeout(window.unloadTimer);};
return "Redirecting..";
} else {
return 'wups';
}
};
return 'first!';
};
In FF/IE, refresh, hit cancel on the first prompt, wait about six seconds, and then try to refresh. The 'wups' will be triggered. However, in Chrome, you can wait as long as you want and cancelPressed will never be set to true.
What do you think?
Which version of Chrome are you using? If I wait long enough, I also get the 'wups' message in Chrome. However, I noticed a subtle difference between Webkit browsers and other browsers. Consider the following code:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Javascript test</title>
<script type="text/javascript" language="javascript">
window.onload = function() {
document.getElementById("test").onclick = function() {
var startdate;
var interval = window.setInterval(function() {
// Get the difference (in milliseconds) between the current
// date and the startdate.
var diff = (new Date()).getTime() - startdate.getTime();
alert(diff);
window.clearInterval(interval);
}, 5000);
alert("Hello!");
startdate = new Date();
};
};
</script>
</head>
<body>
<button id="test">Test button</button>
</body>
</html>
In chrome and safari, the second alert will always display a number slightly greater than 5000, while in other browsers, you get a number between 0 and 5000.
So what is happening? With setInterval(), the browser creates a timer that will invoke a javascript method every given interval. Javascript is single threaded, and an alert box will completely block the javascript execution. In chrome and safari, this means that the timer is also paused, while in other browsers the timer continues, but the javascript method invocation is suppressed until the alert box is closed.
What has this to do with your example? It means that in chrome and webkit you always have to wait at least 3000 milliseconds before cancelPressed is set, while in others browser, this will happen somewhere between 0 and 3000 milliseconds.

Categories

Resources