As the title.
And is there a picture which introduces HTML DOM's construct?
The DOM (Document Object Model) begins at the document node. It is referred to as the "root node".
Observe the following tree (corresponding nodeTypes in parentheses):
[HTMLDocument](9)
[DocumentType](10)
[HTMLHTMLElement](1)
[HTMLHeadElement](1)
[HTMLTitleElement](1)
[Text]Title(3)
[HTMLBodyElement](1)
The tree¹ would be formed from the following markup:
<!DOCTYPE HTML><html><head><title>Title</title></head></body></html>
Note the distinct lack of whitespace. Adding whitespace would add text nodes to the document tree and clearly make it more difficult to simulate.
The window object is not part of the DOM. It is a host object implemented as the "global object" to complete an ECMAScript implementation. It has its own standard which is available from the W3C. Whereas the global object is required to complete an ECMAScript implementation, the DOM is not. This is exemplified in the node.js environment.
¹ Certain environments ignore the doctype node. I've observed Opera 5-9 and Safari 3.1 as environments that exhibit this behaviour.
There is no public standard for window, but most browsers support it with Window at the root.
I've found a lot of good stuff at: http://www.w3schools.com (I have no connection with the site).
A simple google search for "dom html" images will get you images. Then...
When all else fails - go to the source: http://www.w3.org/TR/DOM-Level-2-HTML/html.html
Related
A teammate of mine wrote some code about a short time ago which navigated about the DOM elements in out HTML page to pre-fill some fields in a modal based on the already existing data in an object (the modal allowed a user to edit that data). The items are generated generically from a database table.
function showModal(editImage) {
var modal = document.getElementById('myModal');
var span = document.getElementsByClassName("close")[0];
var nameAndTitle = editImage.srcElement.parentElement.innerHTML;
var parent = editImage.srcElement.parentElement.parentElement;
etc....
The problem is, they only tested that it worked in Chrome. The code never worked in firefox, it seems. When I try to open one of the modals in firefox, I get the console output "TypeError: editImage.srcElement is undefined"
My question is, is there a more "correct" way to access this data that will work for any browser, or do I need to check what browser I am in and access that information in a different way depending on the browser being used?
Your immediate answer is: change srcElement to target. The Mozilla Developer Network is a very good (one of many) resource to check for standards compliance. A visit to their site for srcElement indicates that it is non-standard and makes the suggestion on the correct way (target).
Unfortunately, even APIs that are standard don't always work in all browsers. Usually, parts of a standard are implemented piecemail. Checking with authoritative sources is vital to know what is supported where.
Other resources:
The World Wide Web Consortium (W3C) for HTML, CSS, XML and many others
The European Computer Manufacturer's Association (ECMA) for JavaScript
CanIUse.com Good for quick compatibility compliance checking
As for your explicit question:
"My question is, is there a more "correct" way to access this data that will work for any browser, or do I need to check what browser I am in and access that information in a different way depending on the browser being used?"
Use standards and check for support (via the resources I've provided above) to have the best chance at cross-browser code.
DO NOT write code that checks the browser type and version to see if your code will run (browser detection) because:
There are too many browsers and too many versions - this sucks!
Browsers can and will lie to you about what they are!
Use "feature detection" when in doubt. Feature detection is code that evaluates whether a feature exists and uses it if it does. If it doesn't a fallback is provided. Here's a very common one for IE8 (and lower) browsers that did not yet support the W3C standard for event handling:
// Here we are attempting to obtain the value of the
// addEventListener property of the window object.
// IE 8 doesn't implement this property so "undefined"
// will be returned. But, because we are attempting to
// use the value as the condition of an if/then construct
// "undefined" will be converted to a boolean. "undefined"
// is a "falsey" value, so it will convert to false.
// This means that if the else portion of our construct
// is reached, we have a browser that doesn't support
// addEventListener
if(window.addEventListener){
// W3C standards are supported - do things the standard way
obj.addEventListener("click", someFunction, capture);
} else {
// Must be IE 8 or less - do things the IE way
obj.attachEvent("onclick", someFunction);
}
This is but one way to use feature detection, but it typically hinges on converting a value to a boolean. See more on it here.
That function showModal is probably an event listener, so the argument editImage is actually an Event object.
As such, the actual property that reports the source of the event - and the only one supported by Firefox - is target, while srcElement is a legacy property that was created by Microsoft and Webkit/Blink based browsers kept supporting it for compatibility. But not Firefox.
In short: use target or, if you need to support older version of Internet Explorer, try with (editImage.target || editImage.srcElement).
srcElement is from IE. The standard property is target.
You should do this:
var target = editImage.srcElement || editImage.target;
I was just forced into a browser upgrade (IE8 to IE11) while in the middle of testing. I've lost some essential functionality with some javascript that suddenly doesn't work in my .NET site.
This section of the code was written when I was in grade school, so I'm not extremely familiar with it, but what seems to be the problem is a call to form.all. I have to assume that call was built into javascript at some point - there's no definition for it in the code.
There are 7 "if statements" that use form.all and they are all written the same way:
if(form.all(cTag + "PersonNum") != null)
form.all(cTag + "PersonNum").value = personNumber;
The error:
JavaScript runtime error: Object doesn't support property or method 'all'
In newer versions of JavaScript, is there a version of form.all that performs the same action? All I really need is for someone to point me in the right direction.
A weird note: the same JavaScript code IS working in production on IE11
EDIT Ok, I found a line that was minimized. It looks like form is a created variable.
var form = document.forms(0);
EDIT2 Compatibility view/mode was the solution after all. I had added our production site's domain to the compatibility list and didn't think about it; adding 'localhost' fixed the issue. You just have to set it to the right domain first for it to work :)
Check the browser compatability mode when your running in production it's probally on IE8.
You can use obj.getElementsByTagName("*")
You could also add an All method to the prototype if it's not there.
IE introduced an all property for certain DOM objects (e.g. document) but it was never part of any W3C standard. It allowed access to DOM objects by name or ID using:
var element = document(elementNameOrID);
or
var element = document[elementNameOrID];
that is, it is a property that could use the same syntax as a method. Neat. Some other browsers supported it for compatibility, but it pretty much went out of use with IE 6 (not sure when IE started supporting getElementById, I think it was IE 5). But IE continued to think name and ID attributes were the same thing until IE 8 in standards mode.
Support for all has been dropped from IE 11 in standards mode.
If form is a reference to a form element, and cTag + "PersonNum" is the name of a form control, then the simplest fix is to change:
form.all(cTag + "PersonNum").value
to
form[cTag + "PersonNum"].value
which takes advantage of named form controls being made properties of the form that contains them. This behaviour is standardised and supported by browsers from the very beginning (i.e. every where) and is future proof (it's not going to change).
What I want to do is to serialize a DOM to XML. So I create a new document
var doc = document.implementation.createDocument ('http://AOR-AppML.org', 'Application', null);
and I add nodes, attributes etc. This is working fine.
The problem is that I have different behaviours with XMLSerializer in Google Chrome and Mozilla Firefox.
Chrome console output:
<Application xmlns="http://AOR-AppML.org" name="SoRiN"><ObjectType name="ObjectTypeName"/><Enumeration name="EnumerationName"/></Application>
Firefox console output (notice the xmlns=""):
<Application xmlns="http://AOR-AppML.org" name="SoRiN"><ObjectType xmlns="" name="ObjectTypeName"/><Enumeration xmlns="" name="EnumerationName"/></Application>
I don't want to generate that empty namespace. I've read this namespaces indicates that the corresponding elements have no default namespace (http://www.w3.org/TR/xml-names/#defaulting), but actually I want them to be in the same namespace as Application.
Is there any way to prevent the namespace generation in Firefox?
P.S. - yes, I've followed the advice from this post -> How to prevent the namespace generation?
UPDATE
Here is a fiddle to play with.
You have to use the method createElementNS, instead of createElement, since the latter creates an element with empty namespace URI.
Chrome serializes incorrectly the document (if you parse the string you would get a different document, with namespace URIs wrong), Firefox does the job right. Actually a bug was filed and marked as solved, but the problem seems to be still there.
So, simply replace doc.createElement(yourElementName) with doc.createElementNS('http://AOR-AppML.org', yourElementName).
I would like to use javascript XPaths in a web app using exslt extensions, but I can't figure out how to do this.
Pretend I've got an html doc with some divs in it. I want to run this:
namespaces={'regexp':'http://exslt.org/regular-expressions'};
result = document.evaluate(
"//div[regexp:test(.,'$')]",
document,
function(ns){
return namespaces.hasOwnProperty(ns) ? namespaces[ns] : null;
},
XPathResult.ANY_TYPE,
null);
Only that results in an invalid XPath expression exception in evaluate. I'm using chrome.
Is there anything else I need to do to make this stuff work? I see on exslt.org that there are implementations for javascript, but how do I make sure those are available? Do I need to insert my javascript into a namespaced script element in the dom or something insane?
UPDATE
If this isn't possible directly using browser dom + javascript and xpath, would it be possible to write XSLT using exslt extensions in the browser to simulate document.evaluate (returning a list of elements that match the xpath)?
I don't think the default browser XPath implementation supports EXSLT. The javascript support mentioned on the EXSLT page is likely about how you can provide your own implementation of the exslt function using in-browser.javascript. Here's one example I was able to find very quickly.
In Firefox, for example, you can have Saxon-B as an extension to run XSLT2.0 and Saxon-B has built-in support for exslt (unlike Saxon-HE), though you will likely be better off just using XSLT/XPath 2.0 features. Here's the regular expression syntax, for example. That said, however, relying on a Mozilla Saxon-B extension isn't something that will help you with Chrome or other browsers for that matter.
With that said I don't think you can find a cross-browser solution to use EXSLT extensions in your XPath. The conformance section of the DOM Level 3 XPath calls for XPath 1.0 support and doesn't mention EXSLT. The INVALID_EXPRESSION_ERR is said to be thrown:
if the expression has a syntax error or otherwise is not a legal expression according to the rules of the specific XPathEvaluator or contains specialized extension functions or variables not supported by this implementation.
Finally, here's an open bugzilla ticket for Firefox to open up EXSLT support for their DOM Level 3 XPath implementation. It seems to be sitting there in NEW status since 2007. The ticket says that:
Currently Mozilla gives an exception "The expression is not a legal expression." even if a namespace resolver correctly resolving the EXSLT prefixes to the corresponding URLs is passed in. Here's the test case.
--
If you don't mind me asking, what exactly you wanted to use the regex for? Maybe we can help you get away with a combination of standard XPath string functions?
--
UPDATE You can build an XPath runner via XSLT (like you're asking in the update to your question) but it won't return the nodes from the source document, it will return new nodes that look exactly the same. XSLT produces a new result tree document and I don't think there's a way to let it return references to the original nodes.
As far as I can tell, Mozilla (and Chrome) both support XSLT not only for XML documents loaded from external sources, but also for DOM elements from the document being displayed. The XSLTProcessor documentation mentions how tranformToFragment(), for example, will only produce HTML DOM objects if the owner document is itself an HTMLDocument, or if the output method of the stylesheet is HTML.
Here's a simple XPath Runner that I built testing out your ides:
1) First you would need an XSLT template to work with.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:regexp="http://exslt.org/regular-expressions"
extension-element-prefixes="regexp">
<xsl:template match="/">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
I started building it in the JavaScript using the document.implementation.createDocument APi but figured it would be easier to just load it. FF still supports document.load while Chrome only lets you load stuff using XHR. You would need to start your Chrome with --allow-file-access-from-files if you want to load files with XHR from your local disk.
2) Once we have the template loaded we would need to modify the value of the select attribute of the xsl:copy-of instruction to run the XPath we need:
function runXPath(xpath) {
var processor = new XSLTProcessor();
var xsltns = 'http://www.w3.org/1999/XSL/Transform';
var xmlhttp = new window.XMLHttpRequest();
xmlhttp.open("GET", "xpathrunner.xslt", false);
xmlhttp.send(null);
var transform = xmlhttp.responseXML.documentElement;
var copyof = transform.getElementsByTagNameNS(xsltns, 'copy-of')[0];
copyof.setAttribute('select', xpath);
processor.importStylesheet(transform);
var body = document.getElementById('body'); // I gave my <body> an id attribute
return processor.transformToFragment(body, document);
}
You can now run it with something like:
var nodes = runXPath('//div[#id]');
console.log(nodes.hasChildNodes());
if (nodes.firstChild) {
console.log(nodes.firstChild.localName);
}
It works great for "regular" XPath like that //div[#id] (and fails to find //div[#not-there]) but I just can't get it to run the regexp:test extension function. With the //div[regexp:test(string(#id), "a")] it doesn't error out, just returns empty set.
Mozilla documentation suggests their XSLT processor support EXSLT. I would imagine they are all using libxml/libxslt behind the scenes anyway. That said, I couldn't get it to work in Mozilla either.
Hope it helps.
Any chance you can get away with jQuery regexp? not likely to be helpful for your XPath builder utility but still a way to run regexp on HTML nodes.
I cannot seem to find a link for a HTML api.
I want to see element.innerHtml, element.OuterHtML. Basically all methods I can invoke in a javascript function to get an elements rendered/not rendered text. Thank you very much
I think you are looking for the DOM API.
You can find it on the w3 site.
The HTML specification is about the structure of the HTML document, not how to access it with innerHTML and other methods.
Try out : https://developer.mozilla.org/en/DOM/element
MDC Doc center is a great reference to use for everything relative to HTML. You can generally find the pages from MDC directly from google. Here I searched "element MDC"
Cheers,
-stan
You want the spec for the Document Object Model.
http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
http://www.w3.org/DOM/DOMTR
A cleaner list can be found here:
https://developer.mozilla.org/en/DOM/element
There is the W3C DOM Level 2 HTML specification which documents some of the bindings you may be interested in. (Seven years ago I put this into a more browsable format here: http://objjob.phrogz.net/html/hierarchy)
However, some of the properties you discuss, such as innerHTML are considered "DOM Level 0". They were implemented by browsers before there was a standard.
You might also be interested in the MSDN DHTML reference, which documents properties, methods, and more supported by various versions of IE. While some of them are non-standard, the documentation these days generally indicates which items are standard and which are proprietary extensions.
Finally, there is the Gecko DOM Reference which provides good information from Mozilla.