Determine a DOM element's document? - javascript

I am getting a reference to a DOM element from a WYSIWYG Editor.
I don't understand JS nor the WYSIWYG Editor (CKEditor) that deeply yet, but it somehow seems to be a pointer or other direct reference to the actual element that resides in an IFRAME within the WYSIWYG editor. At least, when I console.log the element, I get a link that, when clicked, opens the actual element in Firebug.
Is there a way to get a reference to this element's document object within the IFRAME?

If you have the DOM element reference, you can use the ownerDocument property:
var ownerDoc = someElement.ownerDocument;

I don't know that specific editor, but if it has a reasonably normal implementation of the DOM, each node (including the DOM element to which you get a reference) has a parentNode read-only property that references its parent node. By following the chain of parentNode references, you're moving upwards in the DOM tree and should eventually reach the document you want.
(The ownerDocument property offers a more immediate solution, but it was not supported in some old browsers such as IE 5.5 -- if you don't have to worry about such "archaeology" issues, it's fine, but parentNode works even more broadly).

Related

How to access browser's DocumentFragment nodes?

For the page chrome://history, in Developer Tools, the DOM Elements tree shows nodes of type DocumentFragment like the following #shadow-root (open) which you can see selected in the screenshot below:
My question is how to use querySelector or another Javascript method to select such nodes ?
Unlike what another answer in this site suggested, DocumentFragment.querySelector doesn't exist.
As explained on developer.mozilla.org,
The ShadowRoot interface of the Shadow DOM API is the root node of a DOM subtree that is rendered separately from a document's main DOM tree.
You can retrieve a reference to an element's shadow root using its Element.shadowRoot property, provided it was created using Element.attachShadow() with the mode option set to open.
In your case, it looks like you need to do
var shroot = document.getElementById('history-app').shadowRoot
.getElementById('history').shadowRoot;
As you can see, we (apparently) have to browse down the DOM step-by-step. I.e. trying for example to access the 'history' element directly won't work since it is itself inside a shadowRoot.

How to get the current document of an element with jQuery

I have a complex code that travels inside windows and iframes (yes, windows cause I open some windows with window.open sometimes and also travel inside iframes) and when some condition apply I get an element from inside of those iframes (they usually are DIVs and SPANs).
So, I have the element that I want in the object "$(this)" so from the parent window how can I know the "document" element that has this element? I need to get the "document" element that has "$(this)" and set some attributes to it.
I tried $(this).parents(document) but it does not work.
If this refers to an element (such that $(this) would give you a jQuery wrapper around it) or indeed any Node, then this.ownerDocument is a reference to the document the element is in (null if it's not in a document). Details in ownerDocument in the specification.

why does console.log(document.body) give different looking result?

I embedded console.log(document.body) at my local page for learning purpose and when I hit refresh it displayed properties of body element like baseURL, innerHTML, etc... rather than its
content. Why is this happening? (I am using Chrome43)
In JavaScript and the DOM, document.body is an object, and when you log it with console, Chrome is displaying displaying the object, which includes all of its properties. The content of document.body can be found in the innerHTML property and accessible via other properties as well.
Chrome may be displaying the object properties instead of the DOM tree if there's a race condition and console.log(document.body) is fired prior to the completion of the DOM tree.
If you need the DOM tree, then try logging document.body after the body loads.
document is the root of the DOM, not the same as window, the global browser scope. console.log(document.body); logs the DOM element, not the JavaScript object.

Is putting an empty string in .outerHTML equivalent to remove()?

So if I have a <span class="iii"></span> container... and I use you know:
document.querySelector('.iii').outerHTML=''; it removes the span and essentially removes that span element from the DOM and everything inside of it correct? Is it really, technically deleting/removing it from the DOM? Does it perform what remove() does?
I ask this, because .remove() is a new experimental method that is not cross browser correct? I'm trying to find a cross browser way to 'remove an element', and outerHTML = ''; does that for me, but I am asking this question because it doesn't seem right. outerHTML's function isn't for deleting, (or can it be) or is it?
Edit: added .iii my bad.
There is no difference, both will remove the element from the DOM removing all event handlers and other related properties from memory when the garbage collector decides to. As for performance I wrote a quick test, http://jsperf.com/outerhtmlblank-vs-remove and it turns out that outerHTML = '' is 14% faster on Google Chrome so I would say that is better to use. Feel free to test on other browsers to confirm the results.
When you call outerHTML = '' it sets the HTML around it to nothing, then when the browser updates it's representation of the DOM it realizes that the element is now gone and removes it from the DOM whereas remove() simply removes it from the DOM.
There doesn't seem to be any significant difference between them when it comes to removing elements from the DOM. For your case they both remove the element, and that's the end of the story.
Here are the most obvious differences that come to mind (feel free to add any other ones):
outerHTML
It is a getter
It is a setter (for the setter version it can be used to either "remove" or "replace" an element)
When you're either removing or replacing an element, you don't need to know its parent like you would need to with el.parentNode.removeChild(el)
It works only with strings, which are then parsed into DOM objects
It is a property and not a method
It is supported by most Browsers
remove
It is a method
It can remove Element and Text nodes where outerHTML isn't available on text nodes
It can only work with DOM objects and not strings
You don't need to know the element's parent, instead you just remove it
It's not supported by most Browsers as it's new

How can a DIV node been "detached" and what's the use?

In this article a detached Div node is created:
http://www.bennadel.com/blog/1008-jQuery-empty-Kills-Event-Binding-On-Persistent-Nodes.htm
I don't understand : I thought that DOM owns every nodes. How would you attach to DOM then ?
Last but not least what would be the purpose of having detached node ?
I'm not sure which answer you expect, so here are some thoughts:
I thought that DOM owns every nodes.
The document owns every node. Each node has an ownerDocument [MDN] property.
From the specification:
The Document interface represents the entire HTML or XML document. Conceptually, it is the root of the document tree, and provides the primary access to the document's data.
Since elements, text nodes, comments, processing instructions, etc. cannot exist outside the context of a Document, the Document interface also contains the factory methods needed to create these objects. The Node objects created have a ownerDocument attribute which associates them with the Document within whose context they were created.
How would you attach to DOM then?
There are various ways to insert a new node, such as appendChild [docs] or insertBefore [docs].
Last but not least what would be the purpose of having detached node ?
One advantage is that you can build complex subtrees offline so that the browser does not have to recalculate the layout every time you insert a node.
Sometimes it is also useful for parsing an HTML string. By creating an empty, detached div and assign the HTML string to innerHTML, you can parse and process the HTML string easily.
The only caveat is that document.getElementById cannot find nodes which are not part of the tree.
Also interesting in this regard might be the explanation for the Node.parentNode property. After all, a Node which does not have parent is not part of the tree:
The parent of this node. All nodes, except Attr, Document, DocumentFragment, Entity, and Notation may have a parent. However, if a node has just been created and not yet added to the tree, or if it has been removed from the tree, this is null.
with document.createElement(), you can create an element node
var p = document.createElement("p");
At this point though, it will exist in memory but will not have been attached to the DOM.
There are numerous ways in which a node can be attached to the DOM, but probably the easiest would be using element.appendChild(node)
var p = document.createElement("p");
// attach the newly created node to the document body
document.body.appendChild(p);
You may want to create the element first, manipulate it and then attach to the DOM so that your manipulations do not cause browser reflow e.g. if you're setting the background colour, border, appending child elements, etc. you want to do this in memory without each change having to be reflected as a visual change in the browser.
Modifying the DOM is expensive. You can create a detached object, set it up the way you need to (adding its attributes, binding event handlers, etc). After its setup the way you want, then append it to the DOM.
You can definitely create elements that are not part of the DOM.
var someElement = document.createElement("div");
var someOtherElement = $("<div>");
Performing operations on detached elements are far more efficient than performing operations on attached elements because detached elements do not have to be rendered.
The page you linked to uses .empty() which detaches elements from the DOM and removes all event handlers from those elements.
There is also .detach(), which may be what you mean. .detach() basically just, well, detaches the node from the DOM. It's not part of the DOM anymore; it's just hanging around in memory (as long as you keep it in a variable). This means that if you discard the variable, you've lost the detached node forever (it's not in the DOM nor in a variable).
A use case is e.g. temporarily "removing" an element from the DOM without actually dismissing it, so that you can attach it later (using .append/.after/etc).
var detached = $("...").detach();
// later:
$("body").append(detached);

Categories