Speech Synthesis is not working in Safari MacOS 12.3 - macos

The Speech Synthesis API does not work on Safari on MacOS 12.3 (It is working on MacOS11). I have the code below where when user clicks a button will call speaknow() function. In the function, new SpeechUtterance utterance is created and window.speechSynthesis.speak(utterance) will be called. Afterwards, it is expected for utterance.onstart(), sound of the utterance, then utterance.onend() to be called.
function speaknow() {
if ('speechSynthesis' in window) {
window.utterances = [];
this.utterance = new SpeechSynthesisUtterance();
this.utterance.text = 'Speaker on';
window.utterances.push(this.utterance);
this.utterance.onstart = function(event) {
console.info('this.utterance.onstart()');
}
this.utterance.onend = function(){
console.info('this.utterance.onend()');
};
this.utterance.onerror = function(event) {
console.error('error utterance ', event );
}
window.speechSynthesis.speak(this.utterance);
setTimeout(function(){
// NOTE: forceStop=true is set through button click
if (!window.speechSynthesis.speaking && (!forceStop)) {
speaknow(); // re-attempt
console.info('window.speechSynthesis is not speaking. Re-attempt speaknow().');
}
else if (window.speechSynthesis.speaking) {
console.info('window.speechSynthesis.speaking: ' + window.speechSynthesis.speaking);
}
},500);
}
}
Observation:
No sound at all.
During the first time window.speechSynthesis.speak() gets called, utterance.onstart() never gets called, but utterance.onend() gets called.
window.speechSynthesis.speaking is always true.
For the next time window.speechSynthesis.speak() gets called, neither utterance.onstart() nor utterance.onend() gets called. window.speechSynthesis.speaking remains true but still no sound.

Related

React Redux Action Creator Dispatch Issue with Fetch API and Promise

I am writing action creator in react app. where in when i do some api call i need to show the Progress Loader on screen. So, my action creator looks like this.
export const fetchData = (actionType, param) => (dispatch) => {
dispatch(Action(ActionConstants.SHOW_PROGRESS_LOADER)); // Show Loader Action
return fetchDataRequest(actionType, param) // Here is Fetch APi Call
.then(responseData => {
dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER));
dispatch(Action(recd(actionType), { data: responseData, receivedAt: Date.now() }));
}).catch((error) => {
dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
});
};
When i write this piece of code its working as expected, i am dispatching the action as dispatch(fetchData(data)) from component and i am able to show the loader in my Parent Component. What i understand is fetch is returning me the promise. Once the fetch gets completed then i am hiding the loader which is working as expected.
Now, There is scenario where in i need to do some validation where in i don't have to make any api call but all the validation are performed locally.
Here also i want to do the same thing like i need to show loader in my parent component as well when all the validation are done i need to hide the loader.
I have written the same piece of code even actions are getting called but my render function is not getting called.
My Code Looks like:
// This my action creator which will actually do the validation
export const validateAndSaveData = () => {
return ((dispatch, getState) => {
return new Promise((resolve, reject) => {
let saveRecommendDetailsFlag = true;
// here i am dispacthing some action and storing data in my store
saveRecommendDetailsFlag = canSaveData(getState());
if (saveRecommendDetailsFlag) {
resolve('SUCCESS');
} else {
reject('ERROR');
}
});
});
};
And there is one more action creator which i am calling it from from UI Component which will first initiate the show loader action and then perform validation and based on the result of validation i have to hide the loader.
export const saveData = () => {
return ((dispatch) => {
dispatch(Action(ActionConstants.SHOW_PROGRESS_LOADER)); // Show Loader Action
return dispatch(validateAndSaveData())
.then(() => {
// Here i m dispatching an action to do some more processing.
dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
})
.catch(() => {
dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
});
});
};
Everything is working fine but my loader are not coming on the screen. i am not able to figure it out where am i doing wrong.
Can anyone suggest something how can i solve this issue?
I got some workaround using setTimeout func but i don't think that is right approach.
export const saveData = () => {
return ((dispatch) => {
dispatch(Action(ActionConstants.SHOW_PROGRESS_LOADER)); // Show Loader Action
setTimeout(()=>return dispatch(validateAndSaveData())
.then(() => {
// Here i m dispatching an action to do some more processing.
dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
})
.catch(() => {
dispatch(Action(ActionConstants.HIDE_PROGRESS_LOADER)); // Hide Loader Action
});
},10);
});
};
Your code looks reasonable, my suspicion is that your validateAndSaveData promise finishes so quickly that there is no visible loader on the screen.
In that case, a timeout is totally reasonable. However, in order to do it properly, I would keep a state on if the loading screen is visible + if it's been shown long enough. You can then remove the loading screen once it is both up for long enough, and the actual event expires.
I'm not sure which action package you're using, so I can't post exact code, but the pseudocode would look something like this:
const delay = (seconds) => new Promise((resolve) => setTimeout(resolve, seconds));
let loadingCounter = 0;
const showLoadingScreen = () => (dispatch) => {
const counter = loadingCounter;
loadingCounter++;
delay(5).then(() => {
if (getStore().loadingScreen.counter === counter) {
dispatch(Action(ActionConstants.PROGRESS_LOADER_DELAY_ELAPSED))
}
})
return dispatch(Action(ActionConstants.SHOW_PROGRESS_LOADER, counter))
}
Basically, you would keep track of 3 pieces of state for the loader:
{
counter: 0,
taskCompleted: false,
canHide: false,
}
Counter is saved so that you can disambiguate what happens if you get SHOW_PROGRESS_LOADER while an existing SHOW_PROGRESS_LOADER is in progress.
taskCompleted keeps a record of whether the thing you're waiting on is done, and canHide keeps track if the loader has been visible on the screen long enough.
When you dispatch PROGRESS_LOADER_DELAY_ELAPSED it sets canHide to true, and when you dispatch HIDE_PROGRESS_LOADER it sets taskCompleted to true. (although you may want to rename the latter action). When both canHide and taskCompleted are set to true, only then can the loader go away.
This is a pretty common UI pattern - Try to complete a task quickly. If it takes more than a short amount of time, then throw up a loading dialog. However, the loading dialog is guaranteed to stay up a minimum amount of time to prevent flickering. So the more advanced version of this kind of pattern would be to add another state which doesn't show the progress loader at all unless the call takes more than Y milliseconds.
Hope this makes sense, leave a comment if not :-)

How do I do this via RxJs?

I have a autocomplete control that triggers a onAutoCompleteSearch() after a debounce where I retrieve results from the server. However, if the user enters text and hits enter (key code 13) then a signal should be raised that will cancel the next invocation of an autocomplete. Since this is a 3rd party control I don't have control over the invocation of onAutoCompleteSearch() that occurs after a set debounce time.
I am using a Subject to do the signalling:
private cancelAutoComplete$ = new Subject<boolean>();
If user hits enter key:
onKeyUp(e) {
if (e.keyCode === 13) {
this.cancelAutoComplete$.next(true);
this.fireExecuteSearch(); // fire full search
} else {
this.fireSearchChange(); // trigger user input change
}
}
When an autocomplete is to be executed:
onAutoCompleteSearch(e) {
console.log('starting autocomplete!');
this.cancelAutoComplete$
.first()
.defaultIfEmpty(false)
.subscribe(c => {
if (c) {
console.log('autocomplete cancelled!');
} else {
console.log('execute the autocomplete!');
this.executeAutoComplete.next(e.query);
}
});
}
the above does not quite work... what I wish to do is check the cancelAutoComplete stream for an element, if one exists then take it off the stream, if the cancel flag is true then abort the autocomplete. If there isn't an element then return a default element of false so I can continue with the autocomplete.
How can I accomplish this? Basically if there is an cancel signal pending from the onKeyUp -> keycode 13 event I want to abort the call, if not continue.
I know I can use a simple boolean to track this but wanted to know how to do it via RxJs Subjects.
Firstly I'd make cancelAutoComplete$ a BehaviorSubject initialised to false. Send it false whenever the keyCode is not 13:
private cancelAutoComplete$ = new BehaviorSubject<boolean>(false);
onKeyUp(e) {
if (e.keyCode === 13) {
this.cancelAutoComplete$.next(true); // prevent autocomplete
this.fireExecuteSearch();
} else {
this.cancelAutoComplete$.next(false); // allow autocomplete
this.fireSearchChange();
}
}
Then I'd use the takeUntil operator as part of your executeAutoComplete stream as follows:
onAutoCompleteSearch(e) {
this.executeAutoComplete.next(e.query);
}
this.executeAutoComplete
.switchMap(query => this.backend.fetchAutoCompleteResults(query).takeUntil(
this.cancelAutoComplete$.filter(c => c === true)
))
.subscribe(...);
I've assumed your backend api is named this.backend.fetchAutoCompleteResults - the takeUntil will abort it if cancelAutoComplete$ is initially true or becomes true while the call is in flight.

Rx.Observable.repeat (indefinitely) with zip causes the browser to stop responding

The following code causes the browser to stop responding, using a value like '100' for example for the repeat solves the problem, but in my case I don't have specific value for it.
Would you please suggest a solution:
var observer = Rx.Observer.create(function (x)
{
console.log(x);
},
function (err)
{
console.log('Error: ' + err);
},
function ()
{
console.log('Completed');
});
var repeat = Rx.Observable.repeat(10, null); //repeat indefinitely
var interval = Rx.Observable.interval(1000);
var zip = Rx.Observable.zip(repeat,
interval,
function(rep, inter)
{
return rep + inter;
});
zip.subscribe(observer);
The browser freezes because .repeat simply yields 10 indefinitely.
Since Rx is push-based, we have no way of knowing when zip needs another item. Instead, we just push new values to zip as they become available. The static (class-method?) repeat says "hey, I have new items RIGHT NOW ALWAYS HERE THEY ARE" and never relinquishes control-flow back to zip. This means zip never actually ends up subscribing to the interval observable, so zip just starts buffering indefinitely.
If you're coming from a functional background, then it would seem like an "infinite" list of "10"s would zip nicely with a finite list of anything. Which is absolutely true, assuming your infinite list is lazy. In this case, our "list" has a mind of it's own, and definitely isn't lazy.
I'd be happy to suggest a solution, but it seems that the example is contrived. What exactly are you attempting to do?
I was dealing with the same problem. Looks like delay can do the trick.
Here's the slightly modified version of your code:
var observer = Rx.Observer.create(function (x)
{
console.log(x);
},
function (err)
{
console.log('Error: ' + err);
},
function ()
{
console.log('Completed');
});
var repeat = Rx.Observable.of(10).delay(0).repeat(-1); //repeat indefinitely
var interval = Rx.Observable.interval(1000);
var zip = Rx.Observable.zip(repeat,
interval,
function(rep, inter)
{
return rep + inter;
});
zip.subscribe(observer);

Why is AngularFire so much slower than plain Firebase API

In testing out Firebase with AngularFire, I was surprised at how slow it is. After further testing, I discovered that it isn't Firebase that is slow, but AngularFire that is slow (incredibly slow in Firefox v26.0).
My use case is where I need to access a number of children for a given parent. The total number of children will potentially be in the thousands, so fetching them all at once is not an option. In addition, they will need to be accessed from grandparents, so querying by priority is not always an option.
Is there something I'm doing wrong in this sample with AngularFire (slow):
http://plnkr.co/edit/eML3HF3RtchIU26EGVaw?p=preview
Gist of accessing children with AngularFire:
function getChild(childID) {
recordCount++;
myC.children[childID] = $firebase(new Firebase(childrenUrl + childID));
myC.children[childID].$on('loaded', function () {
returnCount++;
checkReturnCount();
});
}
function checkReturnCount() {
if (recordCount != 0 && recordCount == returnCount) {
var diff = (new Date).getTime() - start;
myC.log.push("Loaded " + parent.FirstName + "'s children in " + diff + "ms.");
$scope.$apply();
}
}
For comparison, see this sample which isn't using any Angular plugin (fast):
http://plnkr.co/edit/GA17FEnHu7p8wAiDXA5b?p=preview
Gist of accessing children without AngularFire
function getChild(childID) {
recordCount++;
var tempRef = new Firebase(childrenUrl + childID);
tempRef.on('value', function (data) {
myC.children[childID] = data.val();
returnCount++;
checkReturnCount();
});
}
function checkReturnCount() {
if (recordCount != 0 && recordCount == returnCount) {
var diff = (new Date).getTime() - start;
myC.log.push("Loaded " + parent.FirstName + "'s children in " + diff + "ms.");
$scope.$apply();
}
}
OK, I may have found a solution. Apparently Firefox used to add random times to it's setTimeouts, but it doesn't any longer (see https://developer.mozilla.org/en-US/docs/Web/API/Window.setTimeout). However, Firefox (as well as other browsers) apparently still have a minimum timeout delay (which in FF is apparently 4ms).
This page proposes a solution: http://dbaron.org/log/20100309-faster-timeouts
Here is the setZeroTimeout method from that blog post:
// Only add setZeroTimeout to the window object, and hide everything
// else in a closure.
(function() {
var timeouts = [];
var messageName = "zero-timeout-message";
// Like setTimeout, but only takes a function argument. There's
// no time argument (always zero) and no arguments (you have to
// use a closure).
function setZeroTimeout(fn) {
timeouts.push(fn);
window.postMessage(messageName, "*");
}
function handleMessage(event) {
if (event.source == window && event.data == messageName) {
event.stopPropagation();
if (timeouts.length > 0) {
var fn = timeouts.shift();
fn();
}
}
}
window.addEventListener("message", handleMessage, true);
// Add the one thing we want added to the window object.
window.setZeroTimeout = setZeroTimeout;
})();
When I use this setZeroTimeout method, using AngularFire doesn't seem to be noticeably slower than using the base API.
For comparison, I've created a new Plnkr using it instead of the $timeout service.
AngularFire with setZeroTimout: http://plnkr.co/edit/nywEJpLcPwEJjXzipS4n?p=preview
AngularFire - http://plnkr.co/edit/nywEJpLcPwEJjXzipS4n?p=preview
Base Firebase API - http://plnkr.co/edit/GA17FEnHu7p8wAiDXA5b?p=preview
Could this be included in AngularFire? Or should I just modify my version for now?
OK, I think I've come up with a further improvement on the solution I started to come up with above, which also triggers the angular digest cycle as needed:
I overwrote the _timeout function in the AngularFire function as follows:
this._timeout = function (fn) {
fn();
throttledApply();
};
throttledApply is defined in the $firebase factory as:
var throttledApply = _.throttle(apply, 100);
function apply() {
$rootScope.$apply();
}
and is then passed to the AngularFire function instead of the $timeout service. It is making use of underscore's throttle function to call $apply immediately, and then at most once every 100ms thereafter. For my purposes, this is sufficient. It could easily be reduced to something more like 50ms, or 25ms though.
Are there any repercussions of these modifications that I'm not seeing?

requesting two Ajax

I'm trying to make two Ajax calls to get data to populate different bits of a web page, and as you'll already know, only the second happens.
So I thought I'd do this:
callAjax1('a'); callAjax2('b');
function callAjax1(data) {
ajax(data);
}
function callAjax2(data) {
ajax(data);
}
function ajax(data) {
// calls XMLHttpRequestObject etc
}
The idea was that instead of calling ajax() twice, now, I'd have two independent instances of ajax that would run independently.
It works .. but only if I put in an alert at the top of ajax() to let me know I've arrived.
So I'm thinking that alert gives the first request time to finish before the second is called. Therefore, I've not managed to separate them properly into separate instances. Is that not possible?
What am I missing?
All the best
J
UPDATE:
I'm thinking this, do I stand a chance?
tParams = new Array (2); // we intend to call ajax twice
tParams[0] = new Array('ajaxGetDataController.php', 'PROJECT', 'id');
tParams[1] = new Array('ajaxGetFileController.php', 'FILE', 'projectId');
<select name='projectSelector' onchange=\"saveData(tParams, this.value);\">\n";
// gets called, twice
function saveData(pParams, pData) // pParams are: PageToRun, Table, Field
{
if (XMLHttpRequestObject)
{
tPage = pParams[0][0]+'?table='+pParams[0][1]+'&pField='+pParams[0][2]+'&pData='+pData;
XMLHttpRequestObject.open('GET', tPage);\n
XMLHttpRequestObject.onreadystatechange = callAjax(pParams, pData);
XMLHttpRequestObject.send(null);
}
}
function callAjax(pParams, pData)
{
if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200)
{
var tReceived = XMLHttpRequestObject.responseXML;
options = tReceived.getElementsByTagName('option'); // fields and their values stored in simplest XML as options
popForm(options, pParams[0][1]); // goes off to use the DOM to populate the onscreen form
pParams.shift(); // cuts off pParams[0] and moves all elements up one
if (pParams.length>0)
{
saveData(pParams, pData);
}
}
}
I would create a ready state variable for the AJAX function:
function ajax(data) {
readyState = false;
// calls XMLHttpRequestObject etc
}
And then check for the ready state before executing the second call:
function callAjax2(data) {
if(readyState == true) {
ajax(data);
readyState = true;
}
}
And make sure to change the readyState back to false after the AJAX calls have executed. This will ensure the first AJAX call has finished executing before the second one tries to fire.

Resources