I don't want to remove an element from it's parent (via element.parentNode.removeChild). I want it to not exist in the DOM whatsoever.
Here's my use case. I have a tampermonkey script I wrote which is supposed to delete annoying pop ups for me. For example, on this page when I hover over the second sentence in point #2, a pop up appears. I want my script to delete that node so that it never pops up.
Here's the problem. Even if I remove it, the element still exists and the website's scripts will move that element into document.body again every time. I want the element to actually not exist. Not merely exist without a parent element.
Related
When inserting new html into a section, I want the first tab press to skip the first few links and focus on a later link. Currently, my solution is to insert an empty <span> with tabindex='-1', and then to call focus() on it. However, I noticed that screen-reading software will jump to this focus(). Is there another way to set the initial tab focus, or to make screen-reading software ignore the focus()? (With NVDA, the div I'm inserting into is a role='status' which should be read whenever it updates, and the focus() grabs NVDA away about 40% of the time, without any seeming pattern.)
A method that failed is tabindex. Both Firefox and Chrome don't respect tabindex for the first tab press for inserted elements. In the code sample below, the second element has the last tabindex, and yet is focused first in Firefox. Behavior in Firefox differs between the first tab press and subsequent tab presses. Chrome ignores the tabindex completely for the first tab focus, so the first tab focus is always the first link.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>
function k() {
document.getElementById("h").innerHTML = "<button tabindex='2' onclick='k()'>first</button><button tabindex='3' onclick='k()'>second</button><button tabindex='1' onclick='k()'>third</button>";
}
</script>
<div id="h"><button onclick='k()'>click me</button></div>
</body>
</html>
I also tried marking the empty <span> with aria-hidden='true' but that didn't help.
Attempt 1: From testing, if the DOM element that owns the existing focus is destroyed, the next object to receive a tab's focus is erratic, and behaves differently on Firefox and Chrome.
On Firefox, the focus is "ghostly shifted" to the first text-order element to appear, and then the first tab will shift forward and backward from this first element. So a tab will reach the element whose tab order is after the first element, and a shift tab will reach the element whose tab order is before the first element.
On Chrome, the first tab's focus will appear on the first text-order element no matter what tabindex is.
That means that tabindex is a nonworking solution if the DOM element is destroyed.
Attempt 2: The alternative is focus(). Inserting a ghost element with tabindex='-1' style='outline:none', and then calling focus() on it, does make tab focus on the element I want it to focus on. However, this has the problem of screwing up screenreaders. Whenever focus() is called, a screenreader (NVDA tested) might do one of three things:
read the new message text like I want it to (20% chance)
read the Window title, then tab title, then the focus()d element, which is horrible (70% chance)
read nothing at all (10% chance)
aria-hidden doesn't help. autofocus does nothing.
Attempt 3: That means focus() is not an acceptable solution. So the only alternative is to not destroy the DOM element. So the DOM element must be moved.
However, the moved-element graveyard will fill up if we continually push things there. And we can't delete a graveyard element if it contains our focus element, or else we'll be in the destroyed-focus-element situation. In my situation, interactive fiction will fill this graveyard up to gigabytes in a few hours.
Thus, when deleting history log elements, we must check the element and all its children to make sure focus is not contained there, and then dance around it if it is.
Attempt 4: However, it turns out that moving an element kills its focus anyway (at least on Firefox). So you can't just move it to a graveyard, you have to not touch it at all.
Once you have a surviving object that you haven't moved anywhere, you need to set tabindex='-1' on it, or else this graveyard object will mess with your tab order. However, if you do set its tabindex to -1, then (at least on Firefox), tab order now behaves like the destroyed-DOM-object situation once again.
Attempt 5:
don't move that disappearing object anywhere!
instead, take that object, and then hide it.
build your new object around it: the old object must be placed exactly where you want the tab placement to be, in text order. Your new content will be half before it and half after it.
check all of the hidden object's subnodes (recursively) for activeElement to find out where its focus is. For every non-active element that isn't a parent of the node with focus, you must delete it or else the screen reader will complain a lot. For the surviving nodes, make sure they are completely invisible and have no content, but don't use display:none, that will destroy the focus. Set tabindex = -1 on the focused node.
If your focus wasn't in the object you deleted, then find the object that owns the focus and set its tabindex to between the tabindex of the first half and second half.
I have run out of patience, and I am not going to implement this proposed solution, leaving mysteriously half-deleted, half-hidden elements in the middle of new text. After 5 failed attempts, I don't have much hope left, and I don't want to saddle maintainers with pages of in-depth comments, strange unintuitive behavior, and unexpected performance concerns, just for screenreaders. I am going to stick with my old focus() solution.
My script scrapes the page and if there is a new element according to my requirements, it clicks the button, when there is only one element everything is perfect but problem is when it clicks the button, a new page opens. So if there are more than one element, I need to get back to previous page to continue process.
I tried browser.back() for sure, but when it comes back to previous page it doesn't remember the elements and gives this error as I expected: selenium.common.exceptions.StaleElementReferenceException: Message: Element not found in the cache - perhaps the page has changed since it was looked up with the line if len(css(".Total", parent=new, nowait=True)) > 0: which is the first line, I made it to recognise the new elements.
I also tried to open a new tab/window by clicking the button but button doesn't have this feature because it is javascript. Is there a efficent way to solve this issue?
first_window_handler = driver.current_window_handle
driver.find_element_by_css_selector("body").send_keys(Keys.CONTROL + 't')
second_window_handler = driver.window_handles[1]
# from second page
driver.switch_to.window(second_window_handler)
element_from_second = driver.find_element_by_css_selector('something')
# from first page
driver.switch_to.window(first_window_handler)
element_from_first = driver.find_element_by_css_selector('something else')
now you can switch between windows, and the elements will still be interactable
As per exception
selenium.common.exceptions.StaleElementReferenceException: Message: Element not found in the cache - perhaps the page has changed since it was looked up
we came to know that whenever page loads webdriver loosing references to webelements which it holds previously.
So the best thing is always pass locators dynamically on calling predefined keywords/methods in java prospective, so that webdriver looks for that web element at that instance and perform action.
Some times we may receive same exception in looping list of web elements, because in loop due to actions webdriver may loose reference, so in loop also we need to specify locators so that it will not fail. example if i need to click on links, i will give path like this "//a["+i+"]"
Thank You,
Murali
Is there a way to find out which JS script created a dynamic element in Chrome's Developer Tools? If I do 'view page source' on the page, the element isn't there. I can see the element though in Chrome's Developer Tools. Is there a way to find out specifically which JavaScript file and what line in my JavaScript file created the element?
To help clarify: I know which element is created...what I don't know is which .js file created it and specifically what line in that .js file
Updated answer:
Below you've said:
I know which element it is...what I don't know is which .js file created it and specifically what line in that .js file
That's not how the question originally read. :-)
If you know which element it is, two options for you:
You can use Dev Tools to trigger a breakpoint when its parent element is modified:
Load the page
Open Dev Tools
Go to the Elements panel
Navigate to the parent element that the target element will eventually be added to
Right-click the parent element and click Break on... > Subtree Modifications
Now, Chrome will trigger a breakpoint when the parent element's subtree is modified, and so you can see what JavaScript code is adding the element.
Unfortuantely, it won't fire that breakpoint if the element is added during the main loading of the page (e.g., during the parsing of the HTML, by script that runs immediately rather than waiting).
If there's any text in the element that seems specific to it (content, id, class, some attribute, whatever), once the page is loaded you can use Chrome's powerful search feature to try to find that text:
Load the page
Open Dev Tools
Go to the Sources tab
Click Ctrl+Shift+F, which is "find in files" — it looks in all of the files associated with the page, not just the "current" file
Type the text that you think might help you identify the code adding the element
Press Enter, all matches will be shown below
You can even use regular expressions.
Original answer:
No, there's no simple way to differentiate an element created via JavaScript after page load from ones created by the initial HTML parsing.
Or at least, there isn't without adding JavaScript to the page that runs before any other JavaScript on the page runs, which I'm guessing is a requirement.
But if you can add JavaScript to the page before any other JavaScript runs, it's actually really easy to do:
Array.prototype.forEach.call(document.querySelectorAll("*"), function(element) {
element.setAttribute("data-original", "");
});
That marks every single element on the page with an attribute that tells you it was there when that code ran. You can see those attributes in the Elements panel of the Dev Tools. And so, if you see an element that doesn't have that attribute, you know it was added later.
document.querySelectorAll("*") is a big hammer you probably wouldn't want to use in production code, but for temporary use when debugging/developing, it's fine.
And if you want to know about the elements that have been created by other code later, you can do this in the console:
Array.prototype.forEach.call(document.querySelectorAll("*"), function(element) {
if (element.getAttribute("data-original") === null) {
console.log(element);
}
});
That'll output every element that wasn't on the page when you ran the earlier code, and Chrome's console is really cool — you can right-click the element display in the console and choose "Reveal in Elements panel" to see exactly where that element is.
You can use chrome-devtools-protocol's experimental feature.
Check this, https://chromedevtools.github.io/devtools-protocol/tot/DOM/#method-getNodeStackTraces
First, send 'DOM.setNodeStackTracesEnabled' to chrome dev protocl.
Second, use 'DOM.getNodeStackTraces' message.
So, you can get call stack information from dynamic creation element.
I wrote my own program using these functions.
Image: https://imgur.com/a/TtL5PtQ
Here is my project: https://github.com/rollrat/custom-crawler
Is there a tool (or something in firebug) that will tell me what events just fired and more importantly on what elements they were bound to?
I have a number of javascript "includes", some minified, some not. I am experiencing some odd behaviour that I want to turn off, but I cannot find what is causing it.
I have a form showing in a "popup" and when I try to click on one of the input boxes, the "popup" closes, so some event bind somewhere is causing this.
The problem is, I don't know what element has this spurious event bound to it. The problem also occurs if I click anywhere inside the popup (and on the background mask that is covering the rest of the page, but that's acceptable)
I am using firefox, so anything I can type in the console is also an option. The eventys in the multiple javascript files are done in various ways, some through jquery, some using inline attributes (eg. onclick="..."), some using just javascript.
I certainly don't want to go and add some line of code to every possible event in every javascript file.
I have spent over an hour trying to hunt down this dom element and have already eliminated the obvious ones like the divs containing the popup and the body tag.
DOM modifications can be tracked down using the Break On Mutate option within Firebug. It can be activated by clicking the related button ( ) within the HTML panel. Note that the Script panel has to be enabled for this to work.
There are also several other Break On ... features, which may help you finding the right position within the code for a specific event.
Furthermore Firebug 2.0 introduced an Events side panel, which displays all events bound to the element selected within the HTML panel. If libraries like jQuery are used, it will even allow you to investigate the user-defined function wrapped by the library function in case you enable the option Show Wrapped Listeners as described in the answer to a related question.
I'm sure we've all done it by now. A website pops up some goofy JavaScript modal preventing you from continuing. You whip out Firebug, inspect it, and hit Delete. Poof! Gone. Now, is there a way with JavaScript to recreate the element or disable that functionality altogether? Thanks!
Create a js reference to the element on page load. Add a listener to the element that looks for the destroy event. If that happens, then use your reference to recreate the item. The only issue is firebug might not fire a destroy event when an element is manually deleted. In that case, you could have a loop that checks every x milliseconds to see if the element is there. If it isn't, then create a new one.