DOM Resources
mozile.dom
, mozile.xml
.All modern web browsers have some support for the W3C's Document Object Model, which describes an HTML or XML document as a tree made up of nodes. The trouble is that every browser differs in the way that it support the DOM.
The mozile.dom
module contains a number of functions that were written to bridge the gap between DOM implementations. Take a look at Mozile's API documentation for mozile.dom
. The odds are that if some developer took the trouble to write a function for that module, then there must have been some cross-browser annoyance that prompted him to do it. You should take a look and consider using it in your code.
The mozile.xml
module bridges the differences between browsers when it comes to things like parsing and serializing XML. It also holds a list of common XML namespaces in mozile.xml.ns
.
XML namespace support is important to Mozile. However, namespace support is not even as consistent between browsers as the rest of the DOM is. When Mozile is editing HTML documents, no namespaces should ever be used and all nodes should be HTML nodes. When editing XHTML and XML namespaces should always be used, and all nodes should be XML nodes.
In the DOM, each node is an object. You can navigate from one node to another. You can move nodes. You can create new node and destroy them. But as the structure of the document changes, and nodes move and are replaced, we need a way to access the document by its structure, not just by the nodes. Event if a node has moved from the first paragraph to the fifth paragraph, we still need a way to address the first node of the first paragraph.
XPath is a way of doing just this. The XPath specification is closely tied to the XSL specification, and you can find a good tutorial for bother of them at Zvon.org. You can think of XPath as like a file path; it's a hierarchy which starts at a root and leads to a node. For example:
The numbers inside the square brackets tell us that we want the nth matching node. So in this example we want the first html
element, and the first body
element which is a child of the html
element. Then we want the second div
in the body
, the third p
inside that div
, the first span
in the p
, and the first text node in the span
.
XPath can get much more complicated than this. It can select sets of nodes, along different axes, matching different patterns, and using several built-in functions. However in Mozile we only use simple XPaths like these. The only other complication we use in Mozile is namespaces.
In this example we have nodes from the XHTML and MathML namespaces, as indicated by the xhtml
and mathml
prefixes. That's about as complicated as it gets.
You can look at the API for the mozile.xpath
module, but most of the time we just use mozile.xpath.getXPath()
to get the XPath address of a node, and mozile.xpath.getNode()
to get a node from and XPath address. Any time we need to store a location in the document which might be changed, we store it using XPath.
Mozilla's Gecko rendering engine is known for its standards support. There's also a lot to be said for having access to the Mozilla source code, to see what's happening under the hood. Most of the time, Mozilla's behaviour is the model we follow in Mozile. However, there are also known bugs. And not all of the browsers built on top of Gecko behave the same way in every situation.
One particularly problematic aspect of Mozilla is its designMode
. By setting document.designMode = "on"
an HTML page will enter a mode which allows editing pretty much the same as the old Netscape Composer. Using document.execCommand()
you can add font
tags, etc. You can also resize images and tables. Most importantly, you get a cursor which you can use for editing the document.
If the mozile.useDesignMode
property is true
(which is the default), then Mozile will use designMode
in order to get a cursor. No execCommand()
calls are made, and designMode
is turned off when outside an editable area.
The problem is that designMode
hasn't seen nearly as much attention as other parts of Mozilla, and it has many bugs. The alternative is to use the "Caret Browsing" mode, which can be activated by the user by pressing F7, or by setting the browser preference accessibility.browsewithcaret
. However, the former must be done manually, and the latter requires the UniversalXPConnect
privilege, which is not given to remotely executed scripts (for good reason). Since designMode
doesn't work in XHTML and XML documents, Caret Browsing is the only option. For XHTML and XML documents set mozile.useDesignMode = false
.
Internet Explorer is the most popular browser on the Internet by a large margin. Because it's so dominant it's very difficult to ignore. We may be tempted to ignore it, because its poor standards support often makes developing for Internet Explorer difficult. However, IE does support all the features necessary to make Mozile work. Mozile currently has support for IE 6, and we expect to support IE 7 in the future.
Internet Explorer supports designMode
, like Mozilla does, with all of its shortcomings. IE also supports the superior contentEditable
attribute, which allows selected elements to be made editable while others are not. Mozile uses contentEditable
in order to have a cursor for editing, but it does not use execCommand()
to perform any of its editing operations. When contentEditable
is enabled, IE uses different white space rules than the standard HTML and XML rules. In most ways this makes editing more convenient, and similar functionality has to be explicitly coded by Mozile for Mozilla.
There are many differences in the way IE implements the DOM. The difference which has had the single largest effect on the Mozile architecture is the fact that DOM objects cannot be prototyped in IE the way they can in other browsers. In Mozilla you can declare a new method Text.prototype.foo()
, and all text nodes will gain the foo()
method. Text
is treated as a normal JavaScript object with prototype-based inheritance. In IE this is not the case. Although prototyping of some DOM objects seems to be allowed, in general it is not. Prototyping of XML objects, for instance, is not permitted. Mozile 0.7 made extensive use of prototyping, adding methods like Node.isBlock()
, which in many ways leads to more readable code. But Mozile 0.8 had to abandon this in favour of functions like mozile.edit.isBlock(node)
.
Most of the DOM Level 1 and DOM Level 2 specifications are implemented similarly by IE and Mozilla. IE has limited namespace support in its DOM methods. It does not allow HTML and XML nodes to mix as freely as Mozilla does. IE does not provide a TreeWalker
object, and so Mozile provides one in mozile.dom.TreeWalker
.
The largest gap between Mozilla and Internet Explorer that Mozile developers have had to bridge is between the two range and selection implementations. When the user highlights a range of text, we need to be able to determine the start and end points, and then perform manipulations on that range. Mozilla provides Range
and Selection
objects. End points are specified by the pair of a node and an integer offset; this could be a text node and a number of characters, or an element and a number of child nodes.
Internet Explorer provides a TextRange
and a selection
object. IE does not use pairs of nodes and points to indicate positions, just character offsets within an element. Since selections are critical for editing, a great deal of effort has been put in to wrapping the IE selection system in an interface which is compatible with the Mozilla system. See the mozile.dom.InternetExplorerRange
and mozile.dom.InternetExplorerSelection
modules. By accessing the window's selection using mozile.dom.selection.get()
you can expect the selection object to behave according to the Mozilla model on all supported browsers.
mozile.dom.InternetExplorerRange
and mozile.dom.InternetExplorerSelection
modules do not yet implement all of the Range
and Selection
methods. See the API documentation for details.Internet Explorer's CSS support is not equivalent to Mozilla's in many ways. This affects Mozile's GUI code.
In general, Internet Explorer provides similar features to Mozilla. However be careful of the differences in the way the two implementations work.
Opera 9 adds a number of new features which make editing with Mozile possible. In most ways Opera does a very good job of matching Mozilla's behaviour, and so adapting Mozile's code to work with Opera is generally easy. However, "porting" Mozile to another browser is always time consuming, and Opera support will have to wait for someone to find that time.
The current release version of Safari for Mac OS X 10.4.6 lacks a number of features which Mozila requires, including Selection and Range objects, and XML namespace support. Development versions, however, include more and more of these requirements, so we expect to be able to support Safari at some point in the future.
Since Safari and Konqueror are based on the same WebKit/KHTML rendering engine, to a large extent what goes for one goes for the other. However there are important differences, and Konqueror does not always include the latest changes that Safari features.