Adding Overlay in JavaScript - 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().

Related

How to route all mouse input to a specific HTML element?

For my webapp I'm working on a popup element, which is used for menus and similar things. I want to redirect all mouse input on the current page to this popup element when it's visible, however I can get it to work.
I have a tile element which, on mouse hover, shows an image (and highlights the tile). When the user clicks on that image the popup is shown (as a context menu). This works already. When the user moves the mouse outside the tile the hover state is gone, the highlight and also the image disappear, which is not what should happen. Instead I want the visual state unaffected as long as the menu is visible.
So I tried to capture the mouse using Element.setPointerCapture. However, this requires a pointer id, which I don't have. I tried to use onPointerDown on the trigger image, but that didn't do anything.
What's the right way to implement this mouse capture, so that no mouse event is scheduled to any other HTML element, but the popup?
This is what I came up with so far:
private handleTriggerClick = (e: React.MouseEvent): void => {
console.log("mouse");
this.props.trigger?.props.onClick?.(e);
if (this.state.open && this.props.closeOnTriggerClick) {
this.close();
} else if (!this.state.open && this.props.openOnTriggerClick) {
this.open();
e.currentTarget.setPointerCapture(this.pointerId);
}
e.stopPropagation();
};
private handleTriggerPointerDown = (e: React.PointerEvent): void => {
console.log("pointer");
this.pointerId = e.pointerId;
};
where trigger is the image used to show the popup.
I also tried using a mouse move handler on the document, but that didn't work either, probably because of event bubbling where first the deeper elements receive the event before it reaches the document, so it's too late then to prevent default handling or stop propagation.
The Element.setPointerCapture API will only work when the pointer is in its "active button" mode (that is between pointerdown and pointerup or pointercancel).
I guess it's not exactly what you want...
Maybe requestPointerLock would be closer to what you are asking, but it may also be a bit too much (a confirm message would pop-up asking your users if they wish to let your app control their mouse etc.)
So a third way, probably easier, is to append an overlay element with a fixed position that would cover the whole page, you could make it appear also only when your menu is hovered, but without seeing your actual situation, I can only give such a broad advice.

onclick element for an element that is not created yet

I am using the google search API and I want that when you click on an image, this image will be copied to a different location.
I created a fiddle here: http://fiddle.jshell.net/wjewg062/
It works this way: The user types in a term in the input field and images will be displayed. When he/she clicks on one twice it will displayed in the image div.
I put the onClick event listener on to the searchresults div, hence the extra click in the beginning. However, I want it to be displayed on the first click.
Now, if I comment this out
var searchresults = document.getElementById('searchresults');
searchresults.addEventListener("click", function(event){
event.preventDefault();
imageing();
});
it doesn't work. The images will be links. I believe the reason for this is that the results are displayed in gs-image-box and not created yet. I tried calling the imaging function in different other functions like the searchImg or the OnLoad but nothing work.
I thought of using a check if element is clicked function described here Detect if I'm clicking an element within an element
but I think there must be an easier way.
I'm running out of ideas, can anyone give an idea or hint?
Thanks !
The images are dynamically created right? Check out this post Event binding on dynamically created elements?
In short, events are attached to elements upon pageload. so a newly created dynamic element such as the ones that google creates, aren't attached to the event. so google probably has a way to circumvent the whole "you need to load the page to attach events to elements" thing but it requires an extra click. Using the syntax found in the post should help you.
By the way. Using Jquery doesn't really show down your site because it's usually cached in the client's browser.
The info you need is already in your searchresults eventListener. The target of this event will be the image you click, even if you add the event on a div higher in the structure.
A javascript event will by default be dispatched from the top element (window) all the way through the element that received the click, then will go back to the top. Any element that is an ancestor of the element that was clicked will receive the event info, so you can listen on any ancestor, but the target remains the element that was actually clicked.
In your case, by simply passing the target to your imageing() function, you can apply the behaviors you want without any extra manipulations.
One problem you might face, is if user clicks on searchresult but not on an img element. Then you'll have a bug, so you should handle these cases.
Something like this:
var searchresults = document.getElementById('searchresults');
searchresults.addEventListener("click", function (event) {
console.log(event.target, this);
event.preventDefault();
if(event.target.tagName == 'IMG'){
imageing(event.target);
}
});
function imageing(targetImg) {
var imageresult = document.getElementsByClassName('gs-image-box');
var xu = document.getElementById('companylogo');
var imgsrc = targetImg.src;
xu.src = imgsrc;
}
http://fiddle.jshell.net/pwjLrfnt/3/

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).

SAPUI5: Handle click events properly

I am using the SAPUI5 control GenericTile and added both headerImage and click event. When this icon is clicked, the event handler of the tile is triggered first so that I am not able to react on the icon click itself (which should perform another action of course).
var oGenericTile = new sap.suite.ui.commons.GenericTile({
frameType: "TwoByOne",
header: "My HEader",
headerImage: "sap-icon://settings",
tileContent: oTileContent
});
oGenericTile._oImage.attachPress(function(oEvent) {
sap.m.MessageToast.show("Icon has been pressed");
oEvent.cancelBubble();
oEvent.preventDefault();
});
oGenericTile.attachPress(function() {
sap.m.MessageToast.show("I am always triggered first!!! :-(");
});`
Any idea how I can avoid this?
you could e.g. also cancel the event on the tile manually in order to avoid this behavior... you'd just need to track whether the icon has been pressed, see a simplified example on JSBin:
http://jsbin.com/daqifomoge/3/edit
Extending existing controls and overriding methods always bears the potential to break things when the original control gets an update from the developers...
Maybe there's a more elegant way to do it, though.
Best,
Christiane

JavaScript/jQuery: global variable inexplicably being reset, causing menu contraction issue

http://jsfiddle.net/VhjR7/1/
When you click the my lists menu once, it expands, but if you click it again, it doesn't contract.
The problem is listsExpanded being inexplicably reset to false after it is set properly to true by listsExpand(). This causes the check within $('#mid-wrap').delegate() to inappropriately call listsExpand() again, instead of listsContract() like it should.
I can't figure out where or why this reset is occurring, but I think it has something to do with the sticky light blue menu functionality. Before I started removing and replacing this blue bar after scrolling to fix an IE7 bug, there was no issue with expansion/contraction of the little white menu.
Any ideas on what's causing this?
The issue is that the hover event does not support both function arguments (in and out) when used with .delegate(). You will need to use mouseenter and mouseleave instead of hover.
Change to this:
$('#mid-wrap').delegate('#lists', 'mouseenter', function() {
listsMouseIn = true;
}).delegate('#lists', 'mouseleave', function() {
listsMouseIn = false;
});
FYI, if these HTML objects are static, not added dynamically, you could significantly simplify your code by using direct event handlers on that actual objects rather than .delegate and just stopPropagation() when you've processed the click. Then, you'd see the click first in the object and wouldn't be processing the same click multiple times causing you to need all these global flags to keep track of state.
You could also just use the visibility of the object as your detection mechanism for whether the menu is open/closed too rather than a global variable.
The first part of your hover handler (with listsMouseIn = true;) never actually fires so whenever you click, your $('body').mouseUp() handler assumes that you are not hovering the lists button, and therefore hides the menu just for the $('#mid-wrap').delegate(...) handler to show it again milliseconds later.
Replacing
$('#mid-wrap').delegate('ul#lists', 'hover', funcIn, funcOut);
with
$('#mid-wrap').delegate('ul#lists', 'mouseover', funcIn).
delegate('ul#lists', 'mouseout', funcOut);
seems to do the trick.

Categories

Resources