Asking for undo/redo events in html/javascript - javascript

I have an interactive html5 canvas thing where sometimes users will want to undo their actions. I have the logic for doing that implemented, but I'm not sure of how to properly catch the "user wants to undo" event.
Currently, I just listen to keyboard events and interpret "CTRL+Z" as a request-to-undo, like this:
document.addEventListener("keydown", e => {
const Z_KEY = 90;
let isUndo = e.keyCode == Z_KEY && e.ctrlKey && !e.shiftKey;
if (isUndo) {
restore(revision.undo());
}
});
The problem is that the standard shortcut for undo-ing varies by OS, and there are totally orthogonal ways to trigger it (such as shaking your phone).
What I want is to somehow tell the browser that I'm supporting undo, and that it should forward all the crazy OS-specific ways of triggering undo to a method I specify. As things stand now, the browser has no idea the user is doing anything that would involve undo-ing. All the browser sees is a canvas being clicked on and drawn to.
Is there a standard way to ask the browser to catch all the undo events for me? In a future-proof way that keeps working even as vendors invent new undo actions? What about a hacky workaround? Or perhaps there's a library whose focus is to solve this particular problem?
Notes:
This question differs from How to handle undo/redo event in javascript?. That one is asking about catching changes to an element, whereas I always know about any changes because my code is the one performing those changes.
The question Listen to undo/redo event in contenteditable div is also about change-detection instead of implementing undo, and is limited to a particular type of element. I'm willing to use custom elements to make this work.

There's no standard javascript way of hooking things like undo/redo as there is no specific event for them.
Maybe Mousetrap does what you want. It's a library for abstracting keyboard events in javascript and includes a way to do a generic [system modifier]+key hotkey kind of thing.
That said, you'll probably need a button somewhere if you want mobile. (I'm not familiar with the shake-to-undo action. That seems like new age hippy nonsense. =P )

Related

Is it possible to cause a webpage, say a HTML5 game to simulate a key press with Javascript?

I am new to JavaScript and programming in general. I will try to explain what I want to do as best I can.
I have a very similar question to this guy, but I would like to do it in JavaScript as I somewhat know how to use it. Need to send key presses to a webpage(html5 game)
Basically I want to be able to send key presses and/or mouse clicks I.E. WASD or up, down, left, and right. So I could effectively automate a task.
As a side note to the main question, is there a way to show JavaScript events that are happening in a game, so that it could react to them?
If it is possible how would I get the script to effect the webpage, and what would I need to know to do it?
Thanks!
Assuming you're fine with using jQuery, as indicated in the comments, you could so something like this:
function simulateKey(char) {
var e = $.Event("keydown", { keyCode: char.charCodeAt(0)});
$("body").trigger(e);
}
Also assuming you want a keydown event and it's triggered on the body (you can change the body to whatever selector).
Your keyboard/mouse event listeners should be calling different functions instead of responding to the event directly. Generally speaking, event listeners should extract information from the event and pass it to methods to handle state changes. So your 'bot' should call the functions that handle the state changes directly instead of faking a key press.

How I can know if a click event is counterfeit?

How I can know if a click event was generated by the user? (They used the mouse).
The opposite would be a click event triggered by a piece of JavaScript.
Think in a JavaScript library that displays advertisements. You wont want that anyone who uses the library fool you.
You need to make sure that the event is not forged.
Client code can never be trusted by the server. Anyone can open up their browser console and totally change the code.
You might be able to do different things to confuse robots or automated scripts, but you're helpless if you are trying to prevent a forgery that targets your site specifically.
To be honest, ANY attempt to making this tamper-proof will fail unless you follow these pretty simple advises:
don't do anything client-side, this problem family is a cognate of security, so you want to do everything server-side without relying on anything on the client;
don't trust the input you receive, doubt about its origin (e.g. user-agent, cookies, HTTP request, ecc. may all be forged into a key that perfectly fits your keyhole);
you do not really want to detect a mouse click, what you want is discriminate between human and machine, so use common techniques for that problem;
a CAPTCHA or other task that is currently next-to-impossible to solve for machines allows you to distinguish a real human from a machine.
That said, the easiest for your use case (advertisement) is a floating button embedded in an image that randomly changes position. On click you send the coordinates and a code that you use server-side to reconstruct the position of the button and thus if the coordinates are inside the buttons boundaries.
A machine will send wrong (random) coordinates with the code and server-side you will discriminate it because the click was not inside the boundaries.
This solution obviously can be enhanced:
smaller button on larger image (lower probability to have a lucky "false positive");
move the button over time (this requires an SWF plugin or HTML5 canvas);
avoid contrast that may be exploited to find the button in the image (e.g. a red button over a blue sky).
All you have to do is go to any website that has advertisements and look what they do: SWF plugins with micro-games that entice you to click it.
BTW: I don't like advertisements on web pages so maybe it's better you don't even implement that stuff...
You can check if the string 'Mouse' is found within the string representation of e.toString():
document.addEventListener('click', function(e){
console.log(e.toString().indexOf('Mouse') !== -1)
});
If the event was generated by code then e.toString() returns [object Event], but if it was a real mouse event it would return [object MouseEvent]. All I am doing is checking whether 'Mouse' is in that string to determine if it was indeed a real mouse click.
You might want to try like this:
document.addEventListener('click', function(e){
var w=[]["filter"]["constructor"]("return this")();//returns window, thanks to JSFuck
console.log(e instanceOf MouseEvent && e.view==w && e.srcElement && e.srcElement.ownerDocument.parentWindow==w && e.target && e.target.ownerDocument.parentWindow==w);
});
It checks if it is an instance of the MouseEvent object, then checks if the window is the same, the e.srcElement exists and if it is in the same window and if e.target exists and is in the same window.

Trigger global touch/click events in javascript without specific target

Since I'm searching for an answer for a while now and I'm still without any clue, I'll just describe my actual problem:
I need to build up automated touch/mouse gestures (tap,drag,pinch...) which I can fire on a webpage in order to test touch frameworks and their performance. Thus I want to trigger "global" touch/mouse events on a webpage with JavaScript without dispatching them from a specific element.
Does anyone know how I could achieve this or how these events are delegated in general?
If you need this just for the sake of emulating mobile touch actions on your browser, Chrome already has a tool for that. Check out Mobile Emulation.

chrome extension force mouse move

I am writing a chrome extension that records your actions like ( mouse click, keyboard keyup ). The idea of the extension is to help me and my colleagues to reduce the boring testing of our web based project. I made it to record the events and store it on the dev server as mysql so i can use or share to them. But the problem is replaying the saved actions.
So how if there is a way to force mouse move, mouse click events. Can it be done from flash,java or something like that.
PS. The project is Extjs but i want to make the extension useful for developer using other frameworks and publish it.
Consider using Selenium for this. It has support for many languages, and you can script your whole test with it. You can for example set it to click on an element, wait for something to happen or fill text boxes.
Imagine some random website controlling your mouse ... not cool, is it? (That's why you cant force mousemove via javascript)
However, you can trigger clicks on elements. To achieve that, you need to save the event(mouse-over|out/(dbl)click/whatever) and the according element (in the eventfunction: this). That should be sufficient to simulate theworkflow.
jQuery-Example:
$('#item').click();
$('#item').trigger('click');
vanilla javascript:
document.querySelector("#item").click();

what is the best practice to do the following using jquery/javascript?

So I am just trying to add some functions to hover. the below does about the same thing except the one with the for loop i have the target stored in an array. I actually have a few questions.
is this the correct use of stopPropagation?
what's the best practice for doing something like this?
which one of the below method is faster and uses less resources?
I know I can use hover() but I used bind because I thought it is faster, is my thinking correct?
thank you
for (var i in slides) {
$(slides[i].el).bind( {
mouseenter: function (event) {
event.stopPropagation();
// do something
},
mouseleave: function (event) {
event.stopPropagation();
//do something
}
});
}
$("#vehicleSlides .vehicleAreas").bind( {
mouseenter: function (event) {
event.stopPropagation();
// do something
},
mouseleave: function (event) {
event.stopPropagation();
//do something
}
});
1 - is this the correct use of stopPropagation
If you wish to stop the event bubbling up the DOM tree, then yes.
2 - what's the best practice for doing something like this
Personally, I prefer the jQuery selector followed by methods, but this is just a preference. The best practice is whatever style you and your team all agree upon and use consistently.
3 - which one of the below method is faster and uses less resources
In practical terms, there will be next to no difference between the two.
4 - I know I can use hover() but I used bind because I thought it is faster, is my thinking correct
The jQuery hover method is shorthand for the bind to mouseenter and mouseleave events, so there will be one extra function call using hover, however there will be almost no difference in performance.
Best practice would make consistently correct functionality the highest priority, so it depends on whether or not the event should be seen or heard by a parent node once processed.
That depends on your design. For example, in a "window"-like object that you want to be able to drag around, you could either A. attach a mouse handler to the entire window, or B. attach a listener to a child "background" object to detect the mouse down event to begin dragging.
If you choose design B., then you have to make sure labels and other objects you don't want to receive mouse events have mouse events disabled (in Flash [AS3] set mouseEnabled and mouseChildren to false; not sure about JavaScript). One con of this design is that it would prevent any object in the U.I. from passively processing or modifying event behavior in the bubbling phase, because any interception in the capture phase would prevent it from reaching the background in the first place. One pro of this design is that by allowing the event to bubble, you could have monitors and other global effects processing mouse clicks at higher levels.
On the other hand, if you choose design A., then you don't have to worry about making child objects transparent to the mouse (an event on a label would still bubble up to the window container itself), but instead you have to make sure that event propagation on child objects like buttons is stopped once the event is handled so that they don't reach the window handler at the top of the hierarchy. It really depends on how you want it to function, and a hybrid approach is probably best.
You can have this down to a design science to the point where the "design" isn't a design at all, but a complex truth known to be true scientifically.
Any browser optimization of this system would involve keeping track, during the capture phase, of which parent nodes had bubble-phase event handlers attached for the event type. If for example it entered the target/bubbling phase knowing that no parent nodes had handlers, it could skip the entire bubbling phase, or jump directly to nodes known to have handlers. That's poor design however, IMO, because you might want to attach new handlers to parent nodes at any time during capture or bubbling, or you may want to move a node to another parent to try to cause the event to bubble up a different parent chain. Try it and see how it behaves in different browsers. There's bound to be huge inconsistency like anything else involving HTML rendering and event processing, in terms of both behavior and performance :P
There's probably not much difference between bind and hover. Work avoidance is always a good thing to consider but 1-3 more function calls to get to an event handler isn't going to put a dent in a modern JIT's performance.
You are not invoking stopPropagation incorrectly but if you're doing it for no particular reason other than bubbling making you uncomfortable or because you're afraid of triggering something else by accident, then yes, you are doing it wrong.
The first rule of UI work should always be:
DON'T DO ANYTHING YOU DON'T NEED TO DO
Examples:
Don't solve problems you don't have yet.
Don't do anything "just in case," because that means you don't know what's actually happening and you really need to understand what your stuff actually does and how it works before you call anything done in UI.
Don't stop people from using your UI differently than anticipated. e.g. validating HTML format and throwing errors when somebody tries to make something you wrote work a little differently. What are you, running a customer support line? It helps no one/serves nothing. What does it matter if they prefer a more semantically correct unordered list to a pile of divs?
But on stopProp specifically, if you must use it (and it can solve some problems very elegantly so never say never) try to only hit endpoint nodes with it so other things can be added to the same container without losing the benefits of bubbling. Yes, benefits I say. Don't fear bubbling. Events moving back up the ancestor line are only likely to trigger other UI events if your HTML is a complete disaster (it should be nothing but containers all the way back up to the body, right?).
Also if you can just verify that you have the right target element in the handler before taking action, do that instead of stopProp. But cripes it pisses me off when people add return false and e.stopPropagation to every single UI handler they write. Especially when they themselves pick up the event from a container that encompasses much more than the active element in question.
So don't do that. We might work in the same office some day and I can be whiny and insufferable and I'll sabotage your cheesecake.

Categories