How to convert Phaser keyboard event into touch event - javascript

I am following a Fruit Ninja tutorial using Phaser. For the main menu, the author has used
if (this.game_state.game.input.keyboard.isDown(Phaser.Keyboard.SPACEBAR)) {
this.menu_items[this.current_item_index].select();
How would I implement that same logic using touch events so I can use it on my tablet/phone? The rest of the swipe logic is using touch, except for the menu. I was wondering how I could change that.

This looks to me to be more than a just simple "change this to that". The code snippet you've posted makes it look to me that the menu keeps some kind of a current index of which menu item is highlighted (maybe using the arrow keys?).
If your menu is composed of sprites for example, you can attach a touch event to each sprite. Say you have a sprite called exitGameMenuItem in the menu. You need to enable its input and attach an onInputDown event callback to it (and it will work with both mouse and touch).
exitGameMenuItem.inputEnabled = true;
exitGameMenuItem.events.onInputDown.add(function() {
// call the exit game function here
}, this);
Alternatively you can add the callback directly (without wrapping it in a function) like this:
exitGameMenuItem.events.onInputDown.add(this.exitGame, this);
(This assumes that you have an exitGame() function in the same state).

Related

Methods to prevent triggering more than one event-functions in javascript

I have two events, one that triggers on touchstart and one that triggers on the custom event longTouch.
events: {
"touchstart .o_slide": "startDragEventHandler",
"longTouch .overview .o_slide": "slidePreview"
},
Basically, I need to make sure, that only one of the events fires at a time, to make sure, that when the users makes a longTouch to preview a slide (the slidePreview function), then the startDragEventHandler can't also be firing.
Problem is, that if the user longTouches to create e preview, but moves the finger just a little bit, then the drag functions will also initiate, messing up the UX.
Can I write code in one of the functions, that makes sure they other function will return before executing the body? Which different methods applies to this problem?

JavaScript - simulate click on contextmenu

I am trying to create web automation for a site. I am simulating clicks. Usually I add an ID to an element like below and trigger a click using the Chrome developer console and it always works.
p.s: below question is outdated.I am actually trying to click an item from context menu in web.whatsapp.com
<div id="myapp">button1</div>
<script>
$("#myapp").click();
</script>
Or, if that won't work, I use a mousedown event using pure JavaScript like below and it will work smoothly.
function triggerMouseEvent(node, eventType) {
var clickEvent = document.createEvent('MouseEvents');
clickEvent.initEvent(eventType, true, true);
node.dispatchEvent(clickEvent);
}
var targetNode = document.querySelector("#myapp");
triggerMouseEvent(targetNode, "mousedown");
Now my question is: this is not working for the menu that is generated via the jQuery contextMenu plugin.
You can see the demo for contextMenu here, where I am testing the above via the developer console.
So when you right click on the context menu there is a list of menu items listed with ul and li tags.I manually added ID #myapp to one of menu and with below code it is also choosing correct element via developer console.
var targetNode = document.querySelector("#myapp");
targetNode;
But I am unable to trigger a click on that menu item generated via context menu. I was struggling with it for more than 24 hours. I tried all events in JavaScript that I could think of, like mouseup, mousedown, and mouseenter.
You can only click the menu items when the context menu is created, which is done dynamically by the plugin. So, we first need to trigger the menu.
Triggering a native context menu is not possible, as far as I know. Triggering a right click however is possible, you need to use the contextmenu event.
In particular, using $(el).trigger('contextmenu') seems to work fine. This seems to be working because the plugin explicitly supports this. When that is done, we need to trigger a click on the menu item we want to click on.
// first, trigger the context menu
$('.button-that-has-contextmenu').trigger('contextmenu');
// then click the menu item you want to click
// substitute the correct index in `eq(X)` here
$('.context-menu-item:eq(1)').trigger('mouseup');
Because this plugin is not hosted on a CDN, it is not easy to create a snippet here. I have however created a JSFiddle to demo this fully, where I copy + pasted the plugin source into the fiddle.
In the comments, you asked about web.whatsapp.com. I happen to have a WhatsApp account and tested it there. It seems that they are not using the jQuery contextMenu plugin. A $ function is indeed defined, but it appears not to be jQuery, but just a shortcut to document.querySelector.
What their custom context menu code is I don't know, but I did manage to trigger it. Basically, I used the vanilla JS version of the above code and then had to figure out which element to trigger. The latter was easier than I thought. There is a list of chats that is open, .infinite-list-item elements. Their order in the DOM does not match the visual order, but finding the one you want can be done using the browser inspector for example. Given that you have that, you want the .chat element inside of that list item. Say we are interested in the second item, we can select it as follows:
var target = $('.infinite-list-item:nth-child(2) .chat');
You can check in the browser console that you got the right element. Then, fire an event as follows.
var evt = new MouseEvent('contextmenu', {
bubbles: true,
cancelable: true,
view: window,
buttons: 2
});
target.dispatchEvent(evt);
This uses the modern MouseEvent constructor, code is based on this example.
The above will open the context menu in the upper left corner of your browser. You can change the position by passing a clientX and clientY property into the MouseEvent constructor, that represent a position in the window.
When that is done, you can click the items in the context menu. Except you cannot automate this using JavaScript. I peeked at the source and the click handler of those menu items checks if event.isTrusted, meaning that you cannot programmatically trigger a click on them.
You may want to look into using something that can emulate clicks on a lower level, like Selenium 2.0 (WebDriver), or some wrapper around it like WebdriverIO.

Top level mouse event handler

Hm. Maybe Is that I can't figure out the correct search keywords, since I'm new in some areas of javascript.
I am making a two.js based interactive game that comprises dragging stuff around. I need to detect when a mouse is released regardless the elements that are (or aren't) over the canvas. The elements (which are SVG canvas elements) capture the mouse events and prevent the canvas mouse event detection.
Mouse events:
$("#canvas").on("mousemove", function(e){
//do stuff
}).on("mousedown",function(){
//do stuff
}).on("mouseup",function(){
//do stuff
})
So, I can either address a event handler to an object, which will happen only within that object, or address it to the canvas, which will only happen when there is no object over. Appending to both will be unelegant, and will need a major re estructuration in the code that is huge (and I admit, messy);
Example elements that steal the mouse events in the inspector
I hope not to be re-asking. I have looked up and tried for some hours. Thanks!
Ok. So I tried an approach trying to think more javascript wise. Mainly I come from the other OOP school of thought; which is why is hard to unlock my understanding of prototypical objects.
I made a global function named pointer, and other named draggable, which goes in the prototype of each object to be dragged. On this function and over any object over which things could be dragged (the canvas), I attached the functions onRelease and release. When the mouse button is released, it runs its release function, which triggers a pointer.release(). The pointer will have an array of any object being dragged, so when it receives the release, it will trigger the onRelease of each dragged element, passing the object under the mouse. So the object being dragged, at the end receives the event handling object (the one upon which mouse was released).
I hope this method doesn't produce any face-palm. If so, I'd like to learn how it was better.
var pointer={
pos:{x:0,y:0},
dragging:false,
//who will be the object that detected the mouse released. see below
mouseUp:function(who){
for(drg in this.dragging){
//look if the -being-dragged- object does have the function
if(typeof(this.dragging.onRelease)=="function")
this.dragging.onRelease(who);
this.dragging=false;
}
}
}
This is the draggable class. The last part is the only concerning one, the rest is for context purpose:
function Draggable(){
this.main=this;
if(!this.pos)
this.pos={x:0,y:0};
this.dragging=false;
this.hover=false;
this.sprite=false;
this.move=function(pos){
this.sprite.translation.x=pos.x;
this.sprite.translation.y=pos.y;
this.pos=pos;
this.moving();
}
this.moving=function(){}
this.release=function(){
pointer.mouseUp(this);
}
this.init=function(){
//fallback sprite is a circle
if(!this.sprite)
this.sprite=two.makeCircle(0,0,this.rad);
this.move(this.pos);
two.update();
this.elem=$(domElem(this.sprite));
//attach a this to the dom element to make back-scope
this.elem[0].main=this;
//append jquery functions to this object's dom sprite
//pendiente: this may need to go in the pointer object, isn't it?
this.elem.on("mouseenter",function(){
this.main.sprite.fill="rgba(127,127,255,0.7)";
this.main.hover=true;
}).on("mouseleave",function(){
this.main.sprite.fill="rgba(127,127,255,0.3)";
this.main.hover=false;
//avoid pieces stuck to mouse. should this be?
/*this.main.dragging=false;
this.main.release();
pointer.dragging=false;*/
}).on("mousedown",function(){
this.main.dragging=this.main.hover;
pointer.dragging=this.main;
}).on("mouseup",function(){
//the important part is here: it triggers an pointer.mouseUp
this.main.dragging=false;
this.main.release();
pointer.mouseUp(this);
});
}
};
And so the node which will be prototype-blended with the draggable
function Node(ind){
//just to make more console-friendly
this.name="node"+ind;
this.pos=a;
this.ind=ind;
this.par=par;
this.broc;
this.sprite=two.makeCircle(0,0,brocSize*1.2);
this.sprite.addTo(layer[2]);
this.$elem=$(domElem(this.sprite));
main=this;
//these are triggered by their draggable bit
//who, is the subject over which mouse was released
this.onRelease=function(who){
//if(typeof(who)=="Broc")
console.log(who);
this.move(this.broc.pos);
console.log("this:");
console.log(this);
}
//pendant: make the abspos function once an unpack
this.son=false;
this.active=false;
};
This implements a bit of jQuery, which may later be replaced by plain javascript, for prototype and learn purposes I feel more comfortable with jQuery.

Google Maps API event listener priority

I have a map which has a google.maps.event.addListener set on the map object for click events to place a marker on the map. Now I want to add a context menu to the markers, so am creating a custom overlay in the floatPane. Again google.maps.event.addListener is used to add a rightclick event to each marker to position and display the menu.
Once the menu is displayed I want it to be cleared by either a menu item being selected, escape being pressed, or a click on the map.
The menu has a div for each items using jQuery .on to attach a click handler to them, whilst when the menu is displayed a keydown handler is attached to the document using .on to check for escape being pressed. These work as desired but I am unable to find a satisfactory solution to detecting a click on the map.
If I use google.maps.event.addListener on the map object to cancel the menu it works, but also registers with the listener to add a marker and event.stopPropagation() does not affect this. i.e. Cancelling the menu also adds a marker. I believe the Google API triggers the handlers in the order they were added with no way to change the priority.
I have also tried using a jQuery .on handler on the div to which the map is attached. But if I use click or mouseup event it is triggered by the right click which adds the menu. i.e. The menu flashes on screen as it appears but immediately closes. A mousedown event avoids this problem, but obviously still triggers the Google API handler to add a marker. It also registers the click to drag the map to scroll it, which the Google API does not and would be the preferred behaviour.
So it seems to me there are only two solutions to this problem.
One would be to cancel any handlers on the map when the menu is displayed, then re-add them once it closes. This seems unnecessarily excessive though.
The other is to make wrap the content of the handlers in a conditional statement to detect whether the menu is open. This could be either by using a global variable as a flag or adding a status property to the menu's object.
But this would make the code less reusable and go against the point of having separate event handlers. I may as well just put the code to close the menu in the original handler too.
Is there anything I am missing? It does not seem to be too obscure a thing to want to do but the inability to set the priority of handlers in the Google API means either having to code the handlers around each other.
For what it's worth, I believe your first approach (adding and removing handlers) is the "cleanest" (or most elegant?) approach.
If you think of the handlers as only having use/meaning when the menu is present, from a conceptual perspective, there's no need for them to exist when the menu is not visible.
If you bundle the event-wiring into the same function(s) or method(s) that handle the menu, then it becomes a self-contained, re-usable element that doesn't leave any "garbage" behind.
Since I don't have your code in front of you, here's some pseudocode:
function displayMenu() {
$menu.show()
.on('click', function() { /* etc */ });
}
function hideMenu() {
$menu.hide()
.off() // remove ALL event handlers
}
Or, even better, encapsulate it in an object:
var menu = {
show: function() {
// ...
}
hide: function() {
// ...
}
};
Or you could use a jQuery function too (though I generally eschew jQuery when I'm working with a map API, just to keep the number of dependencies low).

Adding Overlay in JavaScript

I am using jsplumb to create a flow-chat. Once the flow-chart creation is over and acknowledged by the user I want to make the created structure un-editable.
For this, have added an overly to the parent that holds the flow-chart, but the mouse clicks are still happening on the flow-chart.
How to - not allow the mouse clicks happen on these components after adding the overlay.
Thank you
Add a handler to the overlay that swallows all click events:
document.getElementById('yourOverlayID').onclick = function () {
return false;
};
Keep in mind that anyone can simply remove the overlay via the console and continue modifying the chart if they desire. You may want to look at the jsplump API for a way to do this instead, such as unbind().

Categories

Resources