You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cryptpad/www/common/hyperjson.js

138 lines
3.9 KiB
JavaScript

define([], function () {
// this makes recursing a lot simpler
var isArray = function (A) {
return Object.prototype.toString.call(A)==='[object Array]';
};
var parseStyle = function(el){
var style = el.style;
var output = {};
for (var i = 0; i < style.length; ++i) {
var item = style.item(i);
output[item] = style[item];
}
return output;
};
var callOnHyperJSON = function (hj, cb) {
var children;
if (hj && hj[2]) {
children = hj[2].map(function (child) {
if (isArray(child)) {
// if the child is an array, recurse
return callOnHyperJSON(child, cb);
} else if (typeof (child) === 'string') {
// string nodes have leading and trailing quotes
return child.replace(/(^"|"$)/g,"");
} else {
// the above branches should cover all methods
// if we hit this, there is a problem
throw new Error();
}
});
} else {
children = [];
}
// this should return the top level element of your new DOM
return cb(hj[0], hj[1], children);
};
var prependDot = function (token) {
return '.' + token;
};
var isTruthy = function (x) {
return x;
};
/* DOM2HyperJSON accepts a DOM element/node
and converts it into Hyperjson. It optionally accepts a predicate
which is used for filtering out subtrees of the DOM from the result.
The function, if provided, must return true for elements which
should be preserved, and 'false' for elements which should be removed.
*/
var DOM2HyperJSON = function(el, predicate, filter){
if(!el.tagName && el.nodeType === Node.TEXT_NODE){
return el.textContent;
}
if(!el.attributes){
return;
}
if (predicate) {
if (!predicate(el)) {
// shortcircuit
return;
}
}
var attributes = {};
var i = 0;
for(;i < el.attributes.length; i++){
var attr = el.attributes[i];
if(attr.name && attr.value){
if(attr.name === "style"){
attributes.style = parseStyle(el);
}
else{
attributes[attr.name] = attr.value;
}
}
}
// this should never be longer than three elements
var result = [];
// get the element type, id, and classes of the element
// and push them to the result array
var sel = el.tagName;
if(attributes.id){
sel = sel +'#'+ attributes.id;
delete attributes.id;
}
if(attributes.class){
/* TODO this can be done with RegExps alone, and it will be faster
but this works and is a little less error prone, albeit slower
come back and speed it up when it comes time to optimize */
sel = sel + attributes.class
.split(/\s+/)
.filter(isTruthy)
.map(prependDot)
.join('');
delete attributes.class;
}
result.push(sel);
// second element of the array is the element attributes
result.push(attributes);
// third element of the array is an array of child nodes
var children = [];
// js hint complains if we use 'var' here
i = 0;
for(; i < el.childNodes.length; i++){
children.push(DOM2HyperJSON(el.childNodes[i], predicate, filter));
}
result.push(children.filter(isTruthy));
if (filter) {
return filter(result);
} else {
return result;
}
};
return {
fromDOM: DOM2HyperJSON,
callOn: callOnHyperJSON
};
});