src/dom/implementation.js in envjs-0.3.7 vs src/dom/implementation.js in envjs-0.3.8

- old
+ new

@@ -35,11 +35,11 @@ return new DOMDocumentType(); }, createDocument : function(nsuri, qname, doctype){ //TODO - this currently returns an empty doc //but needs to handle the args - return new Document(this, null); + return new DOMDocument(this, null); }, createHTMLDocument : function(title){ // N.B. explict window on purpose ... var doc = new HTMLDocument(this, window, ""); var html = doc.createElement("html"); doc.appendChild(html); @@ -123,471 +123,9 @@ return msg; } }); - -/** -* Defined 'globally' to this scope. Remember everything is wrapped in a closure so this doesnt show up -* in the outer most global scope. -*/ - -/** - * process SAX events - * - * @author Jon van Noort (jon@webarcana.com.au), David Joham (djoham@yahoo.com) and Scott Severtson - * - * @param impl : DOMImplementation - * @param doc : DOMDocument - the Document to contain the parsed XML string - * @param p : XMLP - the SAX Parser - * - * @return : DOMDocument - */ - -function __parseLoop__(impl, doc, p, isWindowDocument) { - var iEvt, iNode, iAttr, strName; - var iNodeParent = doc; - - var el_close_count = 0; - - var entitiesList = new Array(); - var textNodesList = new Array(); - - // if namespaceAware, add default namespace - if (impl.namespaceAware) { - var iNS = doc.createNamespace(""); // add the default-default namespace - iNS.value = "http://www.w3.org/2000/xmlns/"; - doc._namespaces.setNamedItem(iNS); - } - - // loop until SAX parser stops emitting events - var q = 0; - while(true) { - // get next event - iEvt = p.next(); - - if (iEvt == XMLP._ELM_B) { // Begin-Element Event - var pName = p.getName(); // get the Element name - pName = trim(pName, true, true); // strip spaces from Element name - if(pName.toLowerCase() == 'script') - p.replaceEntities = false; - - if (!impl.namespaceAware) { - iNode = doc.createElement(p.getName()); // create the Element - // add attributes to Element - for(var i = 0; i < p.getAttributeCount(); i++) { - strName = p.getAttributeName(i); // get Attribute name - iAttr = iNode.getAttributeNode(strName); // if Attribute exists, use it - - if(!iAttr) { - iAttr = doc.createAttribute(strName); // otherwise create it - } - - iAttr.value = p.getAttributeValue(i); // set Attribute value - iNode.setAttributeNode(iAttr); // attach Attribute to Element - } - } - else { // Namespace Aware - // create element (with empty namespaceURI, - // resolve after namespace 'attributes' have been parsed) - iNode = doc.createElementNS("", p.getName()); - - // duplicate ParentNode's Namespace definitions - iNode._namespaces = __cloneNamedNodes__(iNodeParent._namespaces, iNode, true); - - // add attributes to Element - for(var i = 0; i < p.getAttributeCount(); i++) { - strName = p.getAttributeName(i); // get Attribute name - - // if attribute is a namespace declaration - if (__isNamespaceDeclaration__(strName)) { - // parse Namespace Declaration - var namespaceDec = __parseNSName__(strName); - - if (strName != "xmlns") { - iNS = doc.createNamespace(strName); // define namespace - } - else { - iNS = doc.createNamespace(""); // redefine default namespace - } - iNS.value = p.getAttributeValue(i); // set value = namespaceURI - - iNode._namespaces.setNamedItem(iNS); // attach namespace to namespace collection - } - else { // otherwise, it is a normal attribute - iAttr = iNode.getAttributeNode(strName); // if Attribute exists, use it - - if(!iAttr) { - iAttr = doc.createAttributeNS("", strName); // otherwise create it - } - - iAttr.value = p.getAttributeValue(i); // set Attribute value - iNode.setAttributeNodeNS(iAttr); // attach Attribute to Element - - if (__isIdDeclaration__(strName)) { - iNode.id = p.getAttributeValue(i); // cache ID for getElementById() - } - } - } - - // resolve namespaceURIs for this Element - if (iNode._namespaces.getNamedItem(iNode.prefix)) { - iNode.namespaceURI = iNode._namespaces.getNamedItem(iNode.prefix).value; - } else { - iNode.namespaceURI = iNodeParent.namespaceURI; - } - - // for this Element's attributes - for (var i = 0; i < iNode.attributes.length; i++) { - if (iNode.attributes.item(i).prefix != "") { // attributes do not have a default namespace - if (iNode._namespaces.getNamedItem(iNode.attributes.item(i).prefix)) { - iNode.attributes.item(i).namespaceURI = iNode._namespaces.getNamedItem(iNode.attributes.item(i).prefix).value; - } - } - } - - // We didn't know the NS of the node when we created it, which means we created a default DOM object. - // Now that we know the NS, if there is one, we clone this node so that it'll get created under - // with the right constructor. This makes things like SVG work. Might be nice not to create twice as - // as many nodes, but that's painfully given the complexity of namespaces. - if(iNode.namespaceURI != ""){ - iNode = iNode.cloneNode(); - } - } - - // if this is the Root Element - if (iNodeParent.nodeType == DOMNode.DOCUMENT_NODE) { - iNodeParent._documentElement = iNode; // register this Element as the Document.documentElement - } - - iNodeParent.appendChild(iNode); // attach Element to parentNode - iNodeParent = iNode; // descend one level of the DOM Tree - } - - else if(iEvt == XMLP._ELM_E) { // End-Element Event - iNodeParent = iNodeParent.parentNode; // ascend one level of the DOM Tree - } - - else if(iEvt == XMLP._ELM_EMP) { // Empty Element Event - pName = p.getName(); // get the Element name - pName = trim(pName, true, true); // strip spaces from Element name - - if (!impl.namespaceAware) { - iNode = doc.createElement(pName); // create the Element - - // add attributes to Element - for(var i = 0; i < p.getAttributeCount(); i++) { - strName = p.getAttributeName(i); // get Attribute name - iAttr = iNode.getAttributeNode(strName); // if Attribute exists, use it - - if(!iAttr) { - iAttr = doc.createAttribute(strName); // otherwise create it - } - - iAttr.value = p.getAttributeValue(i); // set Attribute value - iNode.setAttributeNode(iAttr); // attach Attribute to Element - } - } - else { // Namespace Aware - // create element (with empty namespaceURI, - // resolve after namespace 'attributes' have been parsed) - iNode = doc.createElementNS("", p.getName()); - - // duplicate ParentNode's Namespace definitions - iNode._namespaces = __cloneNamedNodes__(iNodeParent._namespaces, iNode); - - // add attributes to Element - for(var i = 0; i < p.getAttributeCount(); i++) { - strName = p.getAttributeName(i); // get Attribute name - - // if attribute is a namespace declaration - if (__isNamespaceDeclaration__(strName)) { - // parse Namespace Declaration - var namespaceDec = __parseNSName__(strName); - - if (strName != "xmlns") { - iNS = doc.createNamespace(strName); // define namespace - } - else { - iNS = doc.createNamespace(""); // redefine default namespace - } - iNS.value = p.getAttributeValue(i); // set value = namespaceURI - - iNode._namespaces.setNamedItem(iNS); // attach namespace to namespace collection - } - else { // otherwise, it is a normal attribute - iAttr = iNode.getAttributeNode(strName); // if Attribute exists, use it - - if(!iAttr) { - iAttr = doc.createAttributeNS("", strName); // otherwise create it - } - - iAttr.value = p.getAttributeValue(i); // set Attribute value - iNode.setAttributeNodeNS(iAttr); // attach Attribute to Element - - if (__isIdDeclaration__(strName)) { - iNode.id = p.getAttributeValue(i); // cache ID for getElementById() - } - } - } - - // resolve namespaceURIs for this Element - if (iNode._namespaces.getNamedItem(iNode.prefix)) { - iNode.namespaceURI = iNode._namespaces.getNamedItem(iNode.prefix).value; - } - - // for this Element's attributes - for (var i = 0; i < iNode.attributes.length; i++) { - if (iNode.attributes.item(i).prefix != "") { // attributes do not have a default namespace - if (iNode._namespaces.getNamedItem(iNode.attributes.item(i).prefix)) { - iNode.attributes.item(i).namespaceURI = iNode._namespaces.getNamedItem(iNode.attributes.item(i).prefix).value; - } - } - } - } - - // if this is the Root Element - if (iNodeParent.nodeType == DOMNode.DOCUMENT_NODE) { - iNodeParent._documentElement = iNode; // register this Element as the Document.documentElement - } - - iNodeParent.appendChild(iNode); // attach Element to parentNode - } - else if(iEvt == XMLP._TEXT || iEvt == XMLP._ENTITY) { // TextNode and entity Events - // get Text content - var pContent = p.getContent().substring(p.getContentBegin(), p.getContentEnd()); - - if (!impl.preserveWhiteSpace ) { - if (trim(pContent, true, true) == "") { - pContent = ""; //this will cause us not to create the text node below - } - } - - if (pContent.length > 0) { // ignore empty TextNodes - var textNode = doc.createTextNode(pContent); - iNodeParent.appendChild(textNode); // attach TextNode to parentNode - - //the sax parser breaks up text nodes when it finds an entity. For - //example hello&lt;there will fire a text, an entity and another text - //this sucks for the dom parser because it looks to us in this logic - //as three text nodes. I fix this by keeping track of the entity nodes - //and when we're done parsing, calling normalize on their parent to - //turn the multiple text nodes into one, which is what DOM users expect - //the code to do this is at the bottom of this function - if (iEvt == XMLP._ENTITY) { - entitiesList[entitiesList.length] = textNode; - } - else { - //I can't properly decide how to handle preserve whitespace - //until the siblings of the text node are built due to - //the entitiy handling described above. I don't know that this - //will be all of the text node or not, so trimming is not appropriate - //at this time. Keep a list of all the text nodes for now - //and we'll process the preserve whitespace stuff at a later time. - textNodesList[textNodesList.length] = textNode; - } - } - } - else if(iEvt == XMLP._PI) { // ProcessingInstruction Event - // attach ProcessingInstruction to parentNode - iNodeParent.appendChild(doc.createProcessingInstruction(p.getName(), p.getContent().substring(p.getContentBegin(), p.getContentEnd()))); - } - else if(iEvt == XMLP._CDATA) { // CDATA Event - // get CDATA data - pContent = p.getContent().substring(p.getContentBegin(), p.getContentEnd()); - - if (!impl.preserveWhiteSpace) { - pContent = trim(pContent, true, true); // trim whitespace - pContent.replace(/ +/g, ' '); // collapse multiple spaces to 1 space - } - - if (pContent.length > 0) { // ignore empty CDATANodes - iNodeParent.appendChild(doc.createCDATASection(pContent)); // attach CDATA to parentNode - } - } - else if(iEvt == XMLP._COMMENT) { // Comment Event - // get COMMENT data - var pContent = p.getContent().substring(p.getContentBegin(), p.getContentEnd()); - - if (!impl.preserveWhiteSpace) { - pContent = trim(pContent, true, true); // trim whitespace - pContent.replace(/ +/g, ' '); // collapse multiple spaces to 1 space - } - - if (pContent.length > 0) { // ignore empty CommentNodes - iNodeParent.appendChild(doc.createComment(pContent)); // attach Comment to parentNode - } - } - else if(iEvt == XMLP._DTD) { // ignore DTD events - } - else if(iEvt == XMLP._ERROR) { - $error("Fatal Error: " + p.getContent() + - "\nLine: " + p.getLineNumber() + - "\nColumn: " + p.getColumnNumber() + "\n"); - throw(new DOMException(DOMException.SYNTAX_ERR)); - } - else if(iEvt == XMLP._NONE) { // no more events - //steven woods notes that unclosed tags are rejected elsewhere and this check - //breaks a table patching routine - //if (iNodeParent == doc) { // confirm that we have recursed back up to root - // break; - //} - //else { - // throw(new DOMException(DOMException.SYNTAX_ERR)); // one or more Tags were not closed properly - //} - break; - - } - } - - //normalize any entities in the DOM to a single textNode - for (var i = 0; i < entitiesList.length; i++) { - var entity = entitiesList[i]; - //its possible (if for example two entities were in the - //same domnode, that the normalize on the first entitiy - //will remove the parent for the second. Only do normalize - //if I can find a parent node - var parentNode = entity.parentNode; - if (parentNode) { - parentNode.normalize(); - - //now do whitespace (if necessary) - //it was not done for text nodes that have entities - if(!impl.preserveWhiteSpace) { - var children = parentNode.childNodes; - for ( var j = 0; j < children.length; j++) { - var child = children.item(j); - if (child.nodeType == DOMNode.TEXT_NODE) { - var childData = child.data; - childData.replace(/\s/g, ' '); - child.data = childData; - } - } - } - } - } - - //do the preserve whitespace processing on the rest of the text nodes - //It's possible (due to the processing above) that the node will have been - //removed from the tree. Only do whitespace checking if parentNode is not null. - //This may duplicate the whitespace processing for some nodes that had entities in them - //but there's no way around that - if (!impl.preserveWhiteSpace) { - for (var i = 0; i < textNodesList.length; i++) { - var node = textNodesList[i]; - if (node.parentNode != null) { - var nodeData = node.data; - nodeData.replace(/\s/g, ' '); - node.data = nodeData; - } - } - - } -}; - - -/** - * @method DOMImplementation._isNamespaceDeclaration - Return true, if attributeName is a namespace declaration - * @author Jon van Noort (jon@webarcana.com.au) - * @param attributeName : string - the attribute name - * @return : boolean - */ -function __isNamespaceDeclaration__(attributeName) { - // test if attributeName is 'xmlns' - return (attributeName.indexOf('xmlns') > -1); -}; - -/** - * @method DOMImplementation._isIdDeclaration - Return true, if attributeName is an id declaration - * @author Jon van Noort (jon@webarcana.com.au) - * @param attributeName : string - the attribute name - * @return : boolean - */ -function __isIdDeclaration__(attributeName) { - // test if attributeName is 'id' (case insensitive) - return attributeName?(attributeName.toLowerCase() == 'id'):false; -}; - -/** - * @method DOMImplementation._isValidName - Return true, - * if name contains no invalid characters - * @author Jon van Noort (jon@webarcana.com.au) - * @param name : string - the candidate name - * @return : boolean - */ -function __isValidName__(name) { - // test if name contains only valid characters - return name.match(re_validName); -}; -var re_validName = /^[a-zA-Z_:][a-zA-Z0-9\.\-_:]*$/; - -/** - * @method DOMImplementation._isValidString - Return true, if string does not contain any illegal chars - * All of the characters 0 through 31 and character 127 are nonprinting control characters. - * With the exception of characters 09, 10, and 13, (Ox09, Ox0A, and Ox0D) - * Note: different from _isValidName in that ValidStrings may contain spaces - * @author Jon van Noort (jon@webarcana.com.au) - * @param name : string - the candidate string - * @return : boolean - */ -function __isValidString__(name) { - // test that string does not contains invalid characters - return (name.search(re_invalidStringChars) < 0); -}; -var re_invalidStringChars = /\x01|\x02|\x03|\x04|\x05|\x06|\x07|\x08|\x0B|\x0C|\x0E|\x0F|\x10|\x11|\x12|\x13|\x14|\x15|\x16|\x17|\x18|\x19|\x1A|\x1B|\x1C|\x1D|\x1E|\x1F|\x7F/; - -/** - * @method DOMImplementation._parseNSName - parse the namespace name. - * if there is no colon, the - * @author Jon van Noort (jon@webarcana.com.au) - * @param qualifiedName : string - The qualified name - * @return : NSName - [ - .prefix : string - The prefix part of the qname - .namespaceName : string - The namespaceURI part of the qname - ] - */ -function __parseNSName__(qualifiedName) { - var resultNSName = new Object(); - - resultNSName.prefix = qualifiedName; // unless the qname has a namespaceName, the prefix is the entire String - resultNSName.namespaceName = ""; - - // split on ':' - var delimPos = qualifiedName.indexOf(':'); - if (delimPos > -1) { - // get prefix - resultNSName.prefix = qualifiedName.substring(0, delimPos); - // get namespaceName - resultNSName.namespaceName = qualifiedName.substring(delimPos +1, qualifiedName.length); - } - return resultNSName; -}; - -/** - * @method DOMImplementation._parseQName - parse the qualified name - * @author Jon van Noort (jon@webarcana.com.au) - * @param qualifiedName : string - The qualified name - * @return : QName - */ -function __parseQName__(qualifiedName) { - var resultQName = new Object(); - - resultQName.localName = qualifiedName; // unless the qname has a prefix, the local name is the entire String - resultQName.prefix = ""; - - // split on ':' - var delimPos = qualifiedName.indexOf(':'); - - if (delimPos > -1) { - // get prefix - resultQName.prefix = qualifiedName.substring(0, delimPos); - - // get localName - resultQName.localName = qualifiedName.substring(delimPos +1, qualifiedName.length); - } - - return resultQName; -}; if(false){ $debug("Initializing document.implementation"); var $implementation = new DOMImplementation(); // $implementation.namespaceAware = false;