Click button using Javascript / Speech recognition /tampermonkey - javascript

Currently, I can click any of the 4 buttons in a HTML, using Javascript running in tampermonkey, to select the ID of the button DIV to click. However I want to use speech recognition to click any of the 4 buttons by speaking any of the following words, NONE, ONE, TWO, THREE. I am guessing that the speech script will change the word I speak to text which will be added to a javascript array which will be matched to a DIV ID to be clicked. How to achieve this using javascript. thanks
document.getElementById('radio0').click();
<div class="radio-container">
<div class="col-6">
<button id="radio0">None</button>
</div>
<div class="col-6">
<button id="radio1">One</button>
</div>
<div class="col-6">
<button id="radio2">Two</button>
</div>
<div class="col-6">
<button id="radio3">Three +</button>
</div>
</div>

Come up with an array of button names. Because SpeechRecognition recognizes numbers as the actual numbers (eg 1, not one), use the numeric values rather than their word representations.
var buttonNames = [ 'None', '1', '2', '3'];
I had trouble giving an embedded StackSnippet permission to access the microphone (probably has to do with cross-domain and sandboxing rules), so I put all the code in a userscript. It replaces the page's HTML with your HTML. Click on the document body and the recognition will start. (Open your browser's console to see what it's doing) Then, speak one of the button names. (Make sure Stack Overflow - or whatever domain you run the userscript on - has permission to listen to your microphone)
When the onresult handler is triggered (when you stop speaking), identify the last word in the transcript, and see if it matches any of the buttonNames. If so, querySelectorAll the buttons in the document, and .click() the appropriate button index.
// ==UserScript==
// #name Userscript Speech Recognition
// #namespace CertainPerformance
// #version 1
// #match https://stackoverflow.com/questions/51702275/click-button-using-javascript-speech-recognition-tampermonkey
// #grant none
// ==/UserScript==
document.head.innerHTML = '';
document.body.innerHTML = `
<div class="radio-container" style="height:1000px">
<div class="col-6">
<button id="radio0">None</button>
</div>
<div class="col-6">
<button id="radio1">One</button>
</div>
<div class="col-6">
<button id="radio2">Two</button>
</div>
<div class="col-6">
<button id="radio3">Three +</button>
</div>
</div>
`;
document.addEventListener('click', ({ target }) => {
if (!target.matches('button')) return;
console.log('Click detected: ' + target.outerHTML);
});
var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition
var SpeechGrammarList = SpeechGrammarList || webkitSpeechGrammarList
var SpeechRecognitionEvent = SpeechRecognitionEvent || webkitSpeechRecognitionEvent
var buttonNames = [ 'None', '1', '2', '3'];
var recognition = new SpeechRecognition();
document.body.onclick = function(e) {
if (e.target.matches('button')) return;
recognition.start();
console.log('Listening');
}
recognition.onresult = function(event) {
var last = event.results.length - 1;
var speechText = event.results[last][0].transcript;
console.log('Heard ' + speechText);
const foundButtonIndex = buttonNames.findIndex(buttonName => buttonName === speechText);
console.log(foundButtonIndex);
if (foundButtonIndex !== -1) document.querySelectorAll('button')[foundButtonIndex].click();
}
recognition.onspeechend = function() {
recognition.stop();
}
recognition.onnomatch = function(event) {
console.log('Not recognized')
}
recognition.onerror = function(event) {
console.log('Error ' + event.error);
}
For a more generic solution when the buttons can have any text inside them, and you want to be able to speak the button text and have the appropriate button clicked, you might querySelectorAll all buttons on pageload, map them to an object with keys corresponding to their text content, and then click buttonObj[speechText] if it exists.

You could select the div by checking the innerHTML of the div with the input you get from speech to text. To match the element you could use the answers from this link Javascript .querySelector find <div> by innerTEXT

Related

Change location.href with jQuery

I need to change the location.href of some URLs on my site. These are product cards and they do not contain "a" (which would make this a lot easier).
Here is the HTML:
<div class="product-card " onclick="location.href='https://www.google.com'">
I mean it is pretty simple, but I just cannot get it to work. Did not find any results from Google without this type of results, all of which contain the "a":
$("a[href='http://www.google.com/']").attr('href', 'http://www.live.com/')
Any ideas on how to get this to work with jQuery (or simple JS)?
I cannot change the code itself unfortunaltely, I can just manipulate it with jQuery and JS.
To change the onClick for all the class='product-card', you can do something like this:
// All the links
const links = document.getElementsByClassName('product-card');
// Loop over them
Array.prototype.forEach.call(links, function(el) {
// Set new onClick
el.setAttribute("onClick", "location.href = 'http://www.live.com/'" );
});
<div class="product-card " onclick="location.href='https://www.google.com'">Test</div>
Will produce the following DOM:
<div class="product-card " onclick="location.href = 'http://www.live.com/'">Test</div>
Another option, is to loop over each <div> and check if something like google.com is present in the onClick, if so, we can safely change it without altering any other divs with the same class like so:
// All the divs (or any other element)
const allDivs = document.getElementsByTagName('div');
// For each
Array.from(allDivs).forEach(function(div) {
// If the 'onClick' contains 'google.com', lets change
const oc = div.getAttributeNode('onclick');
if (oc && oc.nodeValue.includes('google.com')) {
// Change onClick
div.setAttribute("onClick", "location.href = 'http://www.live.com/'" );
}
});
<div class="product-card" onclick="location.href='https://www.google.com'">Change me</div>
<div class="product-card">Don't touch me!</div>

Satisfying button click condition to bring up a message in javascript

Sorry in advance if my code is really bad but I am just a beginner. I would like to create a word search puzzle using buttons. When the person is finished finding by clicking on all of the words which I am going to make from buttons I want a message to come up that they have completed the puzzle. So I created a sample here with 4 buttons but I can't seem to get my code to work. I want the message to come up in the div container once all the buttons have been clicked on. Am I on the right track here or way off? Any insight would be so much appreciated!
<html>
<p onclick="myFunction()" id="1" value=false >Button1</p>
<p onclick="myFunction()" id="2" value=false >Button2</p>
<p onclick="myFunction()" id="3" value=false >Button3</p>
<p onclick="myFunction()" id="4" value=false >Button4</p>
<div id="demo">Message displays here if all 4 buttons are clicked</div>
<script>
function myFunction(){
value = true;}
if(p 1){
value = true;}
if(p 2){
value = true;}
if(p 3){
value = true;}
if(p 4){
value = true;}
else{
document.getElementById("demo").innerHTML = "Congratulations you clicked on all of the buttons";}
}
</script>
</html>
You could use the buttons' data attributes to hold their state. (Note: for a more complex project, you probably don't want to do this)
Also, putting JS inline like onclick="myfunction()" is somewhat bad for your code - it encourages globals and makes JS logic harder to follow. So, I've shown an alternative using an IIFE, .querySelectorAll(), and .addEventListener():
// IIFE to keep variables out of the global scope
;(() => {
// NOTE: These are more flexible when they are arrays (thus, Array.from())
const btnEls = Array.from(document.querySelectorAll('.js-button'))
const msgEls = Array.from(document.querySelectorAll('.js-message'))
const handleButtonClick = ({ target: btnEl }) => {
btnEl.disabled = true // optional
btnEl.dataset.toggled = 'true' // using the DOM to hold data
if (btnEls.some(el => el.dataset.toggled !== 'true')) return
msgEls.forEach(el => {
el.textContent = 'Congratulations you clicked on all of the buttons'
})
}
// Our "onclick" equivalent
btnEls.forEach(el => el.addEventListener('click', handleButtonClick))
})()
<button class="js-button">Button1</button>
<button class="js-button">Button2</button>
<button class="js-button">Button3</button>
<button class="js-button">Button4</button>
<p class="js-message">Message displays here if all 4 buttons are clicked</p>
...There's probably a lot of syntax there you don't know but that example should be helpful for those learning from a more modern source. Since you're learning from something that uses older JS syntax, here's some older JS code that works about the same (but isn't as easy to maintain):
// IIFE to keep variables out of the global scope
;(function () {
// NOTE: These are more flexible when they are arrays (thus, Array.from())
var btnEls = Array.from(document.querySelectorAll('.js-button'))
var msgEls = Array.from(document.querySelectorAll('.js-message'))
function handleButtonClick(event) {
var btnEl = event.target
btnEl.disabled = true // optional
btnEl.dataset.toggled = 'true' // using the DOM to hold data
if (btnEls.some(function (el) {
return el.dataset.toggled !== 'true'
})) return
msgEls.forEach(function (el) {
el.textContent = 'Congratulations you clicked on all of the buttons'
})
}
// Our "onclick" equivalent
btnEls.forEach(function (el) {
el.addEventListener('click', handleButtonClick)
})
})()
<button class="js-button">Button1</button>
<button class="js-button">Button2</button>
<button class="js-button">Button3</button>
<button class="js-button">Button4</button>
<p class="js-message">Message displays here if all 4 buttons are clicked</p>
Here was my solution.
var set = []; //decalre an empty array
function myFunction(Id) {
console.log(Id); //the Id will be the vlaue from the button. For example button 1 has an Id of one as passed into by 'myFunction(1)
if (set.indexOf(Id) == -1) { //here we check to see if the Id number is in the array
set.push(Id); //if it's not in the array, we add it in
console.log(set);
console.log("length: " + set.length);
if (set.length > 3) { //if the lengthof the array is greater than three, all 4 buttons have been clicked.
document.getElementById("demo").innerHTML = "Congratulations you clicked on all of the buttons";
}
}
}
<p onclick="myFunction(0)">Button0</p>
<p onclick="myFunction(1)">Button1</p>
<p onclick="myFunction(2)">Button2</p>
<p onclick="myFunction(3)">Button3</p>
<div id="demo">Message displays here if all 4 buttons are clicked</div>
An easier way of doing this is with an event listener that listens to each button click, then makes the value of that button true, and then checks all the buttons to see if they are all clicked and if so output the congrats message
HTML
added classes to each button and removed the onclick function
<html>
<p class='button' id="1" value=false >Button1</p>
<p class='button' id="2" value=false >Button2</p>
<p class='button' id="3" value=false >Button3</p>
<p class='button' id="4" value=false>Button4</p>
<div id="demo">Message displays here if all 4 buttons are clicked</div>
</html>
JS
window.addEventListener('click', (e)=>{
var bool = true
if (e.target.classList.contains('button')) {
e.target.setAttribute('value', "true")
}
buttons = document.querySelectorAll('.button')
for (let i = 0; i < buttons.length; i++) {
console.log(buttons[i].getAttribute('value'))
if (buttons[i].getAttribute('value') == "false") {
bool = false
}
}
if (bool == true) {
document.getElementById("demo").innerHTML = "Congratulations you clicked on all of the buttons";
}
})
I would suggest this as an easy answer to understand javascript and html a little better:
HTML
<html>
<body>
<button onclick="myFunction(event)" name="button1">Button1</button>
<button onclick="myFunction(event)" name="button2">Button2</button>
<button onclick="myFunction(event)" name="button3">Button3</button>
<button onclick="myFunction(event)" name="button4">Button4</button>
<div id="demo">Message displays here if all 4 buttons are clicked</div>
</body>
</html>
JS
var foundButtons = {
button1: false,
button2: false,
button3: false,
button4: false,
};
function myFunction(event) {
foundButtons[event.target.name] = true;
for (var button in foundButtons) {
if (foundButtons.hasOwnProperty(button)) {
if (!foundButtons[button]) {
return
}
}
}
document.getElementById("demo").innerHTML = "Congratulations you clicked on all of the buttons";
}
What this does is that you have an object of the buttons or rather the words that must be clicked to show the message. Now when one of the buttons gets clicked, its property gets set to true. Then it iterates over the properties and ends the function with a return statement, if it finds a false value, which means there is a button that has not been clicked. When the function does not get stopped it will show the success message.

Use XPath or onClick or onblur to select an element and use jQuery to blur this element

*UPDATE:I am new to jQuery, as well as using XPath, and I am struggling with getting a proper working solution that will blur a dynamically created HTML element. I have an .onblur event hooked up (doesn't work as expected), and have tried using the $(document.activeElement), but my implementation might be incorrect. I would appreciate any help in creating a working solution, that will blur this element (jqInput) when a user clicks anywhere outside the active element. I have added the HTML and jQuery/JavaScript below.
Some ideas I have had:
(1) Use XPath to select a dynamic HTML element (jqInput), and then use jQuery's .onClick method to blur a this element, when a user clicks anywhere outside of the area of the XPath selected element.
(2) Use the $(document.activeElement) to determine where the .onblur should fire:
var thisTitle = input0;
var activeElement = $(document.activeElement);
if (thisTitle != activeElement) {
jqInput.hide();
_layout.viewHeaderTextInput.inputOnBlurHandler(canvasObj, jqHeaderText, jqInput);
}
I am open to all working solutions. And hopefully this will answer someone else's question in the future.
My challenge: Multiple elements are active, and the .onblur does not fire. See the image below:
NOTE: The <input /> field has focus, as well as the <div> to the left of the (the blue outline). If a user clicks anywhere outside that <input />, the blur must be applied to that element.
My Code: jQuery and JavaScript
This is a code snippet where the variable jqInput and input0 is created:
var jqInput = null;
if (jqHeaderText.next().hasClass("inline-editable"))
{
//Use existing input if it already exists
jqInput = jqHeaderText.next();
}
else
{
//Creaet a new editable header text input
jqInput = $("<input class=\"inline-editable\" type=\"text\"/>").insertAfter(jqHeaderText);
}
var input0 = jqInput.get(0);
//Assign key down event for the input when user preses enter to complete entering of the text
input0.onkeydown = function (e)
{
if (e.keyCode === 13)
{
jqInput.trigger("blur");
e.preventDefault();
e.stopPropagation();
}
};
This is my .onblur event, and my helper method to blur the element:
input0.onblur = function ()
{
_layout.viewHeaderTextInput.inputOnBlurHandler(canvasObj, jqHeaderText, jqInput);
};
inputOnBlurHandler: function (canvasObj, jqHeaderText, jqInput)
{
// Hide input textbox
jqInput.hide();
// Store the value in the canvas
canvasObj.headingText = jqInput.val();
_layout.updateCanvasControlProperty(canvasObj.instanceid, "Title", canvasObj.headingText, canvasObj.headingText);
// Show header element
jqHeaderText.show();
_layout.$propertiesContent.find(".propertyGridEditWrapper").filter(function ()
{
return $(this).data("propertyName") === "Title";
}).find("input[type=text]").val(canvasObj.headingText); // Update the property grid title input element
}
I have tried using the active element, but I don't think the implementation is correct:
var thisTitle = input0;
var activeElement = $(document.activeElement);
if (thisTitle != activeElement) {
jqInput.hide();
_layout.viewHeaderTextInput.inputOnBlurHandler(canvasObj, jqHeaderText, jqInput);
}
My HTML code:
<div class="panel-header-c">
<div class="panel-header-wrapper">
<div class="panel-header-text" style="display: none;">(Enter View Title)</div><input class="inline-editable" type="text" style="display: block;"><div class="panel-header-controls">
<span></span>
</div>
</div>
</div>
I thank you all in advance.

javascript replace div on each click

The following works to replace a div with a new div...
<div id = "div1" style="display:block" onclick = "replace()"><img src="1.jpg" /></div>
<div id = "div2" style="display:none"><img src="2.jpg" /></div>
<script type = "text/javascript">
function replace() {
document.getElementById("div1").style.display="none";
document.getElementById("div2").style.display="block";
}
</script>
What I can't figure out is how to make this work so when you click div2 it is replaced by div3 and so on.
In other words, I want to replace the div on each click more than just once. What's the best way to go about this? I'm a novice, so not sure if the above is a good start or not.
Thanks!
You could make a more generic function:
function replace( hide, show ) {
document.getElementById(hide).style.display="none";
document.getElementById(show).style.display="block";
}
Then you can create many divs and use the same function:
<div id = "div1" style="display:block" onclick = "replace('div1','div2')">...</div>
<div id = "div2" style="display:none" onclick = "replace('div2','div3')">..</div>
<div id = "div3" style="display:none" onclick = "replace('div3','div4')">..</div>
...
I will suggest you some best practices in this answer:
Use classes instead of the style property, it's way nicer for the browser.
Don't use inline event handler. See the example below.
It's not "replace" you're looking for, it's "toggling".
I suggest you use event bubbling. This way, you add a single event on the container of all your div, and you can work on this.
Alright, now for the example:
HTML:
<div id="container">
<div id="div1">..</div>
<div id="div2" class="hidden">..</div>
<div id="div3" class="hidden">..</div>
</div>
JS:
// Notice how I declare an onclick event in the javascript code
document.getElementById( 'container' ).onclick = function( e ) {
// First, get the clicked element
// We have to add these lines because IE is bad.
// If you don't work with legacy browsers, the following is enough:
// var target = e.target;
var evt = e || window.event,
target = evt.target || evt.srcElement;
// Then, check if the target is what we want clicked
// For example, we don't want to bother about inner tags
// of the "div1, div2" etc.
if ( target.id.substr( 0, 3 ) === 'div' ) {
// Hide the clicked element
target.className = 'hidden';
// Now you have two ways to do what you want:
// - Either you don't care about browser compatibility and you use
// nextElementSibling to show the next element
// - Or you care, so to work around this, you can "guess" the next
// element's id, since it remains consistent
// Here are the two ways:
// First way
target.nextElementSibling.className = '';
// Second way
// Strip off the number of the id (starting at index 3)
var nextElementId = 'div' + target.id.substr( 3 );
document.getElementById( nextElementId ).className = '';
}
};
And of course, the CSS:
.hidden {
display: none;
}
I highly suggest you read the comments in the javascript code.
If you read carefully, you'll see that in modern browsers, the JS code is a matter of 5 lines. No more. To support legacy browsers, it requires 7 lines.

Changing content of a div with Prototype or JavaScript

I have this code :
<div class="box_container">
<div class="box_container_button" id="navigator_1">
Button 1
</div>
<div class="box_container_button" id="navigator_2">
Button 2
</div>
<div class="box_container_button" id="navigator_3">
Button 3
</div>
<div class="box_container_content" style="background-color:#d5d5d5;" id="navigator_content_1">
Content 1
</div>
<div class="box_container_content" style="background-color:#00aeef; display:none;" id="navigator_content_2">
Content 2
</div>
<div class="box_container_content" style="background-color:#4db848; display:none;" id="navigator_content_3">
Content 3
</div>
</div>
If I press on the button with navigator_2, navigator_content_1 must be hidden, and navigator_content_2 showed.
How can I do this with prototype? (Or javascript if it's too stronger). Unfortunatly I can't use jQuery.
Try this
function nav(obj)
{
document.getElementById("navigator_content_1").style.display = "hidden"
document.getElementById("navigator_content_2").style.display = "hidden"
document.getElementById("navigator_content_3").style.display = "hidden"
obj.style.display = "none";
}
Add onclick="nav(this)" to each button element.
Here is my suggestion:
Give the container holding the buttons in ID (for convenience).
Change the IDs of the content containers from navigator_content_1 to navigator_1_content (again, for convenience).
Then all you have to do is to keep a reference to the currently showed content pane and you have to attach a click handler to the container holding the buttons:
// by default, the first panel is shown
var current = document.getElementById('navigator_1_content');
document.getElementById('box_container').onclick = function(event) {
event = event || window.event; // for IE
var target = event.target || event.srcElement; // for IE
current.style.display = 'none';
current = document.getElementById(target.id + '_content');
current.style.display = 'block';
};
This makes use of event bubbling. event.target has a reference to the element that was actually clicked (I don't know if the Safari bug is still present, you might have to traverse the DOM up to find the correct element). This can certainly be improved but should give you a good start. You can easily add new buttons / content panels without having to modify the code.
Here is a DEMO.
To learn more about event handling, I suggest to have a look at the excellent articles at quirksmode.org
This would use prototype and get what you want
$$('.box_container_button').each(function(element) {
element.observe('click', function(event) {
$$('.box_container_content').each(function(element) {
element.setStyle({
'display': 'none'
});
});
$('navigator_content_' + this.id.replace("navigator_", "")).setStyle({
'display': 'block'
});
});
});
http://jsfiddle.net/VENLh/
THIS solution would work even if you add more buttons / contents without changing any line in the javascript (just add the html part!)

Categories

Resources