You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
2.9 KiB
131 lines
2.9 KiB
'use strict' |
|
|
|
module.exports = adapterFactory; |
|
|
|
function adapterFactory(implementation){ |
|
ensureImplementation(implementation); |
|
|
|
var adapter = {} |
|
|
|
var baseAdapter = { |
|
removeSubsets: function (nodes){ |
|
return removeSubsets(adapter, nodes); |
|
}, |
|
existsOne: function(test, elems){ |
|
return existsOne(adapter, test, elems); |
|
}, |
|
getSiblings: function(elem){ |
|
return getSiblings(adapter, elem); |
|
}, |
|
hasAttrib: function(elem, name){ |
|
return hasAttrib(adapter, elem, name); |
|
}, |
|
findOne: function(test, arr){ |
|
return findOne(adapter, test, arr); |
|
}, |
|
findAll: function(test, elems){ |
|
return findAll(adapter, test, elems) |
|
} |
|
}; |
|
|
|
Object.assign(adapter, baseAdapter, implementation); |
|
|
|
return adapter; |
|
} |
|
|
|
var expectImplemented = [ |
|
"isTag", "getAttributeValue", "getChildren", "getName", "getParent", |
|
"getText" |
|
]; |
|
|
|
function ensureImplementation(implementation){ |
|
if(!implementation) throw new TypeError("Expected implementation") |
|
|
|
var notImplemented = expectImplemented.filter(function(fname){ |
|
return typeof implementation[fname] !== "function"; |
|
}); |
|
|
|
if(notImplemented.length){ |
|
var notList = "(" + notImplemented.join(", ") + ")"; |
|
var message = "Expected functions " + notList + " to be implemented"; |
|
throw new Error(message); |
|
} |
|
} |
|
|
|
function removeSubsets(adapter, nodes){ |
|
var idx = nodes.length, node, ancestor, replace; |
|
|
|
// Check if each node (or one of its ancestors) is already contained in the |
|
// array. |
|
while(--idx > -1){ |
|
node = ancestor = nodes[idx]; |
|
|
|
// Temporarily remove the node under consideration |
|
nodes[idx] = null; |
|
replace = true; |
|
|
|
while(ancestor){ |
|
if(nodes.indexOf(ancestor) > -1){ |
|
replace = false; |
|
nodes.splice(idx, 1); |
|
break; |
|
} |
|
ancestor = adapter.getParent(ancestor) |
|
} |
|
|
|
// If the node has been found to be unique, re-insert it. |
|
if(replace){ |
|
nodes[idx] = node; |
|
} |
|
} |
|
|
|
return nodes; |
|
} |
|
|
|
function existsOne(adapter, test, elems){ |
|
return elems.some(function(elem){ |
|
return adapter.isTag(elem) ? |
|
test(elem) || adapter.existsOne(test, adapter.getChildren(elem)) : |
|
false; |
|
}); |
|
} |
|
|
|
function getSiblings(adapter, elem){ |
|
var parent = adapter.getParent(elem); |
|
return parent && adapter.getChildren(parent); |
|
} |
|
|
|
|
|
function hasAttrib(adapter, elem, name){ |
|
return adapter.getAttributeValue(elem,name) !== undefined |
|
} |
|
|
|
function findOne(adapter, test, arr){ |
|
var elem = null; |
|
|
|
for(var i = 0, l = arr.length; i < l && !elem; i++){ |
|
if(test(arr[i])){ |
|
elem = arr[i]; |
|
} else { |
|
var childs = adapter.getChildren(arr[i]); |
|
if(childs && childs.length > 0){ |
|
elem = adapter.findOne(test, childs); |
|
} |
|
} |
|
} |
|
|
|
return elem; |
|
} |
|
|
|
function findAll(adapter, test, elems){ |
|
var result = []; |
|
|
|
for(var i = 0, j = elems.length; i < j; i++){ |
|
if(!adapter.isTag(elems[i])) continue; |
|
if(test(elems[i])) result.push(elems[i]); |
|
var childs = adapter.getChildren(elems[i]); |
|
if(childs) result = result.concat(adapter.findAll(test, childs)); |
|
} |
|
|
|
return result; |
|
}
|
|
|