| '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; |
| } |