Chrome: Inspect elements that appear only when dragging - javascript

I often want to view the styles of an element that appears only when dragging or when the mouse is clicked (mousedown event). How can I view the element's style using Google Chrome's developer tools?

Open the developer tools.
Go to "Sources":
Expand "Event Listener Breakpoints" on the right:
Add a listener for keydown events on the keyboard section:
Now start dragging the thing you want, and when it's time press any key on your keyboard and you'll be able to inspect the dragable element.

You can simply press F8 while dragging (and developer tools is open)

In case anyone encountered this question in the future, I have another solution for this. This solution is kinda same with the most upvoted answer, but it doesn't require any keydown, just simply drag:
Open chrome devtools
Click on the Sources tab
Go to Event Listeners Breakpoints down there
Om the event list, click Drag / drop, then tick dragover
After that, whenever you start to drag an element, the browser window will pause for debugging, then you can inspect the element's CSS styles freely.
Note: I tested this on Chrome version 80, but I think it works in older version though.
Edited:
Just now I figured out dragover breakpoints doesn't work in certain condition, e.g., if you want to inspect styles after the dragged item reached another element. For that situation, you may try different listeners as specify in Drag / drop, such as drop.

dragMethod() {
setTimeout( () => {
debugger;
}, 500)
}
This will suspend the drag action so you can proceed to inspect as normal.

From the DevTools Go to the lowest element that will wrap your draggable item
Right click this element and chose "Store as global variable" it'll be referred to from the console as temp1
Write in the console this command - let myInterval = setInterval(() => console.log(temp1.cloneNode(true)), 1000)
At this stage you can see the element details in the console whem you drag it.
When you don't need to inspect it any more run from the console - clearInterval(myInterval).
Instead of section 2 you can run the follow command and select your draggable element with the appropriate query selector - let myInterval = setInterval(() => console.log(document.querySelector(/* your query goes here */)?.cloneNode(true)), 1000)

Put a breakpoint in the code - inside of the mousedown event callback.
This will freeze the app when you begin dragging, and then you can tab over the the Element section of the inspector to use it like you normally would, only now it's frozen at the beginning of the drag.
EDIT: You should put the breakpoint on a line below where the new elements you want to inspect are created, so the elements are on the DOM by the time you freeze.
// Raw event
someElement.addEventListener('mousedown', function(ev) {
// Put a breakpoint on any of the lines in here
}, false);
// jQuery for prudence
$(someSelector).on('mousedown', function(ev) {
// Put a breakpoint on any of the lines here
});

One way of doing it is to open the elements panel then right click while dragging.
This opens the contextual menu and "pauses" the mouse move/hover effect.
Then after right clicking, go back to the elements panel and search for the element using the find feature.
This can also be used to inspect hover effects (it's just faster than other methods)
This can be tested here for example
https://jqueryui.com/draggable/#visual-feedback

In addition to #Davids answer, it might be worth mentioning, that you need to add a eventlistener somewhere in your code as well or simply put it in the console before
Example:
document.onclick=function(){};

Related

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.

Disable Double Tap To Click On Touchscreen iOS Devices

So, quite recently I've been working on a website that was given me to improve and make responsive, and one of the issues that I've been faced with is that there are many elements that are clickable, with a mixture of CSS and jQuery effects for hover states.
Now, firstly I'd prefer all of these hover states to be CSS, but the main issue I'm having is that on these hover states, certain elements are changing display and visibility css properties. I did some reading, and apparently if this is the case, on touchscreen iOS devices, this causes the first 'touch' to force the hover state, and then a second click is needed to actually click the element.
I'm trying to find a solution that doesn't require lots of markup and styling changes. Preferably a fix harnessing jQuery/JavaScript would be good.
I've tried the following:
$(document).ready(function() {
$('a').on('click touchend', function(e) {
var el = $(this);
var link = el.attr('href');
window.location = link;
});
});
However, this has issues when the user holds their finger down on a clickable element, and drags the page to scroll. When they release their finger after dragging, the window.location is still changed.
I'll add a jsFiddle later if necessary.
Thanks in advance.
EDIT:
Here's a jsFiddle that shows the issue. http://jsfiddle.net/0bj3uxap/4/
If you tap one of the blocks, you'll see it shows the hover state, you then need to tap again to actually fire the click event.
It seems to happen when an element is hidden, and then the hover state shows the element.
Looks like I found a solution.
https://github.com/ftlabs/fastclick
FastClick fixes this issue, and removes the 300ms delay issue with some mobile browsers.
Just include the library in <script> tags, and then initiate it using jQuery, or whatever you prefer:
$(document).ready(function() {
FastClick.attach(document.body);
});
Just to explain briefly why the issue occurs:
When an element is hidden, for example when it has a CSS property of any of the following:
display: none;
opacity: 0;
visibility: hidden;
And the hover state of the hidden element then shows the element, iOS doesn't fire a click event on the first touch, it forces the hover state (to show the element). The user then needs to touch the element again for a click event to fire.
I see why this has been added, but I think I'd rather iOS didn't do this, and then developers would just need to tailor their websites to not hide content that coud be vital.
If it helps anyone else: In my case I had a very similar problem, however it wasn't simply due to a :hover style on it's own. Instead, it was due to the fact that I was using JavaScript event listeners (touchstart, touchmove and touchend) to change visibility of elements on the page (no matter where).
In my case, I was simply adding a touch class to the <html> tag in order to detect that the device was capable of touch and should always display certain elements that typically only show on hover. My fix was two fold:
Move to a >300ms delay (i.e. the amount of time mobile browsers may typically wait before determining if this was a single vs. double click). In my case, I just settled on 500ms (see #2 below for why).
I then used a cookie to temporarily retain this setting so that these elements would be visible immediately and no touch event listeners would be required on subsequent page loads (thus a delay of 500ms on the first occasion shouldn't be a deal breaker).
Example code:
In this case, using jQuery + https://github.com/carhartl/jquery-cookie (modified to support maxAge).
function initTouchSupport() {
// See if touch was already detected and, if so, immediately toggle the touch classes.
if ($.cookie('touch-device')) {
toggleTouch();
return;
}
// Be efficient and listen once and, if ever detected, flag capability and stop listening (for efficiency).
var events = 'touchstart touchmove touchend';
$body.on(events, detectTouch);
function detectTouch() {
// Detected; retain for a short while (e.g. in case this is a laptop with touch capability and they switch
// to mouse control). That way there's no delay on the next several page loads and no chance of a double-touch bug.
$body.off(events, detectTouch);
$.cookie('touch-device', true, {
path: '/',
domain: getDomain(),
maxAge: 86400 // 86400 seconds = 1 day
});
setTimeout(toggleTouch, 500);
}
function toggleTouch() {
// Swap out classes now
$html.toggleClass('no-touch', false);
$html.toggleClass('touch', true);
}
}
I had a very similar issue in IOS having to double tab buttons etc I removed all the desktop styles which included some hover styles this made no difference. I put the hover styles back in which are not used in the mobile UI. In then end the issue was a css class called
.error-message
Correction it turns out this css has been used in our UI and it was linked to a mouseover event

javascript dragging a file from desktop: dragenter / dragleave triggers uncorrectly

Made a fiddle for this: http://jsfiddle.net/terjeto/MN4FJ/
My problem is that dragleave fires when you drag a file from desktop into the box and over the text inside the box. (drag a file into box will make the border solid -> drag the file over the text inside the box and the border will be dashed:->which is not what I want).
Is this a browser bug? (firefox 9#win).
I also put in a box for mouse up/down which works just fine so you can compare the two.
How can I achieve the correct dragenter / dragleave behaviour?
PS. I bind to body because I need the event-delegation in my real app.
This is a well documented shortcomming of the spec.
As Peter-Paul Koch points out here
A function like this might help you work out if the target element is a child of the target area that you want to drop the file onto.
function isChildElement(parent, child) {
var childParent = child;
while (childParent) {
if (childParent == parent) {
return true;
}
childParent = childParent.parentNode;
}
return false;
},
I've written a little library called Dragster to help me deal with this issue, it works everywhere except IE (where it just does nothing).
The issue is relatively well known, but solutions are all pretty 'hacky'. I came across a workaround that fixes it in my case and should be adaptable for most situations.
I listen for dragenter events on the container (a box) of my possible dropzones. Events fire whenever the drag moves from one element to another and bubble to the container. When the target is one of my drop zones (or possibly a child within the drop zone but that wasn't necessary in my case since you can't get to the children without entering the surrounding box first) then I set the droppable highlighting, just as normal.
When the dragenter event fires on the container itself then I remove the highlighting from the previous element because I must have left it. For a dragenter event, the element that was highlighted is the relatedTarget so it is easy to find and there is no need for a dragleave event listener.
Note that you may have the remove the highlighting explicitly following a drop, depending on your exact drop logic.
I had the same problem and finally figured out a stable solution. Here is a plugin called draghover, which works cross browsers. Check it out here: https://github.com/bingjie2680/jquery-draghover

Mobile Safari Event Issue

I have designed a website with a menu that is initially invisible. When the user clicks on a button, the menu becomes visible. There are two ways for the user to hide the now visible menu:
Click the button that caused the menu to become visible
Click anywhere on the web page that isn't the menu
The way I have coded the second option is to tie an onclick event to the window element, and have it compare where the user clicked to the menu's position to determine if the menu should be hidden. This works great in Firefox and Safari, but it fails in Mobile Safari.
I noticed that the window onclick event only fires when I click on another element with an onclick event already assigned. If I click on an element with no event(s) assigned, the window's onclick event never fires. If I click on the button which displays the menu, it fires along with the event tied to the button.
Is it possible to assign events to the window element in Mobile Safari?
I'v been encountering this same problem. Here is what worked for me. (Note: I am working within a Modernizr and jQuery context)
First, I add a custom Modernizr class using Modernizr's addTest Plugin API to test for iOS, which will add the class appleios or no-appleios accordingly.
Because in my research the body seems to fire events on it's own agenda, I am taking a little precaution by wrapping all the document's content with an element in an iOS context. Then I add an event handler to this element.
$(".appleios body").wrapInner('<div id="appleios-helper" />');
$("#appleios-helper").bind("mouseup", function(){return;});
What was suggested earlier in this thread is using void(0). I did some quick testing, and found that void(0) as the event just wasn't causing touches on the body to be recognized. When I plugged in my own "empty" function in the form of function(){return;} things started working.
This all hinges on the fact that no events are fired in Mobile Safari unless the element explicitly has events to fire (Safari Web Content Guide.) By inserting this empty event on the wrapper, things will bubble up to the body.
If you're doing strait JavaScript with none of these libraries, the same effect could be achieved in the HTML markup
<html>
...
<body>
<div id="appleios-helper" onmouseup="function(){return;}">
...
</div>
</body>
</html>
This worked for me to hide tooltips when touching anywhere on the document's body. Your mileage may vary.
Simply adding the dummy onclick handler to the html body works for me:
<body onclick="void(0)">
Note that I am using usual live event handlers as shown below:
function liveHandler( event ) {
var target = event.target; ...}
window.addEventListener(evtype, liveHandler, true);
// evtype such as 'mousedown' or 'click'
// we use the capturing mode here (third parameter true)
This is an old question, but I struggled with the same thing today.
I found that using touchstart event works.
I solved it like this:
var isTouchDevice = 'ontouchstart' in document.documentElement;
if (isTouchDevice) {
// Do touch related stuff
$(document).on('touchstart', function (event) {
// Do stuff
});
} else {
// Do non-touch related stuff
$(document).on('click', function () {
// Do stuff
});
}
You could just add onclick="void(0);" to some <div> that covers the whole page so that no matter what, you are always clicking on an element that has an onclick event. Not a great solution, though.
I'd prefer not having the onclick event be tied to the window. Why don't you create a container <div> that has that event on it. Then handle it just like you currently are.
You can also:
$('body').css('cursor', 'pointer');
No idea what those "engineers" at Apple are doing. LOL.
This has problems though. You wouldn't want to do this on every touch device. Only touch devices that don't also have a pointing device (Laptops with Touch Screens, for example).
Source: http://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
The conclusion of the article is this:
So I don’t understand why all this is the case, but it most certainly is the case. If you’re having bubbling problems, just add an empty-function event handler anywhere between the body and the element, and you’re set to go. But it shouldn’t be necessary.

Javascript detect when drop down list is closed

Because of the issue explained in this question I have a situation where I need to attach the mousewheel event to the drop down list only when it is expanded (I do this in the onclick event). However I need to remove the mousewheel event when the list collapses. How do I go about detecting this?
I can't just use the onchange event because the user may not have actually changed their selection. I've tried the onblur event but in most browsers (except IE) the drop list stays focused when the list is collapsed.
Cheers.
var list = document.getElementById("list");
list.onclick = function (e) {
// attach mousewheel
list.onmousewheel = function (e) {
// ...
}
// attach click off
// This event fires fine in all browsers except FF when the list is expanded.
// In firefox it only fires when anywhere in the document is clicked twice.
// The first click closes the drop down list as expected and the second one
// fires the event.
window.document.onclick = function (e) {
list.onmousewheel = null;
window.document.onclick = null
}
};
EDIT:
Unfortunately meder's solution doesnt work in firefox. The click event on the document doesn't get fired until i click twice off the drop down list. How do I get around that? It works fine in IE.
EDIT2:
I've done some more testing and the following browsers behave as expected
IE 7,
Chrome 3
Opera 10
Firefox requires 2 clicks in the window to make it work & Safari doesn't work at all.
It appears that even when you click off the drop down list firefox maintains focus on it. It's not until the second click occurs that the drop down list eventually loses it's focus.
Are you looking for something like this? If the user clicks anywhere that's not within #el, it will branch out and you can do what you want, though this requires jQuery but it would take far too many lines of DOM Scripting.
var dropdown = $('#el');
$(document).click(function(e){
if ( (!$(e.target).is(dropdown)) || !$(e.target).closest('#el').length ) {
// do what you need to
}
});
If not, can you be more specific and include an example?
PS - I did not test the snippet, sorry if it isn't what you want.
OK, I still have no idea what you're trying to achieve with such a tightly-scripted select box, but in general trying to change the internal working of a native <select> isn't fruitful. There's no standard that says how events flow internally to the form element, and browsers that implement select as an OS-level widget (IE) can't do much to support it anyway.
If you must have this behaviour, I'd suggest using scripting to replace the <select> box on-fly with a JavaScript-powered analogue made out of <div>s. Then you can control exactly how each mouse and keyboard interaction behaves. There are many libraries that do this already, though again if you need to be very specific about the exact behaviour they might not suit you.

Categories

Resources