Preferably in Javascript.
[Maybe] iterate through all the nodes and console.log() its XPath.
I searched enough and could not find an answer.
Why I need it?
I want to see the coordinates(getBoundingClientRect()) of all leaf nodes of a DOM (means, elements of an HTML).
A combination of How to loop through ALL DOM elements on a page and how do I get the XPath of an element in an X/HTML file
should do:
function getXPath(node) {
var comp, comps = [];
var parent = null;
var xpath = '';
var getPos = function(node) {
var position = 1, curNode;
if (node.nodeType == Node.ATTRIBUTE_NODE) {
return null;
}
for (curNode = node.previousSibling; curNode; curNode = curNode.previousSibling) {
if (curNode.nodeName == node.nodeName) {
++position;
}
}
return position;
}
if (node instanceof Document) {
return '/';
}
for (; node && !(node instanceof Document); node = node.nodeType == Node.ATTRIBUTE_NODE ? node.ownerElement : node.parentNode) {
comp = comps[comps.length] = {};
switch (node.nodeType) {
case Node.TEXT_NODE:
comp.name = 'text()';
break;
case Node.ATTRIBUTE_NODE:
comp.name = '#' + node.nodeName;
break;
case Node.PROCESSING_INSTRUCTION_NODE:
comp.name = 'processing-instruction()';
break;
case Node.COMMENT_NODE:
comp.name = 'comment()';
break;
case Node.ELEMENT_NODE:
comp.name = node.nodeName;
break;
}
comp.position = getPos(node);
}
for (var i = comps.length - 1; i >= 0; i--) {
comp = comps[i];
xpath += '/' + comp.name;
if (comp.position != null) {
xpath += '[' + comp.position + ']';
}
}
return xpath;
}
var all = document.getElementsByTagName("*");
for (var i=0, max=all.length; i < max; i++) {
console.log(getXPath(all[i]));
}
The updated version works much better than the first installment.
Related
On a MouseEvent instance, we have a property called path, it might look like this:
Does anybody know if there is a reliable way to translate this path array into an XPath? I assume that this path data is the best data to start from? Is there a library I can use to do the conversion?
This library looks promising, but it doesn't use the path property of an event: https://github.com/johannhof/xpath-dom
There's not a unique XPath to a node, so you'll have to decide what's the most appropriate way of constructing a path. Use IDs where available? Numeral position in the document? Position relative to other elements?
See getPathTo() in this answer for one possible approach.
PS: Taken from Javascript get XPath of a node
Another option is to use SelectorGadget from below link
https://dv0akt2986vzh.cloudfront.net/unstable/lib/selectorgadget.js
The actual code for the DOM path is at
https://dv0akt2986vzh.cloudfront.net/stable/lib/dom.js
Usage: on http://google.com
elem = document.getElementById("q")
predict = new DomPredictionHelper()
predict.pathOf(elem)
// gives "body.default-theme.des-mat:nth-child(2) div#_Alw:nth-child(4) form#f:nth-child(2) div#fkbx:nth-child(2) input#q:nth-child(2)"
predict.predictCss([elem],[])
// gives "#q"
CODE if link goes down
// Copyright (c) 2008, 2009 Andrew Cantino
// Copyright (c) 2008, 2009 Kyle Maxwell
function DomPredictionHelper() {};
DomPredictionHelper.prototype = new Object();
DomPredictionHelper.prototype.recursiveNodes = function(e){
var n;
if(e.nodeName && e.parentNode && e != document.body) {
n = this.recursiveNodes(e.parentNode);
} else {
n = new Array();
}
n.push(e);
return n;
};
DomPredictionHelper.prototype.escapeCssNames = function(name) {
if (name) {
try {
return name.replace(/\s*sg_\w+\s*/g, '').replace(/\\/g, '\\\\').
replace(/\./g, '\\.').replace(/#/g, '\\#').replace(/\>/g, '\\>').replace(/\,/g, '\\,').replace(/\:/g, '\\:');
} catch(e) {
console.log('---');
console.log("exception in escapeCssNames");
console.log(name);
console.log('---');
return '';
}
} else {
return '';
}
};
DomPredictionHelper.prototype.childElemNumber = function(elem) {
var count = 0;
while (elem.previousSibling && (elem = elem.previousSibling)) {
if (elem.nodeType == 1) count++;
}
return count;
};
DomPredictionHelper.prototype.pathOf = function(elem){
var nodes = this.recursiveNodes(elem);
var self = this;
var path = "";
for(var i = 0; i < nodes.length; i++) {
var e = nodes[i];
if (e) {
path += e.nodeName.toLowerCase();
var escaped = e.id && self.escapeCssNames(new String(e.id));
if(escaped && escaped.length > 0) path += '#' + escaped;
if(e.className) {
jQuery.each(e.className.split(/ /), function() {
var escaped = self.escapeCssNames(this);
if (this && escaped.length > 0) {
path += '.' + escaped;
}
});
}
path += ':nth-child(' + (self.childElemNumber(e) + 1) + ')';
path += ' '
}
}
if (path.charAt(path.length - 1) == ' ') path = path.substring(0, path.length - 1);
return path;
};
DomPredictionHelper.prototype.commonCss = function(array) {
try {
var dmp = new diff_match_patch();
} catch(e) {
throw "Please include the diff_match_patch library.";
}
if (typeof array == 'undefined' || array.length == 0) return '';
var existing_tokens = {};
var encoded_css_array = this.encodeCssForDiff(array, existing_tokens);
var collective_common = encoded_css_array.pop();
jQuery.each(encoded_css_array, function(e) {
var diff = dmp.diff_main(collective_common, this);
collective_common = '';
jQuery.each(diff, function() {
if (this[0] == 0) collective_common += this[1];
});
});
return this.decodeCss(collective_common, existing_tokens);
};
DomPredictionHelper.prototype.tokenizeCss = function(css_string) {
var skip = false;
var word = '';
var tokens = [];
var css_string = css_string.replace(/,/, ' , ').replace(/\s+/g, ' ');
var length = css_string.length;
var c = '';
for (var i = 0; i < length; i++){
c = css_string[i];
if (skip) {
skip = false;
} else if (c == '\\') {
skip = true;
} else if (c == '.' || c == ' ' || c == '#' || c == '>' || c == ':' || c == ',') {
if (word.length > 0) tokens.push(word);
word = '';
}
word += c;
if (c == ' ' || c == ',') {
tokens.push(word);
word = '';
}
}
if (word.length > 0) tokens.push(word);
return tokens;
};
DomPredictionHelper.prototype.decodeCss = function(string, existing_tokens) {
var inverted = this.invertObject(existing_tokens);
var out = '';
jQuery.each(string.split(''), function() {
out += inverted[this];
});
return this.cleanCss(out);
};
// Encode css paths for diff using unicode codepoints to allow for a large number of tokens.
DomPredictionHelper.prototype.encodeCssForDiff = function(strings, existing_tokens) {
var codepoint = 50;
var self = this;
var strings_out = [];
jQuery.each(strings, function() {
var out = new String();
jQuery.each(self.tokenizeCss(this), function() {
if (!existing_tokens[this]) {
existing_tokens[this] = String.fromCharCode(codepoint++);
}
out += existing_tokens[this];
});
strings_out.push(out);
});
return strings_out;
};
DomPredictionHelper.prototype.simplifyCss = function(css, selected_paths, rejected_paths) {
var self = this;
var parts = self.tokenizeCss(css);
var best_so_far = "";
if (self.selectorGets('all', selected_paths, css) && self.selectorGets('none', rejected_paths, css)) best_so_far = css;
for (var pass = 0; pass < 4; pass++) {
for (var part = 0; part < parts.length; part++) {
var first = parts[part].substring(0,1);
if (self.wouldLeaveFreeFloatingNthChild(parts, part)) continue;
if ((pass == 0 && first == ':') || // :nth-child
(pass == 1 && first != ':' && first != '.' && first != '#' && first != ' ') || // elem, etc.
(pass == 2 && first == '.') || // classes
(pass == 3 && first == '#')) // ids
{
var tmp = parts[part];
parts[part] = '';
var selector = self.cleanCss(parts.join(''));
if (selector == '') {
parts[part] = tmp;
continue;
}
if (self.selectorGets('all', selected_paths, selector) && self.selectorGets('none', rejected_paths, selector)) {
best_so_far = selector;
} else {
parts[part] = tmp;
}
}
}
}
return self.cleanCss(best_so_far);
};
DomPredictionHelper.prototype.wouldLeaveFreeFloatingNthChild = function(parts, part) {
return (((part - 1 >= 0 && parts[part - 1].substring(0, 1) == ':') &&
(part - 2 < 0 || parts[part - 2] == ' ') &&
(part + 1 >= parts.length || parts[part + 1] == ' ')) ||
((part + 1 < parts.length && parts[part + 1].substring(0, 1) == ':') &&
(part + 2 >= parts.length || parts[part + 2] == ' ') &&
(part - 1 < 0 || parts[part - 1] == ' ')));
};
DomPredictionHelper.prototype.cleanCss = function(css) {
return css.replace(/\>/, ' > ').replace(/,/, ' , ').replace(/\s+/g, ' ').replace(/^\s+|\s+$/g, '').replace(/,$/, '');
};
DomPredictionHelper.prototype.getPathsFor = function(arr) {
var self = this;
var out = [];
jQuery.each(arr, function() {
if (this && this.nodeName) {
out.push(self.pathOf(this));
}
})
return out;
};
DomPredictionHelper.prototype.predictCss = function(s, r) {
var self = this;
if (s.length == 0) return '';
var selected_paths = self.getPathsFor(s);
var rejected_paths = self.getPathsFor(r);
var css = self.commonCss(selected_paths);
var simplest = self.simplifyCss(css, selected_paths, rejected_paths);
// Do we get off easy?
if (simplest.length > 0) return simplest;
// Okay, then make a union and possibly try to reduce subsets.
var union = '';
jQuery.each(s, function() {
union = self.pathOf(this) + ", " + union;
});
union = self.cleanCss(union);
return self.simplifyCss(union, selected_paths, rejected_paths);
};
DomPredictionHelper.prototype.fragmentSelector = function(selector) {
var self = this;
var out = [];
jQuery.each(selector.split(/\,/), function() {
var out2 = [];
jQuery.each(self.cleanCss(this).split(/\s+/), function() {
out2.push(self.tokenizeCss(this));
});
out.push(out2);
});
return out;
};
// Everything in the first selector must be present in the second.
DomPredictionHelper.prototype.selectorBlockMatchesSelectorBlock = function(selector_block1, selector_block2) {
for (var j = 0; j < selector_block1.length; j++) {
if (jQuery.inArray(selector_block1[j], selector_block2) == -1) {
return false;
}
}
return true;
};
// Assumes list is an array of complete CSS selectors represented as strings.
DomPredictionHelper.prototype.selectorGets = function(type, list, the_selector) {
var self = this;
var result = true;
if (list.length == 0 && type == 'all') return false;
if (list.length == 0 && type == 'none') return true;
var selectors = self.fragmentSelector(the_selector);
var cleaned_list = [];
jQuery.each(list, function() {
cleaned_list.push(self.fragmentSelector(this)[0]);
});
jQuery.each(selectors, function() {
if (!result) return;
var selector = this;
jQuery.each(cleaned_list, function(pos) {
if (!result || this == '') return;
if (self._selectorGets(this, selector)) {
if (type == 'none') result = false;
cleaned_list[pos] = '';
}
});
});
if (type == 'all' && cleaned_list.join('').length > 0) { // Some candidates didn't get matched.
result = false;
}
return result;
};
DomPredictionHelper.prototype._selectorGets = function(candidate_as_blocks, selector_as_blocks) {
var cannot_match = false;
var position = candidate_as_blocks.length - 1;
for (var i = selector_as_blocks.length - 1; i > -1; i--) {
if (cannot_match) break;
if (i == selector_as_blocks.length - 1) { // First element on right.
// If we don't match the first element, we cannot match.
if (!this.selectorBlockMatchesSelectorBlock(selector_as_blocks[i], candidate_as_blocks[position])) cannot_match = true;
position--;
} else {
var found = false;
while (position > -1 && !found) {
found = this.selectorBlockMatchesSelectorBlock(selector_as_blocks[i], candidate_as_blocks[position]);
position--;
}
if (!found) cannot_match = true;
}
}
return !cannot_match;
};
DomPredictionHelper.prototype.invertObject = function(object) {
var new_object = {};
jQuery.each(object, function(key, value) {
new_object[value] = key;
});
return new_object;
};
DomPredictionHelper.prototype.cssToXPath = function(css_string) {
var tokens = this.tokenizeCss(css_string);
if (tokens[0] && tokens[0] == ' ') tokens.splice(0, 1);
if (tokens[tokens.length - 1] && tokens[tokens.length - 1] == ' ') tokens.splice(tokens.length - 1, 1);
var css_block = [];
var out = "";
for(var i = 0; i < tokens.length; i++) {
if (tokens[i] == ' ') {
out += this.cssToXPathBlockHelper(css_block);
css_block = [];
} else {
css_block.push(tokens[i]);
}
}
return out + this.cssToXPathBlockHelper(css_block);
};
// Process a block (html entity, class(es), id, :nth-child()) of css
DomPredictionHelper.prototype.cssToXPathBlockHelper = function(css_block) {
if (css_block.length == 0) return '//';
var out = '//';
var first = css_block[0].substring(0,1);
if (first == ',') return " | ";
if (jQuery.inArray(first, [':', '#', '.']) != -1) {
out += '*';
}
var expressions = [];
var re = null;
for(var i = 0; i < css_block.length; i++) {
var current = css_block[i];
first = current.substring(0,1);
var rest = current.substring(1);
if (first == ':') {
// We only support :nth-child(n) at the moment.
if (re = rest.match(/^nth-child\((\d+)\)$/))
expressions.push('(((count(preceding-sibling::*) + 1) = ' + re[1] + ') and parent::*)');
} else if (first == '.') {
expressions.push('contains(concat( " ", #class, " " ), concat( " ", "' + rest + '", " " ))');
} else if (first == '#') {
expressions.push('(#id = "' + rest + '")');
} else if (first == ',') {
} else {
out += current;
}
}
if (expressions.length > 0) out += '[';
for (var i = 0; i < expressions.length; i++) {
out += expressions[i];
if (i < expressions.length - 1) out += ' and ';
}
if (expressions.length > 0) out += ']';
return out;
};
I wrote the following function to linearize the text content of an arbitrary string of HTML:
html2text(html) {
function _html2text(element, accum) {
return Array.prototype.slice.call(element.childNodes).reduce((accum, node) => {
return (node.nodeType === 3)
? `${accum} ${node.textContent}`
: _html2text(node, accum);
}, accum);
}
const div = document.createElement('div');
div.innerHTML = html;
return _html2text(div, '');
}
But now I am not able to transform it into a trail-recusive style so that it can be optimized.
My problem is that the recursion recurs within the reduction.
I will write this out as loops, but it's been killing me that I've not been able tail recurse this.
Here is my loop version:
function html2text(html) {
var div = document.createElement('div');
div.innerHTML = html;
var accum = '';
var stack = [];
stack.push([div, 0]);
while (stack.length !== 0) {
var frame = stack.pop();
var el = frame[0];
var i = frame[1];
for (; i < el.childNodes.length; i++) {
var node = el.childNodes[i];
if (node.nodeType === Node.ELEMENT_NODE) {
stack.push([el, i+1]);
stack.push([node, 0]);
break;
} else if (node.nodeType === Node.TEXT_NODE) {
accum += ' ' + node.textContent;
}
}
}
return accum;
}
Here's the function above written with a recursive tail call, passing the stack:
function html2text(html) {
function recurse(stack, accum) {
if (!stack.length) {
return accum;
}
var frame = stack.pop();
var el = frame[0];
var i = frame[1];
for (; i < el.childNodes.length; i++) {
var node = el.childNodes[i];
if (node.nodeType === Node.ELEMENT_NODE) {
stack.push([el, i+1]);
stack.push([node, 0]);
break;
} else if (node.nodeType === Node.TEXT_NODE) {
accum += ' ' + node.textContent;
}
}
return recurse(stack, accum)
}
var div = document.createElement('div');
div.innerHTML = html;
var stack = [];
stack.push([div, 0]);
return recurse(stack, '');
}
The inner loop can be converted to another recursion, but without using immutable datastructures none of this really makes too much sense for me.
function html2text(current, text = "") {
"use strict";
if (current === null) return text;
var nextNode = current.nextSibling || current.parentNode.nextSibling,
more = current.nodeType === 3 ? current.textContent : "";
return html2text(nextNode, text + more);
}
You were right, you can do the concatenation before the tail call. I think this fits all the criteria, but ES6 is new, so please do double check.
Here is a javascript file which turns xml file to text.This text is often equation.I want this equation to be in such a way that the result of xml passed to python produce required result.any help is appreciable.
function getDOM(xmlstring) {
parser=new DOMParser();
return parser.parseFromString(xmlstring, "text/xml");
}
function remove_tags(node) {
var result = "";
var nodes = node.childNodes;
var tagName = node.tagName;
if (!nodes.length) {
if (node.nodeValue == "π") result = "pi";
else if (node.nodeValue == " ") result = "";
else result = node.nodeValue;
} else if (tagName == "mfrac") {
result = "("+remove_tags(nodes[0])+")/("+remove_tags(nodes[1])+")";
} else if (tagName == "msup") {
result = "Math.pow(("+remove_tags(nodes[0])+"),("+remove_tags(nodes[1])+"))";
} else for (var i = 0; i < nodes.length; ++i) {
result += remove_tags(nodes[i]);
}
if (tagName == "mfenced") result = "("+result+")";
if (tagName == "msqrt") result = "Math.sqrt("+result+")";
return result;
}
function stringifyMathML(mml) {
xmlDoc = getDOM(mml);
return remove_tags(xmlDoc.documentElement);
}
Example of xml file is
s = stringifyMathML(" <math><mi>sin</mi><mfenced><mi>x</mi></mfenced></math>");
alert(s);
alert(eval(s));
I am expecting output to be
math.sin(x)
Adding the specific .math part will solve the issue:
The "math." part must be added only when special keyword are present.
So first, build the potential operation you will need to cover in a list (mList)
Then, if you meet this operation, prepend it with ".math"
var mList = ['pow', 'sin', 'cos', 'pow', 'sqrt', 'π'];
function getDOM(xmlstring) {
parser=new DOMParser();
return parser.parseFromString(xmlstring, "text/xml");
}
function remove_tags(node) {
var result = "";
var nodes = node.childNodes;
var tagName = node.tagName;
if (!nodes.length) {
if(mList.indexOf(node.nodeValue) != -1 ) {
result += 'math.'
}
if (node.nodeValue == "π") result += "pi";
else if (node.nodeValue == " ") result += "";
else result += node.nodeValue;
} else if (tagName == "mfrac") {
result += "("+remove_tags(nodes[0])+")/("+remove_tags(nodes[1])+")";
} else if (tagName == "msup") {
result += "pow(("+remove_tags(nodes[0])+"),("+remove_tags(nodes[1])+"))";
} else for (var i = 0; i < nodes.length; ++i) {
result += remove_tags(nodes[i]);
}
if (tagName == "mfenced") result = "("+result+")";
if (tagName == "msqrt") result = "sqrt("+result+")";
console.log('returning', result)
return result;
}
function stringifyMathML(mml) {
xmlDoc = getDOM(mml);
return remove_tags(xmlDoc.documentElement);
}
a = stringifyMathML("<math><mi>x</mi></math>");
b = stringifyMathML("<math><mi>x</mi><mo>+</mo><mn>5</mn></math> ");
c = stringifyMathML("<math><mi>sin</mi><mfenced><mi>x</mi></mfenced></math> ");
console.log(a, 'vs x');
console.log(b, 'vs x+5');
console.log(c, 'vs math.sin(x)');
Output
x vs x
x+5 vs x+5
math.sin(x) vs math.sin(x)
DOM4 compareDocumentPosition
I want to implement compareDocumentPosition. Resig has made a great start at doing just this. I've taken his code and neatened it up
function compareDocumentPosition(other) {
var ret = 0;
if (this.contains) {
if (this !== other && this.contains(other)) {
ret += 16;
}
if (this !== other && other.contains(this)) {
ret += 8;
}
if (this.sourceIndex >= 0 && other.sourceIndex >= 0) {
if (this.sourceIndex < other.sourceIndex) {
ret += 4;
}
if (this.sourceIndex > other.sourceIndex) {
ret += 2;
}
} else {
ret += 1;
}
}
return ret;
}
This works for Element but does not for Text or DocumentFragment. This is because IE8 does not give .sourceIndex on those nodes. (It doesn't give .contains either but I've fixed that problem already)
How do I efficiently write the +=4 and +=2 bit which correspond to DOCUMENT_POSITION_FOLLOWING and DOCUMENT_POSITION_PRECEDING.
For extra reference those two are defined by tree-order which DOM4 defines as
An object A is preceding an object B if A and B are in the same tree and A comes before B in tree order.
An object A is following an object B if A and B are in the same tree and A comes after B in tree order.
The tree order is preorder, depth-first traversal.
Most modern browsers implement this (including IE9). So you only need something that works in IE8 (I don't care about IE6/7, but if it works awesome!)
function recursivelyWalk(nodes, cb) {
for (var i = 0, len = nodes.length; i < len; i++) {
var node = nodes[i];
var ret = cb(node);
if (ret) {
return ret;
}
if (node.childNodes && node.childNodes.length) {
var ret = recursivelyWalk(node.childNodes, cb);
if (ret) {
return ret;
}
}
}
}
function testNodeForComparePosition(node, other) {
if (node === other) {
return true;
}
}
function compareDocumentPosition(other) {
function identifyWhichIsFirst(node) {
if (node === other) {
return "other";
} else if (node === reference) {
return "reference";
}
}
var reference = this,
referenceTop = this,
otherTop = other;
if (this === other) {
return 0;
}
while (referenceTop.parentNode) {
referenceTop = referenceTop.parentNode;
}
while (otherTop.parentNode) {
otherTop = otherTop.parentNode;
}
if (referenceTop !== otherTop) {
return Node.DOCUMENT_POSITION_DISCONNECTED;
}
var children = reference.childNodes;
var ret = recursivelyWalk(
children,
testNodeForComparePosition.bind(null, other)
);
if (ret) {
return Node.DOCUMENT_POSITION_CONTAINED_BY +
Node.DOCUMENT_POSITION_FOLLOWING;
}
var children = other.childNodes;
var ret = recursivelyWalk(
children,
testNodeForComparePosition.bind(null, reference)
);
if (ret) {
return Node.DOCUMENT_POSITION_CONTAINS +
Node.DOCUMENT_POSITION_PRECEDING;
}
var ret = recursivelyWalk(
[referenceTop],
identifyWhichIsFirst
);
if (ret === "other") {
return Node.DOCUMENT_POSITION_PRECEDING;
} else {
return Node.DOCUMENT_POSITION_FOLLOWING;
}
}
I wrote it myself. I thought this implementation was bugged but it was a bug in some other code of mine. Seems pretty solid.
The answer from Raynos is a top start, but is not runnable out of the box. Node.* cannot be found and .bind is not available in IE8.
Here is the code ready for use in Internet Explorer 8:
function recursivelyWalk(nodes, cb) {
for (var i = 0, len = nodes.length; i < len; i++) {
var node = nodes[i];
var ret = cb(node);
if (ret) {
return ret;
}
if (node.childNodes && node.childNodes.length) {
var ret = recursivelyWalk(node.childNodes, cb);
if (ret) {
return ret;
}
}
}
}
function testNodeForComparePosition(node, other) {
if (node === other) {
return true;
}
}
var DOCUMENT_POSITION_DISCONNECTED = 1;
var DOCUMENT_POSITION_PRECEDING = 2;
var DOCUMENT_POSITION_FOLLOWING = 4;
var DOCUMENT_POSITION_CONTAINS = 8;
var DOCUMENT_POSITION_CONTAINED_BY = 16;
function compareDocumentPosition(thisNode, other) {
function identifyWhichIsFirst(node) {
if (node === other) {
return "other";
} else if (node === reference) {
return "reference";
}
}
var reference = thisNode,
referenceTop = thisNode,
otherTop = other;
if (this === other) {
return 0;
}
while (referenceTop.parentNode) {
referenceTop = referenceTop.parentNode;
}
while (otherTop.parentNode) {
otherTop = otherTop.parentNode;
}
if (referenceTop !== otherTop) {
return DOCUMENT_POSITION_DISCONNECTED;
}
var children = reference.childNodes;
var ret = recursivelyWalk(
children,
function(p) {
(function() {
var localOther = other;
return testNodeForComparePosition(localOther, p);
})();
}
);
if (ret) {
return DOCUMENT_POSITION_CONTAINED_BY +
DOCUMENT_POSITION_FOLLOWING;
}
var children = other.childNodes;
var ret = recursivelyWalk(
children,
function(p) {
(function() {
var localOther = reference;
return testNodeForComparePosition(localOther, p);
})();
}
);
if (ret) {
return DOCUMENT_POSITION_CONTAINS +
DOCUMENT_POSITION_PRECEDING;
}
var ret = recursivelyWalk(
[referenceTop],
identifyWhichIsFirst
);
if (ret === "other") {
return DOCUMENT_POSITION_PRECEDING;
} else {
return DOCUMENT_POSITION_FOLLOWING;
}
}
You call it like this:
compareDocumentPosition(sourceElement, elementToTest)
(It's like calling sourceElement.compareDocumentPosition(elementToTest))
I can get a style of an element just doing this:
alert (document.defaultView.getComputedStyle (document.getElementById ("element"), null).getPropertyValue ("background-color"));
I can get all styles of an element just doing this:
var styles = document.defaultView.getComputedStyle (document.getElementById ("element"), null);
var string = ""
for (var i = 0; i < styles.length; i ++) {
string = string + styles[i] + ": " + styles.getPropertyValue (styles[i]) + "\n";
}
alert (string);
But, how can I get only the specified styles of an element?
What do you mean by 'specified styles'? Do you mean:
var el = document.getElementById("element");
alert(el.style.display);
alert(el.style.background);
...etc...
or do you mean something like this:
function in_array (needle, haystack, argStrict) {
var key = '', strict = !!argStrict;
if (strict) {
for (key in haystack) {
if (haystack[key] === needle) {
return true;
}
}
} else {
for (key in haystack) {
if (haystack[key] == needle) {
return true;
}
}
}
return false;
}
var styles = document.defaultView.getComputedStyle (document.getElementById ("element"), null);
var string = "";
var whichStyles = ['display','background-color'];
for (var i = 0; i < styles.length; i ++) {
if(in_array(styles[i], whichStyles) {
string = string + styles[i] + ": " + styles.getPropertyValue (styles[i]) + "\n";
}
}
alert (string);