Chapter 2 – Document Nodes

最后更新于:2022-04-01 04:39:11

## 2.1 *document* node overview The *HTMLDocument* constructor (which inherits from *document*) when instantiated represents specifically a*DOCUMENT_NODE* (i.e. *window.document*) in the DOM. To verify this we can simply ask which constructor was used in the creation of the *document* node object. live code: [http://jsfiddle.net/domenlightenment/qRAzL](http://jsfiddle.net/domenlightenment/qRAzL) ~~~ <!DOCTYPE html> <html lang="en"> <body> <script> console.log(window.document.constructor); //logs function HTMLDocument() { [native code] } console.log(window.document.nodeType); //logs 9, which is a numeric key mapping to DOCUMENT_NODE </script> </body> </html> ~~~ The code above concludes that the *HTMLDocument* constructor function constructs the *window.document* node object and that this node is a *DOCUMENT_NODE* object. ### Notes Both *Document* and *HTMLDocument* constructors are typically instantiated by the browser when you load an HTML document. However, using *document.implementation.createHTMLDocument()* its possible to create your own HTML document outside of the one currently loaded into the browser. In addtion to *createHTMLDocument()* its also possible to create a document object which has yet to be setup as an HTML document using *createDocument()*. Typically the use of theses methods are associated with programatically providing an HTML document to an iframe. ## 2.2 *HTMLDocument* properties and methods (including inherited) To get accurate information pertaining to the available properties and methods on an *HTMLDocument* node its best to ignore the specification and to ask the browser what is available. Examine the arrays created in the code below detailing the properties and methods available from an *HTMLDocument* node (a.k.a. *window.document*) object. live code: [http://jsfiddle.net/domenlightenment/jprPe](http://jsfiddle.net/domenlightenment/jprPe) ~~~ <!DOCTYPE html> <html lang="en"> <body> <script> //document own properties console.log(Object.keys(document).sort()); //document own properties & inherited properties var documentPropertiesIncludeInherited = []; for(var p in document){ documentPropertiesIncludeInherited.push(p); } console.log(documentPropertiesIncludeInherited.sort()); //documment inherited properties only var documentPropertiesOnlyInherited = []; for(var p in document){ if( !document.hasOwnProperty(p)){documentPropertiesOnlyInherited.push(p); } } console.log(documentPropertiesOnlyInherited.sort()); </script> </body> </html> ~~~ The available properties are many even if the inherited properties were not considered. Below I've hand pick a list of noteworthy properties and methods for the context of this chapter. * *doctype* * *documentElement* * *implementation*. * *activeElement* * *body* * *head* * *title* * *lastModified* * *referrer* * *URL* * *defaultview* * *compatMode* * *ownerDocument* * *hasFocus()* ### Notes The *HTMLDocument* node object is used to access (typically inherit) a great deal of the methods and properties available for working with the DOM (i.e. *document.querySelectorAll()*). You will be seeing many of these properties not discussed in this chapter discussed in the appropriate chapter's following this chapter. ## 2.3 Getting general HTML document information (title, url, referrer, lastModified, compatMode) The *document* object provides access to some general information about the HTML document/DOM being loaded. In the code below I use the *document.title*, *document.URL*, *document.referrer*, *document.lastModified*, and *document.compatMode* properties to gain some general information about the *document*. Based on the property name the returned values should be obvious. live code: [http://jsfiddle.net/domenlightenment/pX8Le](http://jsfiddle.net/domenlightenment/pX8Le) ~~~ <!DOCTYPE html> <html lang="en"> <body> <script> var d = document; console.log('title = ' +d.title); console.log('url = ' +d.URL); console.log('referrer = ' +d.referrer); console.log('lastModified = ' +d.lastModified); //logs either BackCompat (Quirks Mode) or CSS1Compat (Strict Mode) console.log('compatibility mode = ' +d.compatMode); </script> </body> </html> ~~~ ## 2.4 *document* child nodes *Document* nodes can contain one *DocumentType* node object and one *Element* node object. This should not be a surprise since HTML documents typically contain only one doctype (e.g. *`<!DOCTYPE html>`*) and one element (e.g. *`<html lang="en">`*). Thus if you ask for the children (e.g. *document.childNodes*) of the *Document* object you will get an array containing at the very least the documents doctype/DTD and *`<html lang="en">`* element. The code below showcases that *window.document* is a type of node object (i.e* Document*) with child nodes. live code: [http://jsfiddle.net/domenlightenment/UasKc](http://jsfiddle.net/domenlightenment/UasKc) ~~~ <!DOCTYPE html> <html lang="en"> <body> <script> //This is the doctype/DTD console.log(document.childNodes[0].nodeType); //logs 10, which is a numeric key mapping to DOCUMENT_TYPE_NODE //This is the <html> element console.log(document.childNodes[1].nodeType); //logs 1, which is a numeric key mapping to ELEMENT_TYPE_NODE </script> </body> </html> ~~~ ### Notes Don't confuse the *window.document* object created from *HTMLDocument* constructor with the *Document* object. Just remember*window.document* is the starting point for the DOM interface. That is why *document.childNodes* contains child nodes. If a comment node (not discussed in this book) is made outside of the *`<html lang="en">`* element then it will become a child node of the *window.document*. However having comment nodes outside of the `<html>` element can cause some buggy results in IE and also is a violation of the DOM specification. ## 2.5 *document* provides shortcuts to `<!DOCTYPE>`, `<html lang="en">`, `<head>`, and `<body>` Using the properties listed below we can get a shortcut reference to the following nodes: * document.doctype refers to `<!DOCTYPE>` * document.documentElement refers to `<html lang="en">` * document.head refers to `<head>` * document.body refers to `<body>` This is demonstrated in the code below. live code: [http://jsfiddle.net/domenlightenment/XsSTM](http://jsfiddle.net/domenlightenment/XsSTM) ~~~ <!DOCTYPE html> <html lang="en"> <body> <script> console.log(document.doctype); // logs DocumentType {nodeType=10, ownerDocument=document, ...} console.log(document.documentElement); // logs <html lang="en"> console.log(document.head); // logs <head> console.log(document.body); // logs <body> </script> </body> </html> ~~~ ### Notes The doctype or DTD is a *nodeType* of 10 or *DOCUMENT_TYPE_NODE* and should not be confused with the *DOCUMENT_NODE* (aka*window.document* constructed from *HTMLDocument()*). The doctype is constructed from the *DocumentType()* constructor. In Safari, Chrome, and Opera the *document.doctype* does not appear in the *document.childNodes* list. ## 2.6 Detecting DOM specifications/features using*document.implementation.hasFeature()* Its possible using *document.implementation.hasFeature()* to ask (boolean) the current document what feature and level the browser has implemented/supports. For example we can ask if the browser has implemented the core DOM level 3 specification by passing the name of the feature and the version to the *hasFeature()*method. In the code below I ask if the browser has implemented the Core 2.0 & 3.0 specification. live code: [http://jsfiddle.net/domenlightenment/TYYZ6](http://jsfiddle.net/domenlightenment/TYYZ6) ~~~ <!DOCTYPE html> <html lang="en"> <body> <script> console.log(document.implementation.hasFeature('Core','2.0')); console.log(document.implementation.hasFeature('Core','3.0')); </script> </body> </html> ~~~ The following table defines the features ([spec calls these modules](http://www.w3.org/TR/DOM-Level-2-Core/introduction.html#ID-Conformance)) and versions that you can pass the*hasFeature()* method. | Feature | Supported Versions | | --- | --- | | Core | 1.0, 2.0, 3.0 | | XML | 1.0, 2.0, 3.0 | | HTML | 1.0, 2.0 | | Views | 2.0 | | StyleSheets | 2.0 | | CSS | 2.0 | | CSS2 | 2.0 | | Events | 2.0, 3.0 | | UIEvents | 2.0, 3.0 | | MouseEvents | 2.0, 3.0 | | MutationEvents | 2.0, 3.0 | | HTMLEvents | 2.0 | | Range | 2.0 | | Traversal | 2.0 | | LS (Loading and saving between files and DOM trees synchronously) | 3.0 | | LS-Asnc (Loading and saving between files and DOM trees asynchronously) | 3.0 | | Validation | 3.0 | ### Notes Don't trust *hasFeature()* alone you should also use [capability detection](http://dev.opera.com/articles/view/using-capability-detection/) in addition to *hasFeature()*. Using the *isSupported* method implementation information can be gathered for a specific/selected node only (i.e.*element.isSupported(feature,version*). You can determince online what a user agent supports by visiting [http://www.w3.org/2003/02/06-dom-support.html](http://www.w3.org/2003/02/06-dom-support.html). Here you will find a table indicating what the browser loading the url claims to implement. ## 2.7 Get a reference to the focus/active node in the *document* Using the *document.activeElement* we can quickly get a reference to the node in the document that is focused/active. In the code below, on page load, I am setting the focus of the document to the *`<textarea>`* node and then gaining a reference to that node using the *activeElement* property. live code: [http://jsfiddle.net/domenlightenment/N9npb](http://jsfiddle.net/domenlightenment/N9npb) ~~~ <!DOCTYPE html> <html lang="en"> <body> <textarea></textarea> <script> //set focus to <textarea> document.querySelector('textarea').focus(); ​//get reference to element that is focused/active in the document console.log(document.activeElement); //logs <textarea> </script> </body> </html> ~~~ ### Notes The focused/active element returns elements that have the ability to be focused. If you visit a web page in a browser and start hitting the tab key you will see focus shifting from element to element in that page that can get focused. Don't confuse the selection of nodes (highlight sections of the HTML page with mouse) with elements that get focus for the purpose of inputting something with keystrokes, spacebar, or mouse. ## 2.8 Determing if the *document *or any node inside of the *document* has focus Using the document.hasFocus() method its possible to know if the user currently is focused on the window that has the HTML document loaded. In the code below you see that if we execute the code and then focus another window, tabe, or application all together the *getFocus()* will return false. live code: [http://jsfiddle.net/domenlightenment/JkE3d](http://jsfiddle.net/domenlightenment/JkE3d) ~~~ <!DOCTYPE html> <html lang="en"> <body> <script> //If you keep focus on the window/tab that has the document loaded its true. If not it's false. setTimeout(function(){console.log(document.hasFocus())},5000); </script> </body> </html> ~~~ ## 2.9 *document.defaultview* is a shortcut to the head/global object You should be aware that the *defaultView* property is a shortcut to the JavaScript head object or what some refer to as the global object. The head object in a web browser is the *window* object and *defaultView* will point to this object in a JavaScript browser enviroment. The code below demonstrates the value of *defaultView* in a browser. live code: [http://jsfiddle.net/domenlightenment/QqK6Q](http://jsfiddle.net/domenlightenment/QqK6Q) ~~~ <!DOCTYPE html> <html lang="en"> <body> <script> console.log(document.defaultView) //reference, head JS object. Would be window object in a browser. </script> </body> </html> ~~~ If you are dealing with a DOM that is headless or an JavaScript enviroment that is not running in a web browser (i.e. [node.js](http://nodejs.org/)) this property can get you access to the head object scope. ## 2.10 Getting a reference to the *Document* from an *element* using*ownerDocument* The *ownerDocument* property when called on a node returns a reference to the *Document* the node is contained within. In the code below I get a reference to the *Document* of the *`<body>`* in the HTML document and the*Document* node for the *`<body>`* element contained inside of the iframe. live code: N/A ~~~ <!DOCTYPE html> <html lang="en"> <body> <iframe src="http://someFileServedFromServerOnSameDomain.html"></iframe> <script> //get the window.document that the <body> is contained within console.log(document.body.ownerElement); //get the window.document the <body> inside of the iframe is contained within console.log(window.frames[0].document.body.ownerElement); </script> </body> </html> ~~~ If *ownerDocument* is called on the *Document* node the value returned is *null*.
';