HTML5 Voice API - Resetting Result Array - javascript

I'm using the HTML5 voice API for a project. I'm having trouble trying to set the result array: event.results.
I'm listening for '[A-H][0-9] "INTO" [A-H][0-9] "GO"'. When I hear "GO", I want to reset the events.result array. I have to listen for the same input again, but the first input cannot be removed from the event.results array.
I've tried:
event.results = [];
event.results.length = 0;
None of these work. I've also looked up the API and I can't find the solution to what I'm trying to do.
A similar example to what I want to do, would be if it was listening for any sequence of words. But when it heard the word "Cancel", it would forget everything it had just heard.
I hope this makes sense and any help is greatly appreciated.

It seems that the results are held in a SpeechRecognitionList, but I couldn't find any api for manipulating the list itself.
What does work is stopping and restarting the recognition, but that's problematic if you're not using a https-site (on a plain http site the browser always asks for permission when restarting recognition).
Here's an example:
<html>
<head>
<title>voice api test</title>
</head>
<body>
<h1>voice api test</h1>
<main></main>
<script>
(function startRecognizing() {
var main = document.querySelector('main');
var recognition = new webkitSpeechRecognition();
recognition.continuous = true;
recognition.addEventListener('result', function (event) {
var lastResult = event.results[event.results.length - 1];
if (lastResult[0].transcript.indexOf('cancel') > -1) {
recognition.stop();
while (main.children.length) main.removeChild(main.children[0]);
startRecognizing();
} else {
var p = document.createElement('p');
p.appendChild(document.createTextNode(lastResult[0].transcript));
main.appendChild(p);
}
});
recognition.start();
}());
</script>
</body>
</html>

Related

HTML IFrame not allowed to download file

im trying to download a file that constructs itself based on the value it recives. This is my code
<html>
<head>
<script>
var myList=[];
window.onmessage = function(event){
if (event.data) {
myList = event.data;
if (myList.length>0) {
buildHtmlTable();
}
}
else {
myList = [];
}
};
function buildHtmlTable() {
var columns = addAllColumnHeaders(myList);
for (var i = 0 ; i < myList.length ; i++) {
var row$ = $('<tr/>');
for (var colIndex = 0 ; colIndex < columns.length ; colIndex++) {
var cellValue = myList[i][columns[colIndex]];
if (cellValue == null) { cellValue = ""; }
row$.append($('<td/>').html(cellValue));
}
$("#excelDataTable").append(row$);
}
return exportF(); // Make Excel file download now
}
function addAllColumnHeaders(myList)
{
var columnSet = [];
var headerTr$ = $('<tr/>');
for (var i = 0 ; i < myList.length ; i++) {
var rowHash =`enter code here` myList[i];
for (var key in rowHash) {
if ($.inArray(key, columnSet) == -1){
columnSet.push(key);
headerTr$.append($('<th/>').html(key));
}
}
}
$("#excelDataTable").append(headerTr$);
return columnSet;
}
function exportF() {
var table = document.getElementById("excelDataTable");
var html = table.outerHTML;
var url = 'data:application/vnd.ms-excel,' + escape(html);
var link = document.getElementById("downloadLink");
link.setAttribute("href", url);
link.setAttribute("download", "export.xls"); // Choose the file name here
link.click(); // Download your excel file
return false;
}
</script>
</head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body onLoad="">
<table id="excelDataTable" border="1">
</table>
<a style="display: none" id="downloadLink"></a>
</body>
</html>
The code itself works, but the error i get is "Download is disallowed. The frame initiating or instantiating the download is sandboxed, but the flag ‘allow-downloads’ is not set. See https://www.chromestatus.com/feature/5706745674465280 for more details."
What can i do to work around this? It feels like ive tried everything i can get my hands on but nothing seems to work for it to download
As the warning message says, you can't initialize downloads from a sandboxed iframe if it doesn't have the allow-downloads permission.
All solutions will imply having access to the page where the iframe is displayed (hereafter "the embedder").
The easiest and recommended way,
is to ask the embedder to add this permission when they define their iframe:
<iframe src="yourpage.html" sandbox="allow-scripts allow-downloads"></iframe>
An other way would be to ask them to not sandbox that iframe at all,
<iframe src="yourpage.html"></iframe>
but I guess that if they did, it's because they don't trust your page enough.
Finally a more complex way would be to pass the generated file back to the parent window.
For this you'd need to define a new API with your clients.
You could obviously just emit a global message event back to them, but I guess the cleanest is to make them pass a MessageChannel's MessagePort along with the myList data, so they can wait for the response there easily and be sure they'll only catch the response and no other unrelated message.
So in the embedder page they'd do
frame.onload = (evt) => {
const channel = new MessageChannel();
// handle the response from the iframe
channel.port2.onmessage = (evt) => {
const file = evt.data;
saveAs( file, "file.html" ); // the embedder is reponsible to initialize the download
};
frame.contentWindow.postMessage( embedders_data, [ channel.port1 ] );
};
And in your page you'd do
window.onmessage = (evt) => {
const myList = evt.data;
// get the MessageChannel's port out of the transfer-list
const port = evt.ports[ 0 ];
// buildHtmlTable has to return the final file, not to make it download
const file = buildHtmlTable( myList );
if( port ) {
port.postMessage( file ); // send back to embedder
}
};
See it as a live plnkr.
Ps: note that your files are not xlsx files but HTML markup.
The correct answer
Under normal circumstances Kaiido's answer is indeed the correct solution to your problem. They will NOT work in your case though.
The answer that will work on WixSince you are using Wix there is no way for you to directly edit the Sandbox attribute of the iframe element. This is just how Wix does things. You can, however, use custom code (only applies to premium websites) to get the class name of the iframe and programatically use javascript to set the new attribute to the existing iframe.
You must use the web inspector to find out the class name (iframes in Wix do not have ids) then add "allow-downloads" to the sandbox attribute. You might then need to reload the iframe using js as well. Go to your website's settings -> Custom Code -> Create custom code at the end of the body tag
If you do not have a premium website then you unfortunately cannot do this. This is due to Wix's own limitations as a platform. If this is an absolute "must" for you project, I recommend you to not use Wix since they limit your freedom as a developer when it comes to working with
technologies that were not made by them. Not to mention that they lock features such as custom elements behind a pay wall. So we can't even test our ideas before committing to a hosting plan. For anyone reading this in the future, take this into consideration and look into other platforms.
Thanks for answers, i didnt find a sollution with the recomended answers. What i did is that i made a completely new page, instead of initializing a html iframe i redirected the current window to the new page i created. The new page took a variable from "www.page.com/?page={value} and downloaded what i needed from there instead. Its messy but it works so if anyone else has this problem i recomend this if you are using wix.

How to add an onclick event in html for Javascript - by a non programmer

This is my first post and I'm asking for help. I am not a programmer of any kind but keen to understand programming and have set up a Codepen page as an example. I am trying to share with some people who have asked can the page allow mouse clicks to work?
What I'm trying to get is to have this working without a keyboard click event, i.e. onkeydown= or onkeyup=, which is what happens now but work with a mouse click which will allow this to work from a mobile phone browser?
If someone can write/show the code I need, I would be very grateful. I see that the HTML needs to define the onclick event and then do two things, the first is speakPrevious and the second getNewRandomColor. I would think that JavaScript will need to define the onclick element? But I am not sure...
`HTML`
<body onkeydown="speakPrevious()">
<body onkeyup="getNewRandomColor()">
`JS`
speakPrevious();
function speakPrevious() {
var synth = window.speechSynthesis;
var utterThis = new SpeechSynthesisUtterance(window.value);
synth.speak(utterThis);
}
getNewRandomColor();
function getNewRandomColor() {
var myArray = ['Red','Green', 'Blue', 'Yellow', ];
var rand = myArray[Math.floor(Math.random() * myArray.length)];
document.getElementsByTagName("body")[0].style.backgroundColor = rand;
var oldRand = rand;
window.value = oldRand;
}
you can allow users to interact with the web page by either using their keyboard or by clicking on the page if you use an event listener.
In your javascript you can add code (like below) which will trigger the function code whenever the html body element is clicked. This will add functionality to allow users to click on the page.
const page = document.querySelector("body");
page.addEventListener("click", function () {
speakPrevious();
getNewRandomColor();
});
Additionally you may find it easier to combine your body tag events into one body tag with both events.
<body onkeydown="speakPrevious()" onkeyup="getNewRandomColor()">
This will allow the user to either click on the page to trigger the functions or to use a keyboard event.
My final document code looked like this
<html>
<body onkeydown="speakPrevious()" onkeyup="getNewRandomColor()">
<p>The algorithm will select colors at random from RGBY and you may see the same color several times in a row. This
is expected behavior and NOT a fault.<br>Click inside the color and press any keyboard key to move to the next
color.</p>
</body>
<script>
const page = document.querySelector("body");
page.addEventListener("click", function () {
speakPrevious();
getNewRandomColor();
});
function speakPrevious() {
var synth = window.speechSynthesis;
var utterThis = new SpeechSynthesisUtterance(window.value);
synth.speak(utterThis);
}
function getNewRandomColor() {
var myArray = ['Red', 'Green', 'Blue', 'Yellow', ];
var rand = myArray[Math.floor(Math.random() * myArray.length)];
document.getElementsByTagName("body")[0].style.backgroundColor = rand;
var oldRand = rand;
window.value = oldRand;
}
</script>
</html>

Banner rotating images. Each image when clicked sends to a different URL (vanilla javascript)

I've been given two examples of how to do this but neither is doing both things that I'm looking to do. My website should include:
Rotating Image Banner (3 images), that changes every few seconds
Each image should be clickable and redirect you to a different URL
In our recent lecture, the professor wrote this code on the board and said that this was how you did that. However, it's not working for me.
<html>
<head>
<script language=JAVASCRIPT type=TEXT/JAVASCRIPT>
//I'm not sure when to use '' or ""
//I replaced some of the "picture.jpg" images with links to images. I'm not sure if I used the right syntax.
adImages = new Array("https://i.picsum.photos/id/666/800/200.jpg",
"https://i.picsum.photos/id/420/800/200.jpg",
"https://i.picsum.photos/id/888/800/200.jpg");
adURL = new Array("https://google.com","https://github.com","https://stackoverflow.com");
thisAd = 0;
//length of what?
imgCt = adImages.length;
function rotate()
{
if (document.images)
{
thisAd++;
//Is it better practice to use "==="?
if (thisAd == imgCt)
{
thisAd = 0;
}
document.adBanner.src=adImages[thisAd];
setTimeout("rotate()", 2 * 1000);
}
}
function newLocation()
{
document.location.href = adURL[thisAd];
}
</script>
</head>
//I don't understand what this is at all
<body onload=rotate()>
//Apparently <center> is obsolete?
<center>
<p><font size=4>Rotating Banner <font color=#ff0000>Assignment 6</font> Rotate Party -
Udemy</font>
</p>
<a href="javascript:newLocation()"><IMG height=105 alt="Ad Banner"
src="https://i.picsum.photos/id/666/800/200.jpg" width=610 name=adBanner></a>
</center>
</body>
</html>
Just a heads up. I've been posting my slides from class on Reddit the past couple of weeks and I've received a lot of comments about things being horribly out of date. If you can, please give me examples that are more modern or better practices than what you see me learning. You can find the conversations about my experience learning JavaScript in community college here if you're interested: https://www.reddit.com/user/gettupled/
The second example we were given was a YouTube video that gave the following example. However, it does not include the option of clicking the image and being sent to a URL. I'm not sure if it's common to post HTML, CSS and Javascript code in the body of a message so I'll just attach a codepen unless told otherwise. This code comes from Travesy Media.
https://codepen.io/vitalwheat/pen/QWbEyqN
Thanks everyone. This is my first post here. Hi.
There are many way to implement this. Here is one of the way to do it.
working Demo
(function() {
"use strict";
const imageList = [
"https://i.picsum.photos/id/666/800/200.jpg",
"https://i.picsum.photos/id/420/800/200.jpg",
"https://i.picsum.photos/id/888/800/200.jpg"
];
const urlList = [
"https://google.com",
"https://github.com",
"https://stackoverflow.com"
];
function createRotatingBanner(rotationTime) {
const $adsBanner = document.querySelector(".adBanner");
let $bannerList;
let currentBannerRendered = 0;
function renderBanner() {
Array.from($bannerList).forEach((banner, bannerIndex) => {
banner.className = bannerIndex === currentBannerRendered ? "" : "hide";
});
currentBannerRendered = (currentBannerRendered+1)%$bannerList.length;
}
// creating Banner image and setting them to hide
function createBanner() {
const fragement = new DocumentFragment();
imageList.forEach((image, index) => {
const banner = document.createElement("img");
banner.src = image;
// wrapping image with anchor element
const anchor = document.createElement("a");
anchor.href = urlList[index];
// hide all the banner
anchor.className = "hide"
anchor.appendChild(banner);
fragement.appendChild(anchor);
});
const cloneFragement = [...fragement.children];
$adsBanner.appendChild(fragement);
return cloneFragement;
}
$bannerList = createBanner();
renderBanner();
setInterval(renderBanner, rotationTime);
}
createRotatingBanner(2000);
})();
.hide {
display: none;
}
<div class="adBanner"></div>

Pause is behaving incorrectly in the SoundCloud Javascript API

Note: Exactly this has been asked before here, and here, without satisfactory answers.
I'll try to explain the problem better here, and you can also read TLDR below. Here's a simple fiddle I created using Soundcloud JS sdk v3. I define global variables playerGlobal and playingId. During the first play, both of them are null, and clicking one of play or playNext buttons initializes those variables. Suppose, we click play first, the related track starts playing. When we click pause button soon after, pause() fires and uses the globalPlayer to pause the currently playing track. This works as expected.
When I click playNext, both global variables are updated as they should. The problem arises when I click play again. For some strange reasons, the track associated with play button plays from time starting at when I clicked pause above. When I click pauseagain, nothing happens.
TLDR: Click play -> pause -> playNext(works fine till here) -> play(strange remembering of last position happens) -> pause(nothing happens).
I'm including the snippet here as well.
SC.initialize({
client_id: 'MmZKx4l7fDwXdlL3KJZBiJZ8fLonINga'
});
//Get player
function getPlayer(url) {
return new Promise(function(resolve, reject) {
SC.stream(url)
.then(player => {
if (player.options.protocols[0] === 'rtmp')
player.options.protocols.splice(0, 1);
resolve(player);
});
});
}
//Global players and id to track current playing track
var playerGlobal = null;
var playingId = null;
function play() {
var id = '1';
//Resume playing if the same song is hit
if (playerGlobal !== null && id === playingId) {
console.log("-- using old player");
playerGlobal.play();
return;
}
//New player on a new song
var url = '/tracks/309689093';
getPlayer(url)
.then(player => {
if (playerGlobal) playerGlobal = null;
playerGlobal = player;
console.log("-- new player created");
playerGlobal.play();
playingId = id;
});
}
function pause() {
playerGlobal.pause();
}
function playNext() {
var id = '2';
//Resume playing if the same song is hit
if (playerGlobal !== null && id === playingId) {
console.log("-- using old player");
playerGlobal.play();
return;
}
//New player on a new song
var url = "/tracks/309689082";
getPlayer(url)
.then(player => {
if (playerGlobal) playerGlobal = null;
playerGlobal = player;
console.log("-- new player created");
playerGlobal.play();
playingId = '2';
});
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<button onClick="play()">play</button>
<button onClick="pause()">pause</button>
<button onClick="playNext()">playNext</button>
<script src="https://connect.soundcloud.com/sdk/sdk-3.1.2.js"></script>
</body>
</html>
I'm not sure why this wouldn't work. One of the ways I was able to make this work was by defining separate player, pause and id variables for both tracks. And then when a track is played after another, I set seek to position 0. Here's it. The problem of course is, this is just for reference, my use case involves many more tracks, and I didn't want to define separate variables for them all, until I'm sure why above code doesn't work and that it is the only way. Any hints are appreciated.

Passing variable between functions in Javascript (Titanium Studio Desktop)

Hopefully I can articulate this problem well. I'm working on a simple audio player in Titanium Desktop. The primary code I'm focused on right now is the following:
function pickMusicFolder (){
var win = Titanium.UI.getCurrentWindow();
win.openFolderChooserDialog(function(folderResponse) {
var file = Titanium.Filesystem.getFile(folderResponse[0]);
var listing = file.getDirectoryListing();
for (var i = 0; i < listing.length; i++) {
if (listing[i].isDirectory()) {
// if the listing is a directory, skip over it
$('#main').append('DIRECTORY: ' + listing[i].nativePath() +
'<br />');
// continue;
}
else {
// otherwise, print the filename of the file to the #main content window
var songOnList = listing[i].nativePath();
var songURL = songOnList.replace(/\\/g,"/");
$('#main ul').append('<li>' + songURL + '</li>');
}
}
});
};
function playSong(songURL){
var currentSong = Titanium.Media.createSound(songURL);
currentSong.play();
this.stopPlayback = stopPlayback;
function stopPlayback(currentSong){
currentSong.stop();
}
}
And then related HTML:
<input type="image" src="img/player_stop.png" name="stopPlayback" onClick="playSong.stopPlayback(songURL)" />
<input type="image" src="img/folder_add.png" name="pickMusicFolder" onClick="pickMusicFolder()" />
Now, both pickMusicFolder and playSong itself work properly. However, stopPlayback isn't working, I'm having a really hard time grasping how to deal with different functions for playing and stopping audio, since the code that's generating the clickable links is completely compartmentalized within the pickMusicFolder function, while the code for stopping playback is only attached to the one separate interface button.
I simply need access to the songURL variable between multiple functions in order to be able to perform operations on one solitary song while it's playing (or not). I'm avoiding resorting to global variables, as I find that to be sort of a cop out.
Anyone have any ideas? Any tips are much appreciated! (Oh, and please ignore my ugly code; was trying a bunch of hack-y solutions before posting.)
Very quickly solution is to store currentSong as property of function playSong:
function playSong(songURL){
var currentSong = Titanium.Media.createSound(songURL);
playSong.currentSong = currentSong; // store curernt playing song as property of function
currentSong.play();
}
playSong.stopPlayback = function() {
if (playSong.currentSong) {
playSong.currentSong.stop();
delete playSong.currentSong;
}
};
when song will be stopped just remove this property that would mean no song are playing now
You should use a closure. See below
var stopPlayback = function() { /* Placeholder, defined later */ };
var playSong = function(songURL){
var currentSong = Titanium.Media.createSound(songURL);
currentSong.play();
// Redefine stopSong in the parent scope
stopPlayback = function(){
// currentSong is available to this function via closure
currentSong.stop();
}
}
HTML Edit
<input type="image" src="img/player_stop.png" name="stopPlayback" onClick="stopPlayback()" />
As a side note, you should not be using HTML attributes to attach JavaScript events. This is a great series on event attachment, but what you really should read is this part. Also, every JS library provides methods for attaching events to make your life easier.

Categories

Resources