Delay execution after eventlistener is triggered - javascript

I'm new to javascript, and have a lot of confusions...
I'm trying to write a script in Tampermonkey which would allow to put the cursor at the end of the input area once "copy" event listener is triggered.
This is the site where I want to apply it: https://voicenotebook.com/#medtrdiv
The original code is:
var input = document.querySelector('#docel');
var textarea = document.querySelector('#docel');
var reset = function (e) {
var len = this.value.length;
this.setSelectionRange(len, len);
};
input.addEventListener('copy', reset, false);
textarea.addEventListener('copy', reset, false);
The problem is that if I click copy, it doesn't copy the text, though it puts the cursor at the end. So I guess the problem is that the function executes too soon.
I wanted to add some delay to this function, but nothing seems to work. So I think the solution would be to delay the function by 100ms once an eventlistener is triggered.
This is what I tried:
var input = document.querySelector('#docel');
var textarea = document.querySelector('#docel');
var reset = function (e) {
var len = this.value.length;
this.setSelectionRange(len, len);
};
textarea.addEventListener('copy', setTimeout(reset, 100), false);
input.addEventListener('copy', setTimeout(reset, 100), false);
I know this probably doesn't make sense at all. I've tried different things also. I've researched many topics about this, but nothing works for me. Can you please help me to figure it out?
Thank you in advance!

There are couple of issues in the code you have written.
id is supposed to be unique on the page.
You intent is to delay the setSelectionRange. This happens when the copy event is triggered. Move the setTimeout to inside the reset function.
Also you if you want to select the text from the start your first argument should be 0.
Your event gets triggered sometime in the future and wrapping reset function reference in the event handler really does nothing other than binding the event handler.
var input = document.querySelector('#docel1');
var textarea = document.querySelector('#docel2');
var reset = function(e) {
var context = this;
setTimeout(function() {
var len = context.value.length;
context.setSelectionRange(0, len);
}, 100);
};
input.addEventListener('copy', reset, false);
textarea.addEventListener('copy', reset, false);
<input id="docel1" />
<textarea id="docel2" />

Related

Stop a portion of Javascript function from auto firing

Is it possible to stop the script and wait for user input before continuing it?
Here is the portion that I need to stop:
var nName = document.getElementById("b1");
nName.innerHTML = "Continue";
document.getElementById("b1").onclick = newName();
So "b1" is a HTML button, I want to stop it after
nName.innerHTML = "Continue";
and wait for user click on the button before firing
document.getElementById("b1").onclick = newName();
using return completely stop the script. Is there any other possible way to do this?
You do not need to stop the script. You cannot.
Pass references to the functions (no paranthesis on the function names) like so:
document.getElementById("b1").onclick = newName;
Example:
function firstClick(){
document.getElementById('b1').innerHTML = "Continue"
// override the first click listener. "firstClick" will no longer be called.
document.getElementById('b1').onclick = newName;
}
function newName(){
document.getElementById('b1').innerHTML = "Good Job!"
}
// listen for first click
document.getElementById('b1').onclick = firstClick
<button id=b1>Click Me!</button>
In order to fully understand what is going on, I do must refer you do Google and Documentation, and most of all - Experimentation.
But in short, in not technical terms.
onclick does nothing on its own. It needs to be told what it does. The browser will do what you tell it to. There can only be 1 function assigned to it. So if you do onclick=a; onclick=b; onclick=c, only c will be called.
If you assign the function name with paranthesis onclick = newName(), what you are doing is you are running the newName() and assigning its return to the onclick. So in this case - nothing. If you do onclick=newName the borwser will automatgically add the paranthesis.
You could even create a 'triaging' function to decide what the next steps are:
function triage(){
var el = document.getElementById('b1');
if (el.innerHTML == "Continue"){
el.innerHTML = 'Good Job!';
}else{
el.innerHTML = 'Continue';
}
}
// listen for first click
document.getElementById('b1').onclick = triage
<button id=b1>Click Me!</button>

Make an onclick event react different when click second time

I have a button on my website, which plays the music when you click on it and in the same time it changes the text inside of the button (to "Go to SoundCloud".)
I want that button (with the new text on it) to redirect to SoundCloud when I click on it.
Now I got both when click first time, which is redirect to SoundCloud and play the track. (plus it changes the text)
Any ideas, how to solve this problem? Thx!
var links = document.getElementById("playButton");
links.onclick = function() {
var html='<iframe width="100%" height="450" src="sourceOfMyMusic"></iframe>';
document.getElementById("soundCloud").innerHTML = html;
var newTexts = ["Go to SoundCloud"];
document.getElementById("playButton").innerHTML = newTexts;
newTexts.onclick = window.open('http://soundcloud.com/example');
};
Use a variable that indicates whether it's the first or second click.
var first_click = true;
links.onclick = function() {
if (first_click) {
// do stuff for first click
first_click = false;
} else {
// do stuff for second click
}
}
Just redefine the onclick after the first function call.
Put the onclick on the button instead of the html.
document.getElementById("playButton").onclick=window.open('http://soundcloud.com/example');
Another option in some cases is to use a ternary operator and a boolean toggle expression:
let btn = document.querySelector('.button');
let isToggledOn = false;
btn.addEventListener ('click', function(e) {
e.target.textContent = !isToggledOn ? 'Is ON' : 'Is OFF';
isToggledOn = !isToggledOn;
});
newTexts.onclick is not creating a function to open a window, it is simply taking the return value of window.open which is being executed right away.
It should look like:
newTexts.onclick = () => window.open('http://soundcloud.com/example');
Also this will not work as intended because newTexts is not the actual DOM element, you need to attach the new onclick on the element and not the array...
But to other answers in this page, the logic is hard to read, so I'd advise to refactor the logic to be more readable.

Javascript detect keyspressed

I am trying to write a program that detects mouse movement and keys pressed conditions.
If run with html, this java script program can detect the mouse moving. I applied a similar strategy and found out that 'keydown' is the correct command to use, yet when I run the program, the keys are not changing the output to "keys are pressed."
var timer;
// mousemove code
var stoppedElement = document.getElementById("stopped");
function mouseStopped() { // the actual function that is called
stoppedElement.innerHTML = "Mouse stopped";
}
window.addEventListener("mousemove", function() {
stoppedElement.innerHTML = "Mouse moving";
clearTimeout(timer);
timer = setTimeout(mouseStopped, 300);
});
//keypress code
var keysElements = document.getElementById('keyPressed');
function keysPressed() {
keysElement.innerHTML = "Keys not Pressed";
}
window.addEventListener("keydown", function() {
keysElement.innerHTML = "Keys Pressed";
clearTimeout(timer);
timer = setTimeout("keysPressed", 300);
});
I have a feeling that my addEventListener for keydown isn't the correct method to use. Which would be the correct js method for checking for keys pressed?
Thanks
You assign a value to keysElements but then later reference keysElement, which would be undefined. Change the assignment from var keysElements = ... to var keysElement = ....
I'm also assuming you have an HTML document that contains elements stopped and keyPressed, e.g.:
<div id="stopped"></div>
<div id="keyPressed"></div>
those elements will be necessary in order for the Javascript to work properly.
Are you doing a keypress in the window or in a text field?
For window, try something like this with jQuery if you like
$(document).keypress(function(e) {
//do something
});
If you want it on an text field, try
$( "#target_input_field" ).keypress(function() {
//do something
});
https://api.jquery.com/keypress/

escape from setInterval at end of game level

I'm writing a game using HTML5 canvas and Javascript. I'm using setInterval to animate the game and check for events at regular intervals. I've written multiple levels for the game, but I can't seem to escape the setInterval when a given level ends in order to start the next one. The code accurately detects when a level is won or lost and successfully clears the interval and renders the button, but the button does not fire.
Adding a button was my latest idea. I've also tried removing the canvas using jQuery and inserting a new one. I've also tried using clearRect on the canvas but it doesn't fire either.
Given that I can't return a value from setInterval, what are my options, if any? Is there another way to accomplish the same thing? Is there a separate error with my code that I've overlooked? Thanks!
Game.prototype.win = function(int) {
clearInterval(int);
var content = "<p style='color:white;'>You win</p><br><button id='next-level'>Next Level</button></menu>"
$('#controls').append(content)
};
Game.prototype.lose = function(int) {
clearInterval(int);
var content = "<p style='color:white;'>You Lose</p><br><button id='next-level'>Start Over?</button></menu>"
$('#controls').append(content)
};
Game.prototype.run = funtion () {
$('#start').click( function () {
$('#controls').empty();
var waveOne = new window.CrystalQuest.Wave(this.X_DIM, this.Y_DIM, this, Game.WAVE_ONE)
var game = this
var int = setInterval( function () {
if (waveOne.step() === "lost" ) {
game.lose(int);
} else if (waveOne.step() === "won") {
game.win(int);
}
waveOne.draw(this.ctx)
}, 20)
this.bindKeyHandlers(waveOne);
}.bind(this));
$('#next-level').click( function () {
$('#controls').empty();
...more code...
});
};
To stop a setInterval() you have to store the returned value from the original call to setInterval() in some persistent location and then call clearInterval() on that value.
Because you declared your interval with var as in var int, it was local only to that method and was not available anywhere else in the code.
There are a number of ways to do that in your code. I would probably suggest storing it as an instance variable like this:
Game.prototype.run = funtion () {
$('#start').click( function () {
$('#controls').empty();
var waveOne = new window.CrystalQuest.Wave(this.X_DIM, this.Y_DIM, this, Game.WAVE_ONE)
var game = this;
this.stop();
this.interval = setInterval( function () {
if (waveOne.step() === "lost" ) {
game.lose(int);
} else if (waveOne.step() === "won") {
game.win(int);
}
waveOne.draw(this.ctx)
}, 20)
this.bindKeyHandlers(waveOne);
}.bind(this));
$('#next-level').click( function () {
$('#controls').empty();
...more code...
});
};
Then, you can make a method that will stop the interval like this:
Game.prototype.stop = function() {
if (this.interval) {
clearInterval(this.interval);
this.interval = null;
}
}
And, change your other methods like this:
Game.prototype.win = function(int) {
this.stop();
var content = "<p style='color:white;'>You win</p><br><button id='next-level'>Next Level</button></menu>"
$('#controls').append(content)
};
Game.prototype.lose = function(int) {
this.stop();
var content = "<p style='color:white;'>You Lose</p><br><button id='next-level'>Start Over?</button></menu>"
$('#controls').append(content)
};
For your event handling issues, if you are destroying and recreating a button, then you will lose any event handlers that were attached to any DOM elements that got replaced.
You have two choices for how to fix it:
After you create the new DOM elements, you can again set the event handlers on the new DOM elements.
You can use "delegated event handling". This attaches the event handlers to a parent DOM object that is itself not replaced. The click event bubbles up to the parent and is handled there. The child can be replaced as many times as you want and the event handler will still work.
See these references for how to use delegated event handling with jQuery:
Does jQuery.on() work for elements that are added after the event handler is created?
jQuery .live() vs .on() method for adding a click event after loading dynamic html
JQuery Event Handlers - What's the "Best" method

Disabled button raises click event after enabling

I'm trying to solve a quite simple task but stuck with JQuery behavior.
I have a HTML button which I disable (add disabled attribute) right after it get clicked to prevent multiple clicks, do something long running (i.e. update DOM with a lot of elements) and enable the button back.
Problem is that even the button is disabled jquery queues all clicks on it and raise my click handler right after it became enabled.
According to JQuery docs it should not raise events for a disabled element.
Bellow is my code. Open JS console, click two times on the button, notice couple 'START --' messages in the console.
<div>
<button id="mybtn" type="button">Find</button>
</div>
var btnElement = $('#mybtn');
btnElement.click(doClick);
function doClick() {
var btnElement = $('#mybtn');
btnElement.attr('disabled', true);
console.log('START --' + Date());
for (var i = 0; i < 70000; i++) {
var el = $('#mybtn');
var w = el.width();
w += 10;
}
console.log('STOP --' + Date());
el.attr('disabled', false);
}
Here is my solution http://jsfiddle.net/DRyxd/8/
var btnElement = $('#mybtn');
var buttonIsBusy = false;
function doHeavyJob () {
console.log('START --' + Date());
for (var i = 0; i < 70000; i++) {
var el = $('#mybtn');
var w = el.width();
w += 10;
}
var timeoutId = setTimeout (unblockTheButton, 0);
console.log('STOP --' + Date());
}
function unblockTheButton () {
console.log('unblockTheButton');
btnElement.attr('disabled', false);
buttonIsBusy = false;
}
function doClick() {
console.log('click', buttonIsBusy);
if (buttonIsBusy) {
return;
}
btnElement.attr('disabled', true);
buttonIsBusy = true;
var timeoutId = setTimeout (doHeavyJob, 0);
}
btnElement.click(doClick);
The issue here is that click-handler function has not finished and browser has not refreshed the DOM. That means that block was not yet applied to the button. You can try pushing your heavy code out of the current context like this:
function someHeavyCode () {
/* do some magic */
}
var timeoutId = setTimeout(someHeavyCode, 0);
This will push your heavy code out of the current context.Letting browser to update the DOM first and only after execute the heavy code.
While the heavy code is executed, browser (at least Chrome) kept the user input queue somewhere in other place (or most-likely other thread). And as soon as heavy code completes - it feeds the DOM with all that queued events. We need to ignore that events somehow. And I use the setTimeout with 0-time again. Letting the browser do what was queued before unblocking the button.
WARNING But be extremely careful with this technique. Browser will still be blocked and if you spawn a lot of such blocks it may hang.
See also this Why is setTimeout(fn, 0) sometimes useful? and consider using webworkers.
P.S. Blocking a user input in such a way is not a good approach, try to rethink what you are going to do, probably there is a better solution for that.

Categories

Resources