summaryrefslogtreecommitdiffstats
path: root/toolkit/components/microformats/test/lib/domutils.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/microformats/test/lib/domutils.js')
-rw-r--r--toolkit/components/microformats/test/lib/domutils.js611
1 files changed, 611 insertions, 0 deletions
diff --git a/toolkit/components/microformats/test/lib/domutils.js b/toolkit/components/microformats/test/lib/domutils.js
new file mode 100644
index 000000000..57269de97
--- /dev/null
+++ b/toolkit/components/microformats/test/lib/domutils.js
@@ -0,0 +1,611 @@
+/*
+ dom utilities
+ The purpose of this module is to abstract DOM functions away from the main parsing modules of the library.
+ It was created so the file can be replaced in node.js environment to make use of different types of light weight node.js DOM's
+ such as 'cherrio.js'. It also contains a number of DOM utilities which are used throughout the parser such as: 'getDescendant'
+
+ Copyright (C) 2010 - 2015 Glenn Jones. All Rights Reserved.
+ MIT License: https://raw.github.com/glennjones/microformat-shiv/master/license.txt
+ Dependencies utilities.js
+
+*/
+
+
+var Modules = (function (modules) {
+
+ modules.domUtils = {
+
+ // blank objects for DOM
+ document: null,
+ rootNode: null,
+
+
+ /**
+ * gets DOMParser object
+ *
+ * @return {Object || undefined}
+ */
+ getDOMParser: function () {
+ if (typeof DOMParser === undefined) {
+ try {
+ return Components.classes["@mozilla.org/xmlextras/domparser;1"]
+ .createInstance(Components.interfaces.nsIDOMParser);
+ } catch (e) {
+ return undefined;
+ }
+ } else {
+ return new DOMParser();
+ }
+ },
+
+
+ /**
+ * configures what are the base DOM objects for parsing
+ *
+ * @param {Object} options
+ * @return {DOM Node} node
+ */
+ getDOMContext: function( options ){
+
+ // if a node is passed
+ if(options.node){
+ this.rootNode = options.node;
+ }
+
+
+ // if a html string is passed
+ if(options.html){
+ //var domParser = new DOMParser();
+ var domParser = this.getDOMParser();
+ this.rootNode = domParser.parseFromString( options.html, 'text/html' );
+ }
+
+
+ // find top level document from rootnode
+ if(this.rootNode !== null){
+ if(this.rootNode.nodeType === 9){
+ this.document = this.rootNode;
+ this.rootNode = modules.domUtils.querySelector(this.rootNode, 'html');
+ }else{
+ // if it's DOM node get parent DOM Document
+ this.document = modules.domUtils.ownerDocument(this.rootNode);
+ }
+ }
+
+
+ // use global document object
+ if(!this.rootNode && document){
+ this.rootNode = modules.domUtils.querySelector(document, 'html');
+ this.document = document;
+ }
+
+
+ if(this.rootNode && this.document){
+ return {document: this.document, rootNode: this.rootNode};
+ }
+
+ return {document: null, rootNode: null};
+ },
+
+
+
+ /**
+ * gets the first DOM node
+ *
+ * @param {Dom Document}
+ * @return {DOM Node} node
+ */
+ getTopMostNode: function( node ){
+ //var doc = this.ownerDocument(node);
+ //if(doc && doc.nodeType && doc.nodeType === 9 && doc.documentElement){
+ // return doc.documentElement;
+ //}
+ return node;
+ },
+
+
+
+ /**
+ * abstracts DOM ownerDocument
+ *
+ * @param {DOM Node} node
+ * @return {Dom Document}
+ */
+ ownerDocument: function(node){
+ return node.ownerDocument;
+ },
+
+
+ /**
+ * abstracts DOM textContent
+ *
+ * @param {DOM Node} node
+ * @return {String}
+ */
+ textContent: function(node){
+ if(node.textContent){
+ return node.textContent;
+ }else if(node.innerText){
+ return node.innerText;
+ }
+ return '';
+ },
+
+
+ /**
+ * abstracts DOM innerHTML
+ *
+ * @param {DOM Node} node
+ * @return {String}
+ */
+ innerHTML: function(node){
+ return node.innerHTML;
+ },
+
+
+ /**
+ * abstracts DOM hasAttribute
+ *
+ * @param {DOM Node} node
+ * @param {String} attributeName
+ * @return {Boolean}
+ */
+ hasAttribute: function(node, attributeName) {
+ return node.hasAttribute(attributeName);
+ },
+
+
+ /**
+ * does an attribute contain a value
+ *
+ * @param {DOM Node} node
+ * @param {String} attributeName
+ * @param {String} value
+ * @return {Boolean}
+ */
+ hasAttributeValue: function(node, attributeName, value) {
+ return (this.getAttributeList(node, attributeName).indexOf(value) > -1);
+ },
+
+
+ /**
+ * abstracts DOM getAttribute
+ *
+ * @param {DOM Node} node
+ * @param {String} attributeName
+ * @return {String || null}
+ */
+ getAttribute: function(node, attributeName) {
+ return node.getAttribute(attributeName);
+ },
+
+
+ /**
+ * abstracts DOM setAttribute
+ *
+ * @param {DOM Node} node
+ * @param {String} attributeName
+ * @param {String} attributeValue
+ */
+ setAttribute: function(node, attributeName, attributeValue){
+ node.setAttribute(attributeName, attributeValue);
+ },
+
+
+ /**
+ * abstracts DOM removeAttribute
+ *
+ * @param {DOM Node} node
+ * @param {String} attributeName
+ */
+ removeAttribute: function(node, attributeName) {
+ node.removeAttribute(attributeName);
+ },
+
+
+ /**
+ * abstracts DOM getElementById
+ *
+ * @param {DOM Node || DOM Document} node
+ * @param {String} id
+ * @return {DOM Node}
+ */
+ getElementById: function(docNode, id) {
+ return docNode.querySelector( '#' + id );
+ },
+
+
+ /**
+ * abstracts DOM querySelector
+ *
+ * @param {DOM Node || DOM Document} node
+ * @param {String} selector
+ * @return {DOM Node}
+ */
+ querySelector: function(docNode, selector) {
+ return docNode.querySelector( selector );
+ },
+
+
+ /**
+ * get value of a Node attribute as an array
+ *
+ * @param {DOM Node} node
+ * @param {String} attributeName
+ * @return {Array}
+ */
+ getAttributeList: function(node, attributeName) {
+ var out = [],
+ attList;
+
+ attList = node.getAttribute(attributeName);
+ if(attList && attList !== '') {
+ if(attList.indexOf(' ') > -1) {
+ out = attList.split(' ');
+ } else {
+ out.push(attList);
+ }
+ }
+ return out;
+ },
+
+
+ /**
+ * gets all child nodes with a given attribute
+ *
+ * @param {DOM Node} node
+ * @param {String} attributeName
+ * @return {NodeList}
+ */
+ getNodesByAttribute: function(node, attributeName) {
+ var selector = '[' + attributeName + ']';
+ return node.querySelectorAll(selector);
+ },
+
+
+ /**
+ * gets all child nodes with a given attribute containing a given value
+ *
+ * @param {DOM Node} node
+ * @param {String} attributeName
+ * @return {DOM NodeList}
+ */
+ getNodesByAttributeValue: function(rootNode, name, value) {
+ var arr = [],
+ x = 0,
+ i,
+ out = [];
+
+ arr = this.getNodesByAttribute(rootNode, name);
+ if(arr) {
+ i = arr.length;
+ while(x < i) {
+ if(this.hasAttributeValue(arr[x], name, value)) {
+ out.push(arr[x]);
+ }
+ x++;
+ }
+ }
+ return out;
+ },
+
+
+ /**
+ * gets attribute value from controlled list of tags
+ *
+ * @param {Array} tagNames
+ * @param {String} attributeName
+ * @return {String || null}
+ */
+ getAttrValFromTagList: function(node, tagNames, attributeName) {
+ var i = tagNames.length;
+
+ while(i--) {
+ if(node.tagName.toLowerCase() === tagNames[i]) {
+ var attrValue = this.getAttribute(node, attributeName);
+ if(attrValue && attrValue !== '') {
+ return attrValue;
+ }
+ }
+ }
+ return null;
+ },
+
+
+ /**
+ * get node if it has no siblings. CSS equivalent is :only-child
+ *
+ * @param {DOM Node} rootNode
+ * @param {Array} tagNames
+ * @return {DOM Node || null}
+ */
+ getSingleDescendant: function(node){
+ return this.getDescendant( node, null, false );
+ },
+
+
+ /**
+ * get node if it has no siblings of the same type. CSS equivalent is :only-of-type
+ *
+ * @param {DOM Node} rootNode
+ * @param {Array} tagNames
+ * @return {DOM Node || null}
+ */
+ getSingleDescendantOfType: function(node, tagNames){
+ return this.getDescendant( node, tagNames, true );
+ },
+
+
+ /**
+ * get child node limited by presence of siblings - either CSS :only-of-type or :only-child
+ *
+ * @param {DOM Node} rootNode
+ * @param {Array} tagNames
+ * @return {DOM Node || null}
+ */
+ getDescendant: function( node, tagNames, onlyOfType ){
+ var i = node.children.length,
+ countAll = 0,
+ countOfType = 0,
+ child,
+ out = null;
+
+ while(i--) {
+ child = node.children[i];
+ if(child.nodeType === 1) {
+ if(tagNames){
+ // count just only-of-type
+ if(this.hasTagName(child, tagNames)){
+ out = child;
+ countOfType++;
+ }
+ }else{
+ // count all elements
+ out = child;
+ countAll++;
+ }
+ }
+ }
+ if(onlyOfType === true){
+ return (countOfType === 1)? out : null;
+ }else{
+ return (countAll === 1)? out : null;
+ }
+ },
+
+
+ /**
+ * is a node one of a list of tags
+ *
+ * @param {DOM Node} rootNode
+ * @param {Array} tagNames
+ * @return {Boolean}
+ */
+ hasTagName: function(node, tagNames){
+ var i = tagNames.length;
+ while(i--) {
+ if(node.tagName.toLowerCase() === tagNames[i]) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+
+ /**
+ * abstracts DOM appendChild
+ *
+ * @param {DOM Node} node
+ * @param {DOM Node} childNode
+ * @return {DOM Node}
+ */
+ appendChild: function(node, childNode){
+ return node.appendChild(childNode);
+ },
+
+
+ /**
+ * abstracts DOM removeChild
+ *
+ * @param {DOM Node} childNode
+ * @return {DOM Node || null}
+ */
+ removeChild: function(childNode){
+ if (childNode.parentNode) {
+ return childNode.parentNode.removeChild(childNode);
+ }else{
+ return null;
+ }
+ },
+
+
+ /**
+ * abstracts DOM cloneNode
+ *
+ * @param {DOM Node} node
+ * @return {DOM Node}
+ */
+ clone: function(node) {
+ var newNode = node.cloneNode(true);
+ newNode.removeAttribute('id');
+ return newNode;
+ },
+
+
+ /**
+ * gets the text of a node
+ *
+ * @param {DOM Node} node
+ * @return {String}
+ */
+ getElementText: function( node ){
+ if(node && node.data){
+ return node.data;
+ }else{
+ return '';
+ }
+ },
+
+
+ /**
+ * gets the attributes of a node - ordered by sequence in html
+ *
+ * @param {DOM Node} node
+ * @return {Array}
+ */
+ getOrderedAttributes: function( node ){
+ var nodeStr = node.outerHTML,
+ attrs = [];
+
+ for (var i = 0; i < node.attributes.length; i++) {
+ var attr = node.attributes[i];
+ attr.indexNum = nodeStr.indexOf(attr.name);
+
+ attrs.push( attr );
+ }
+ return attrs.sort( modules.utils.sortObjects( 'indexNum' ) );
+ },
+
+
+ /**
+ * decodes html entities in given text
+ *
+ * @param {DOM Document} doc
+ * @param String} text
+ * @return {String}
+ */
+ decodeEntities: function( doc, text ){
+ //return text;
+ return doc.createTextNode( text ).nodeValue;
+ },
+
+
+ /**
+ * clones a DOM document
+ *
+ * @param {DOM Document} document
+ * @return {DOM Document}
+ */
+ cloneDocument: function( document ){
+ var newNode,
+ newDocument = null;
+
+ if( this.canCloneDocument( document )){
+ newDocument = document.implementation.createHTMLDocument('');
+ newNode = newDocument.importNode( document.documentElement, true );
+ newDocument.replaceChild(newNode, newDocument.querySelector('html'));
+ }
+ return (newNode && newNode.nodeType && newNode.nodeType === 1)? newDocument : document;
+ },
+
+
+ /**
+ * can environment clone a DOM document
+ *
+ * @param {DOM Document} document
+ * @return {Boolean}
+ */
+ canCloneDocument: function( document ){
+ return (document && document.importNode && document.implementation && document.implementation.createHTMLDocument);
+ },
+
+
+ /**
+ * get the child index of a node. Used to create a node path
+ *
+ * @param {DOM Node} node
+ * @return {Int}
+ */
+ getChildIndex: function (node) {
+ var parent = node.parentNode,
+ i = -1,
+ child;
+ while (parent && (child = parent.childNodes[++i])){
+ if (child === node){
+ return i;
+ }
+ }
+ return -1;
+ },
+
+
+ /**
+ * get a node's path
+ *
+ * @param {DOM Node} node
+ * @return {Array}
+ */
+ getNodePath: function (node) {
+ var parent = node.parentNode,
+ path = [],
+ index = this.getChildIndex(node);
+
+ if(parent && (path = this.getNodePath(parent))){
+ if(index > -1){
+ path.push(index);
+ }
+ }
+ return path;
+ },
+
+
+ /**
+ * get a node from a path.
+ *
+ * @param {DOM document} document
+ * @param {Array} path
+ * @return {DOM Node}
+ */
+ getNodeByPath: function (document, path) {
+ var node = document.documentElement,
+ i = 0,
+ index;
+ while ((index = path[++i]) > -1){
+ node = node.childNodes[index];
+ }
+ return node;
+ },
+
+
+ /**
+ * get an array/nodeList of child nodes
+ *
+ * @param {DOM node} node
+ * @return {Array}
+ */
+ getChildren: function( node ){
+ return node.children;
+ },
+
+
+ /**
+ * create a node
+ *
+ * @param {String} tagName
+ * @return {DOM node}
+ */
+ createNode: function( tagName ){
+ return this.document.createElement(tagName);
+ },
+
+
+ /**
+ * create a node with text content
+ *
+ * @param {String} tagName
+ * @param {String} text
+ * @return {DOM node}
+ */
+ createNodeWithText: function( tagName, text ){
+ var node = this.document.createElement(tagName);
+ node.innerHTML = text;
+ return node;
+ }
+
+
+
+ };
+
+ return modules;
+
+} (Modules || {}));