Z-Index on Absolute Positioned Element Shows Above Higher Z-Index Elements - javascript

I am trying to create some javascript that when an object is added to the window, a listener listens for any click on the body except for the placed object and removes the object if anywhere on the window except the actual object itself is clicked.
Through numerous unsuccessful attempts, the idea I came up with is to dynamically add an overlay div to the screen called overlay2 (or whatever, it doesnt matter) and then listen for clicks on that div. When I add the overlay to the window and set the zIndex to a higher number than the top element already placed (say 5000) and then set the zIndex of the only object to be placed above the overlay to an even higher number (say 6000), the overlay still appears on top of everything and I cannot select any of the objects in the div I meant to place above it.
var overlayDiv = document.createElement('div');
overlayDiv.setAttribute('id', 'overlay2');
overlayDiv.style.zIndex = '5000';
overlayDiv.style.width = '100%';
overlayDiv.style.height = '100%';
overlayDiv.style.left = '0';
overlayDiv.style.top = '0';
overlayDiv.style.position = 'absolute';
document.body.appendChild(overlayDiv);
$(container).append(template);
template.style.zIndex = '6000';
//Listeners
//Page click listener. Closes the tool when the page is clicked anywhere but inside the parent.
var initialClick = false;
$('body').on('click.editObjectListeners', function(event) {
var target = EventUtility.getTarget(event);
if(initialClick) {
console.log(target.id);
if(target.id == 'overlay2' && target.id != '') {
$(overlayDiv).remove();
finish();
};
}
initialClick = true;
});
I've determined that this has everything to do with the absolute positioning of the overlayDiv. While testing, if I used absolute positioning to place the template and if I append the template object directly to the body like I did the overlayDiv, the zIndex works above the overlayDiv as I originally anticipated. Unfortunately absolutely positioning this element doesn't make much sense for me beyond testing purposes. Is there a way to get around this?

Turns out that z-index can really only be used successfully with absolute placed elements. Therefore the original plan to solve the body click listener will not work. Instead, I decided to use jQuery and listener objects to listen for the click instead. Its a much cleaner solution, I just had to wrap my head around it. You can view my other solution here.

I don't know how much this will help your particular problem, but I just happened to notice that you may have a problem with your use of jQuery's "on()" method.
First off, you are using jQuery version 1.7+ with that, correct?
Unlike "live", I believe that the on() parameters are event, selector, function.
So where you have this:
$('body').on('click.editObjectListeners', function(event) {
var target = EventUtility.getTarget(event);
if(initialClick) {
console.log(target.id);
if(target.id == 'overlay2' && target.id != '') {
$(overlayDiv).remove();
finish();
};
}
initialClick = true;
});
I think you want this:
$('body').on('click.editObjectListeners', [SOME SELECTOR], function(event) {
var target = EventUtility.getTarget(event);
if(initialClick) {
console.log(target.id);
if(target.id == 'overlay2' && target.id != '') {
$(overlayDiv).remove();
finish();
};
}
initialClick = true;
});
Hope that helps in some small way.
Good luck!

Try setting the zIndex before appending it to container.
template.style.zIndex = '6000';
$(container).append(template);

Related

Events not firing inside mapboxgl popup

I'm attempting to do something custom with clusters, where when you click down on a cluster that cannot be expanded further (eg. two objects with the same or very similar location data), a list of what is contained in that cluster should appear, which you can then interact with. I am able to retrieve the objects, create the list and place it on the correct spot on the map, but I am unable to bind any events to those list entries. I have created similar functionality in other parts of the map application, and these seem to be working as expected. Those were not created using the Popup library, so I could try reusing that technique, but the ease of placing popups makes me want to at least try to get those working with events.
I've tried using addEventListener with the click, mouseup and mouseenter events, but nothing is triggering.
How can I use eventListeners in mapbox popups? Is the HTML passed to the popup being sanitized somehow?
I am currently using mapboxgl 1.2.0.
How the popup is generated:
new mapboxgl.Popup({offset:25}).setHTML(generateListPopup(myEntries).outerHTML)
.setLngLat(coords[0])
.addTo($scope.map);
How the content is generated:
function generateListPopup(entries){
var container = document.createElement('div');
container.maxHeight = "240px";
container.overflowY = "auto";
var ul = document.createElement('ul');
ul.style.listStyle = "none";
ul.style.padding = "0";
container.style.background = "blue"; // does set the color to blue
container.addEventListener('mouseenter', function () { // does not trigger
console.log("by golly"); // does not show
});
angular.forEach(entries, function (e) {
var li = document.createElement('li');
var entry = document.createElement('p');
var f = document.createElement('button');
entry.innerHTML = e.name;
entry.style.cursor = "pointer";
f.addEventListener('mouseup', function () {
console.log("hello"); // nope
});
li.appendChild(f);
li.appendChild(entry);
ul.appendChild(li);
});
container.appendChild(ul);
return container;
}
Any help is greatly appreciated!
I just typed out this whole question before figuring it out, so might as well post it in case anyone ever has the same issue:
use setDOMContent on the returned container instead of setHTML on the returned container's outerHTML. I'm guessing the bound events are lost when the elements are serialized using outerHTML.

Iframe nomenucontext - Modify img tag after creation

Hi I am adding a iframe dynamically, It displays an image from a server. I need to disable the context menu for this item. In chrome I can inspect element and if I add oncontextmenu="return false" I do get the wanted affect. However I am unable to do this while the page is generated. Here is an example of the working html.
However I can not reproduce this when i frame is being created. Here is my code.
$(window).scrollTop(0);
$('#secVerify').show();
$("#popWaitLoad").modal("hide");
imgLoading.hide();
dvIframe.empty();
//else load deposit data into interface
$("#spanType").text(deposit.DepositType);
$("#spanReference").text(deposit.Reference);
$("#spanAmount").text("R " + deposit.Amount.toFixed(2));
$("#spanDate").text(deposit.DateCreatedOffsetS);
imageID = deposit.Deposit_Doc_imageID;
var url = imageUrl + '/' + deposit.Deposit_Doc_imageID + '/false';
var imgFrame = document.createElement("iframe");
imgFrame.src = url;
imgFrame.frameBorder = '0';
imgFrame.scrolling = 'no';
imgFrame.width = '100%';
imgFrame.height = '100%';
imgFrame.align = 'middle';
imgFrame.id = "iframeImg";
dvIframe.append(imgFrame);
I have tried examples like.
$("#iframeImage").contents().find("img").attr("oncontextmenu", 'return false');
$('#iframeImage img').on('contextmenu', function (e) {
e.stopPropagation();
// Your code.
return false;
});
But because the img element seems to be only created is done after page load it seems to not work. I know disabling the the menu will not help much and I have explained all the other methods of obtaining the image that is still available but the client really wants this.
I have added nocontextmenu to the body tag and it works everywhere except for the iframe.
So let me clarify, My iframe is working like it should however I would like to disable the right click aka context menu on the specific iframe.
I have used setAttribute to set the attributes and targeted a container to appendChild.
function example(){
var target = document.getElementById('container');
var element = document.createElement('img');
element.setAttribute('src', 'http://gopalshenoy.files.wordpress.com/2011/04/product_demos.jpg');
//element.setAttribute('width','100%');
//element.setAttribute('height','100%');
element.setAttribute('id','iframeImage');
element.setAttribute("oncontextmenu","return false;");
target.appendChild(element);
}
// Demo-Snippet use.
window.onload=example;
<!-- Demo Snippet use -->
<div id="container"></div>
If you build more than one element using this function you might find further issues due to duplicated ID's.
ID's are used to target a specific element 'one of' so if you want to build multiple elements I would recommend giving them unique ID's.
I hope this helps. Happy coding!

Calling a function or focusing a programmatically generated Iframe from an HTML5 canvas

I have an HTML5 canvas controlled and generated by a library of JavaScript files (Craftyjs library mostly).
The canvas generates 2 regular html iframes (same domain) which are stacked on top of each other.
The canvas switches between the two iframes based on calls from the iframes to the parent so I know the code controlling the canvas is easily accessed by their common parent.
I want the parent canvas to either call a function in the iframes to have them focus on a specific element in them or to somehow just have the iframes get focus in general.
I would also prefer to not have to constantly reload/recreate the iframes to get focus.
---- In the Iframe ----
//The head has a function "focusThis()" to focus on an element in the iframe
//body also has onfocus="focusThis();"
//Call the parent to change to the other iframe
parent.changeIframe();
---- In the parent's canvas JS code ----
// I know the function and will hide/show the iframe, but it won't focus
function changeIframe(){
//For now, just switch randomly
MODE = Math.floor(Math.random()*2);
//I am hiding the iframes here, then showing the one that should be seen
Crafty("Game1").each(function () {this.visible = false});
Crafty("Game2").each(function () {this.visible = false});
//Switch the iframes
if(MODE){
//Show this iframe
Crafty("iframe1").each(function () {this.visible = true});
These are things I have tried to get to work
When it doesn't throw an error it doesn't do anything in chrome or FireFox.
(Object [object global] has no method 'focusThis') is a common error
//document.getElementById('iframe1').focus();
//document.getElementById("iframe1").contentWindow.focusThis();
//document.getElementById('iframe1').contentWindow.focusThis();
//var iframe_window = window.frames["iframe1"];
//iframe_window.focus();
//iframe_window.contentDocument.body.focus();
//window.parent.document.getElementById('iframe1').contentWindow.focusThis;
//window.parent.document.getElementById('iframe1').contentWindow.focusThis();
//window.frames["iframe1"].focus();
//window.frames["iframe1"].contentWindow.focus();
//window.frames["iframe1"].contentDocument.focus();
var frame = document.getElementById("iframe1");
if(frame){
alert("yep");
frame.contentWindow.focusThis();
}
}
else{
//....Same thing but for iframe2
}
}
Any help would be greatly appreciated.
I solved my problem after some more fiddling.
This also solved my problem without having to reload the iframe.
I set a timer in the onload function of each iframe that tries to focus itself onto an element in itself based on a parent flag variable (MODE) that tells the iframe if it is supposed to have focus and an internal variable (focused) that tells it to stop trying to focus once it finally has focus again.
Somewhere in the head...
var focused = false;
function focusThis(){
if(parent.MODE && !focused){
document.getElementById("SOME_ELEMENT_I_WANT_FOCUSED").focus();
focused = true;
}
}
Somewhere in onLoad...
var autoFocus =
setInterval(function(){if(parent.MODE && !focused) focusThis()},500);
Somewhere in script below the body...
parent.changeIframe();
changeImage();
if(!parent.MODE){
//This element is just to have a place for focus to go when out of focus
document.getElementById("NA").focus();
focused = false;
}
else
focused = true;

How to find scrollable elements in DOM using XPath?

Basically I need to find all elements on the page that have a scrollbar (vertical or horizontal)
How to tell if an element has a scrollbar and can actually be scrolled? I found this code snippet on jsperf. Is it possible to capture the logic behind the code into and XPath expression? Or are there any other ways to check for scrollbars?
Added:
Just to explain what I'm trying to do: I'm developing VimFx - extension for Firefox. Basically it introduces Vim-style mouseless shortcuts (I know there is Vimperator and Pentadactyl...). One of the features I'd like to implement is to allow the use to select the container that's scrolled with j/k keys. That's why I need to discover all scrollable elements on any given random page.
You can check it with javscript is the overflow of a div is set to "scroll"
document.getElementById(elementId).style.overflow == "scroll";
I would check that on every element tough. If all of your elements are divs' then use this:
var allElements = document.getElementsByTagName("div");
for(index in allElements) {
var element = allElements[index];
if (element.style.overflow == "scroll" || element.style.overflowX == "scroll" || element.style.overflowY == "scroll"){
//do something
}
}
I have now implemented support for discovering scrollable elements in VimFx.
The key to solving this problem is to use the Mozilla-specific events overflow
and underflow.
The concept is:
// The function used for the overflow event:
function(event) {
// `window` is a reference to the current window.
var computedStyle = window.getComputedStyle(event.target)
// `overflow: hidden` can cause overflow, but without a scrollbar, so
// exclude such elements
if (computedStyle && computedStyle.getPropertyValue('overflow') == 'hidden') {
return
}
// `scrollableElements` is a reference to a `WeakMap` object for the
// current window.
scrollableElements.set(event.target)
}
// The function used for the underflow event:
function(event) {
scrollableElements.delete(event.target)
}
// Somewhere else in the code we can now get a suitable `scrollableElements`
// object and check if elements are present in it.
if (scrollableElements.has(someElement)) {
// `someElement` is scrollable!
}

Is there a way to resize an image when live?

E.g. with something akin to firebug, so that you can see how other page elements wrap around it. I don't know of anything like this other than http://makiapp.com/maki , which is useful but not ideal as it doesn't wrap text around the image for example.
Is there a way to re-size images directly on a website?
Not clear on what exactly you want, but I made a fiddle none the less: http://jsfiddle.net/sveinatle/r8J9F/2/
If you want to use this on your own pages, then you can just add the code as is, and add the class resizable to any elements (doesn't need to be images) that you want to be able to resize.
If you want to use it on a page without modifying its source, then you can open Firebug and run the code in the console, just swap out the $('.resizable') selection with something that will match the elements you want to resize. $('*') would apply it to everything.
The code:
var startX,startY,
startW,startH,
$box=null;
$('.resizable').mousedown(function(e){
startX = e.pageX;
startY = e.pageY;
$box = $(this);
startW = $box.innerWidth();
startH = $box.innerHeight();
return false;
});
$('body')
.mouseup(function(){
$box = null;
return false;
})
.mousemove(function(e){
if($box!=null){
$box.innerWidth (startW + e.pageX-startX);
$box.innerHeight(startH + e.pageY-startY);
}
});

Categories

Resources