jquery draggable and droppable - stop inheriting parents css - javascript

This is hard to explain but I have draggable and droppable elements on my page. Some of the droppable elements have draggable elements inside them already but most don't.
When you hover over the droppables a back-ground image appears so you know your hovering over it. However, when you move a draggable into another droppable, now hovering over the newly moved draggable a background image appears in the OLD droppable which used to contain it.
if you look here you can see my problem: - try moving one of the yellow boxes around and then hover over it after you've moved it. The background image appears in the initial position.
http://liquidlizard.net/
Can anyone tell me how to sort this out? I'd appreciate it :)
EDIT here's some of the code I'm using
<div id="row-2col0" class="empty"><div class="position"><a href class="bookmark" target="_blank"></a></div></div>
<div id="row-2col1" class="empty"><div class="position"></div></div>
<div id="row-2col2" class="empty"><div class="position"></div></div>
JS:
$('.draggable').draggable({start: function() {var initialposition = ???}});
$('.droppable').droppable({drop: handleDropEvent, accept:'.bookmark'});
function handleDropEvent( event, ui ) {
}
CSS:
.empty:hover{background-image:url(../img/tilehover.png);}
Basically everything has a class 'empty' which shows the background image when the item is hovered over.

The problem is that your dragged element is a child of the div it came from, so when you assign the empty class to that element, because your dragged element is a child of that didv, your CSS rule, .empty:hover comes into play.
To avoid this problem, put a second div inside of each box, like this:
Add a new div inside of the div with the class empty.
So this line: (and all the ones like it)
<div id="row-2col3" class="empty"><div class="position"></div></div>
Changes to this: (I broke it down to make it easier to read.)
<div id="row-2col3" class="empty">
<div class = "elementContainer"> <!-- This is added..-->
<div class = "wordHolder"></div> <!-- ...............-->
</div> <!--................-->
<div class="position"></div>
</div>
Then add this to your CSS:
.elementContainer {
position:relative;
}
.wordHolder {
position:absolute;
width:65px;
height:65px;
}
And finally, replace your CSS rule .empty:hover with elementContainer:hover and it should work!
How and Why it works
To quote w3schools,
An absolute position element is positioned relative to the first parent element that has a position other than static. If no such element is found, the containing block is <html>:
So using .elementContainer with the relative attribute set serves as our container for our absolutely positioned elements with the class wordHolder. And they do not get in the way because they are removed from the regular flow and all the other elements act as if it did not exist.
You can read more about positioning elements here: http://www.w3schools.com/css/css_positioning.asp
Hope this helps!

Related

click events and css attributes not attaching to divs, possibly because divs are "mostly padding"

I'm trying to attach click events to a couple of divs. One of which has no height or width, just borders. Maybe it's just the browser, but the clicks are being triggered very unreliably. Even the css parameters .class:hover{} isn't really working.
$("body").on("click", "._tlh_dropdown, ._tlh_dropdown *", function (event) {
isn't working when the a div contained by ._tlh_dropdown is clicked. And the div ._tlh_dropdown_close_button is not removing it's parent div when clicked, nor turning a darker shade of gray when it is hovered over. What am I doing wrong here? I assume it has to do with the click event not being applied to the areas of the divs that are "just padding". Is this the case? How can I overcome this?
http://jsfiddle.net/UrNUM/7/
This is happening because the underline element that is a div element overlaps the elements in question . As you know div is a block level element.
One work around is to to set the 2 divs to inline-block
._tlh_dropdown_input_container, ._tlh_dropdown{
display: inline-block;
}
Check Fiddle for hover
If you want the div to be block level as it is then you can also play around with the z-index
._tlh_dropdown_close_button{
z-index: 1;
}
This will make sure the close div is always on top of the underlying container
UPDATE
2 events fire for every click event on the page..
So the content is not shown when u click on the image because of this condition
if ($targ.hasClass('_tlh_dropdown')
|| $targ.closest('._tlh_dropdown_content').length)
return;
This happens because the e.target when you click on the arrow image will be the arrow and not the tlh_dropdown .. So it fails on this condition and moves to the next statement where the content is removed.
Change it
if ($targ.hasClass('_tlh_dropdown')
|| $targ.closest('._tlh_dropdown').length
|| $targ.closest('._tlh_dropdown_content').length)
return;
It should work..
Check Fiddle
Also I feel the same can be accomplished with a lot less code. You can always have the HTML already built and then hide or show based on the condition.
Regarding the close button, if you hover "_tlh_dropdown_input_container" in the inspector, you can see that it overlaps the bottom part of the X button. That's why the hover/click event on the X is not caught below the middle of it.
Regarding the down arrow, just wrap it with another DIV on which you'll add the events. You can achieve minimal HTML by using a single DIV and adding the arrow to it using CSS :before or :after.

Apply gradient over page without hindering user interaction [duplicate]

I have a div that has background:transparent, along with border. Underneath this div, I have more elements.
Currently, I'm able to click the underlying elements when I click outside of the overlay div. However, I'm unable to click the underlying elements when clicking directly on the overlay div.
I want to be able to click through this div so that I can click on the underlying elements.
Yes, you CAN do this.
Using pointer-events: none along with CSS conditional statements for IE11 (does not work in IE10 or below), you can get a cross browser compatible solution for this problem.
Using AlphaImageLoader, you can even put transparent .PNG/.GIFs in the overlay div and have clicks flow through to elements underneath.
CSS:
pointer-events: none;
background: url('your_transparent.png');
IE11 conditional:
filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='your_transparent.png', sizingMethod='scale');
background: none !important;
Here is a basic example page with all the code.
Yes, you CAN force overlapping layers to pass through (ignore) click events.
PLUS you CAN have specific children excluded from this behavior...
You can do this, using pointer-events
pointer-events influences the reaction to click-, tap-, scroll- und hover events.
In a layer that should ignore / pass-through mentioned events you set
pointer-events: none;
Children of that unresponsive layer that need to react mouse / tap events again need:
pointer-events: auto;
That second part is very helpful if you work with multiple overlapping div layers (probably some parents being transparent), where you need to be able to click on child elements and only that child elements.
Example usage:
.parent {
pointer-events:none;
}
.child {
pointer-events:auto;
}
<div class="parent">
I'm unresponsive
I'm clickable again, wohoo !
</div>
Allowing the user to click through a div to the underlying element depends on the browser. All modern browsers, including Firefox, Chrome, Safari, and Opera, understand pointer-events:none.
For IE, it depends on the background. If the background is transparent, clickthrough works without you needing to do anything. On the other hand, for something like background:white; opacity:0; filter:Alpha(opacity=0);, IE needs manual event forwarding.
See a JSFiddle test and CanIUse pointer events.
I'm adding this answer because I didn’t see it here in full. I was able to do this using elementFromPoint. So basically:
attach a click to the div you want to be clicked through
hide it
determine what element the pointer is on
fire the click on the element there.
var range-selector= $("")
.css("position", "absolute").addClass("range-selector")
.appendTo("")
.click(function(e) {
_range-selector.hide();
$(document.elementFromPoint(e.clientX,e.clientY)).trigger("click");
});
In my case the overlaying div is absolutely positioned—I am not sure if this makes a difference. This works on IE8/9, Safari Chrome and Firefox at least.
Hide overlaying the element
Determine cursor coordinates
Get element on those coordinates
Trigger click on element
Show overlaying element again
$('#elementontop').click(e => {
$('#elementontop').hide();
$(document.elementFromPoint(e.clientX, e.clientY)).trigger("click");
$('#elementontop').show();
});
I needed to do this and decided to take this route:
$('.overlay').click(function(e){
var left = $(window).scrollLeft();
var top = $(window).scrollTop();
//hide the overlay for now so the document can find the underlying elements
$(this).css('display','none');
//use the current scroll position to deduct from the click position
$(document.elementFromPoint(e.pageX-left, e.pageY-top)).click();
//show the overlay again
$(this).css('display','block');
});
I currently work with canvas speech balloons. But because the balloon with the pointer is wrapped in a div, some links under it aren't click able anymore. I cant use extjs in this case.
See basic example for my speech balloon tutorial requires HTML5
So I decided to collect all link coordinates from inside the balloons in an array.
var clickarray=[];
function getcoo(thatdiv){
thatdiv.find(".link").each(function(){
var offset=$(this).offset();
clickarray.unshift([(offset.left),
(offset.top),
(offset.left+$(this).width()),
(offset.top+$(this).height()),
($(this).attr('name')),
1]);
});
}
I call this function on each (new) balloon. It grabs the coordinates of the left/top and right/down corners of a link.class - additionally the name attribute for what to do if someone clicks in that coordinates and I loved to set a 1 which means that it wasn't clicked jet. And unshift this array to the clickarray. You could use push too.
To work with that array:
$("body").click(function(event){
event.preventDefault();//if it is a a-tag
var x=event.pageX;
var y=event.pageY;
var job="";
for(var i in clickarray){
if(x>=clickarray[i][0] && x<=clickarray[i][2] && y>=clickarray[i][1] && y<=clickarray[i][3] && clickarray[i][5]==1){
job=clickarray[i][4];
clickarray[i][5]=0;//set to allready clicked
break;
}
}
if(job.length>0){
// --do some thing with the job --
}
});
This function proofs the coordinates of a body click event or whether it was already clicked and returns the name attribute. I think it is not necessary to go deeper, but you see it is not that complicate.
Hope in was enlish...
Another idea to try (situationally) would be to:
Put the content you want in a div;
Put the non-clicking overlay over the entire page with a z-index higher,
make another cropped copy of the original div
overlay and abs position the copy div in the same place as the original content you want to be clickable with an even higher z-index?
Any thoughts?
I think the event.stopPropagation(); should be mentioned here as well. Add this to the Click function of your button.
Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
Just wrap a tag around all the HTML extract, for example
<a href="/categories/1">
<img alt="test1" class="img-responsive" src="/assets/photo.jpg" />
<div class="caption bg-orange">
<h2>
test1
</h2>
</div>
</a>
in my example my caption class has hover effects, that with pointer-events:none; you just will lose
wrapping the content will keep your hover effects and you can click in all the picture, div included, regards!
An easier way would be to inline the transparent background image using Data URIs as follows:
.click-through {
pointer-events: none;
background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
}
I think that you can consider changing your markup. If I am not wrong, you'd like to put an invisible layer above the document and your invisible markup may be preceding your document image (is this correct?).
Instead, I propose that you put the invisible right after the document image but changing the position to absolute.
Notice that you need a parent element to have position: relative and then you will be able to use this idea. Otherwise your absolute layer will be placed just in the top left corner.
An absolute position element is positioned relative to the first parent
element that has a position other than static.
If no such element is found, the containing block is html
Hope this helps. See here for more information about CSS positioning.
You can place an AP overlay like...
#overlay {
position: absolute;
top: -79px;
left: -60px;
height: 80px;
width: 380px;
z-index: 2;
background: url(fake.gif);
}
<div id="overlay"></div>
just put it over where you dont want ie cliked. Works in all.
This is not a precise answer for the question but may help in finding a workaround for it.
I had an image I was hiding on page load and displaying when waiting on an AJAX call then hiding again however...
I found the only way to display my image when loading the page then make it disappear and be able to click things where the image was located before hiding it was to put the image into a DIV, make the size of the DIV 10x10 pixels or small enough to prevent it causing an issue then hiding the containing div. This allowed the image to overflow the div while visible and when the div was hidden, only the divs area was affected by inability to click objects beneath and not the whole size of the image the DIV contained and was displaying.
I tried all the methods to hide the image including CSS display=none/block, opacity=0, hiding the image with hidden=true. All of them resulted in my image being hidden but the area where it was displayed to act like there was a cover over the stuff underneath so clicks and so on wouldn't act on the underlying objects. Once the image was inside a tiny DIV and I hid the tiny DIV, the entire area occupied by the image was clear and only the tiny area under the DIV I hid was affected but as I made it small enough (10x10 pixels), the issue was fixed (sort of).
I found this to be a dirty workaround for what should be a simple issue but I was not able to find any way to hide the object in its native format without a container. My object was in the form of etc. If anyone has a better way, please let me know.
I couldn't always use pointer-events: none in my scenario, because I wanted both the overlay and the underlying element(s) to be clickable / selectable.
The DOM structure looked like this:
<div id="outerElement">
<div id="canvas-wrapper">
<canvas id="overlay"></canvas>
</div>
<!-- Omitted: element(s) behind canvas that should still be selectable -->
</div>
(The outerElement, canvas-wrapper and canvas elements have the same size.)
To make the elements behind the canvas act normally (e.g. selectable, editable), I used the following code:
canvasWrapper.style.pointerEvents = 'none';
outerElement.addEventListener('mousedown', event => {
const clickedOnElementInCanvas = yourCheck // TODO: check if the event *would* click a canvas element.
if (!clickedOnElementInCanvas) {
// if necessary, add logic to deselect your canvas elements ...
wrapper.style.pointerEvents = 'none';
return true;
}
// Check if we emitted the event ourselves (avoid endless loop)
if (event.isTrusted) {
// Manually forward element to the canvas
const mouseEvent = new MouseEvent(event.type, event);
canvas.dispatchEvent(mouseEvent);
mouseEvent.stopPropagation();
}
return true;
});
Some canvas objects also came with input fields, so I had to allow keyboard events, too.
To do this, I had to update the pointerEvents property based on whether a canvas input field was currently focused or not:
onCanvasModified(canvas, () => {
const inputFieldInCanvasActive = // TODO: Check if an input field of the canvas is active.
wrapper.style.pointerEvents = inputFieldInCanvasActive ? 'auto' : 'none';
});
it doesn't work that way. the work around is to manually check the coordinates of the mouse click against the area occupied by each element.
area occupied by an element can found found by 1. getting the location of the element with respect to the top left of the page, and 2. the width and the height. a library like jQuery makes this pretty simple, although it can be done in plain js. adding an event handler for mousemove on the document object will provide continuous updates of the mouse position from the top and left of the page. deciding if the mouse is over any given object consists of checking if the mouse position is between the left, right, top and bottom edges of an element.
Nope, you can't click ‘through’ an element. You can get the co-ordinates of the click and try to work out what element was underneath the clicked element, but this is really tedious for browsers that don't have document.elementFromPoint. Then you still have to emulate the default action of clicking, which isn't necessarily trivial depending on what elements you have under there.
Since you've got a fully-transparent window area, you'll probably be better off implementing it as separate border elements around the outside, leaving the centre area free of obstruction so you can really just click straight through.

Draggable element disappears in div

Trying to create a draggable div, but instead of it dragging into the droppable div and snapping into it, the draggable div just disappears when dragged. As seen here the div begins to disappear and still appends. I thought it might be a containment issue
$('.sorting').draggable({containment: 'parent', cursor:'pointer'});
When I changed the containment to parent from window the draggable div stays within as seen here. Not understanding why the draggable div disappears and does not enter the droppable the box like I want. I am sure there is something I am not understanding or seeing that probably needs to be pointed out. I would also be very appreciative to know why this happens and any other tips one may have.
Your draggable ul element disappears because of the overflow attribute of the .mousescroll class.
Replacing the css with
.mousescroll{
float: left;
}
.mousescroll:hover {
}
fixes your problem.

Javascript/jQuery mouseover and mouseout Event Listeners

Not sure how to solve an issue I'm having at the moment. I'm building a Javascript and PHP powered image gallery. The basic div structure is that I have a div that contains the gallery as a whole, one for the image being displayed, and a div containing a "previous button", and another containing a "next button."
The next/previous buttons are positioned on the left/right side at the bottom of the image container div (the gallery container is set to relative position, the button divs to absolute). By default they are made non-visible using jQuery, and become visible when you hover over the image container div. The issue I'm having is when you hover over the container div, and then over the arrows, the transition effect re-plays and I'm not sure how to fix that using HTML/CSS/JS. My current structure for the divs is
<div id="galleryContainer">
<div id="imageContainer">
<img src="img" />
</div>
<div id="leftArrow"></div>
<div id="rightArrow"></div>
</div>
How do I make it so my fadein/out effect stops acting all bugged when I hover over the next/prev buttons? I've tried a bunch of combinations of using "onmouseover" listeners when I establish the div, to using jQuery listeners, to trying to change up the hierarchy of the drivs. Any help would be appreciated!
Edit: Here is my current jQuery code of what I'm trying to do:
$(document).ready(function(){
$("#imageContainer").mouseover(function()
{
$("#leftArrow").fadeIn();
$("#rightArrow").fadeIn();
});
$("#galleryContainer").mouseout(function()
{
$("#leftArrow").fadeOut();
$("#rightArrow").fadeOut();
});
});
When I put the buttons inside of the imageContainer it still does the fade bug/effect.
You probably want to use $.mouseleave and $mousenter A problem is that the mouseout and mouseover events bubble. Then, your handlers are called when those events are fired on #galleryContainer when it happens in any of its descendants
http://jsfiddle.net/z2Y8a/20/
$("#imageContainer").mouseenter(function() {
$("#leftArrow").fadeIn();
$("#rightArrow").fadeIn();
});
$("#galleryContainer").mouseleave(function() {
$("#leftArrow").fadeOut();
$("#rightArrow").fadeOut();
});
It would not flicker if your arrows are inside of your image container. Or maybe put the show arrow effect in the main gallery container. Basically when your mouse laves the image container, it will trigger the mouseout. When I say leave I mean in code sense, visually it does not leave because you have it positioned differently but in code sense, your mouse left the image container and entered the arrow containers
This is how I interpreted your question without seeing any code.. Let me know.
I added colors to the divs so you can see which is located where.
jsFiddle: http://jsfiddle.net/z2Y8a/19/
<div id="galleryContainer" style="width:200px;height:200px;background:green;">
<div id="imageContainer" style="width:50px;height:100px;background:blue;">
<div style="height:75px;">
<img src="img" />
</div>
<div id="leftArrow" style="width:25px;height:25px;background:red;float:left;display:none;">L</div>
<div id="rightArrow" style="width:25px;height:25px;background:yellow;float:left;display:none;">R</div>
</div>
</div>​
<script>
$("#imageContainer").hover( function()
{
$("#leftArrow").toggle();
$("#rightArrow").toggle();
});​
</script>
-- EDIT --
$("#galleryContainer").hover(function()
{
$("#leftArrow").toggle();
$("#rightArrow").toggle();
});

Container div over its content

I've got this HTML. Flash# divs are for flash objects (swfobjects). There is a container div container2 which I want to place it over its content, like a curtain when flash objects are updated and rebuilt to prevent the user from clicking them.
//rest of html code
<div id="container2">
<div id="flash1"></div>
<div id="flash2"></div>
<div id="flash3"></div>
<div id="flash4"></div>
</div>
//rest of html code
I've tried an absolute positioned div over the flash divs to achieve this but this doesn't work with jQuery slidetoggle effect which I use in a previous div (it has a weird width behaviour that narrows the page) therefore I've decided to try this different approach, which also seems to be more efficient.
Any idea of how to achieve this? I'm open mainly to jQuery but also to strict Javascript or whatever.
Delete div when slide up.
Add div when slide down.
Good luck =)
For me you have to add another div inside the container and use it to overlay the flash objs. Leave the container in position:relative and overflow:hidden and use a div child to cover the content!
Marco
I eventually follow the workaround proposed by mkk. This is to completely delete any applied rule to the slid div and have just worked for me.
Simple but effective.

Categories

Resources