| 1 | 'use strict'
|
|---|
| 2 |
|
|---|
| 3 | module.exports = adapterFactory;
|
|---|
| 4 |
|
|---|
| 5 | function adapterFactory(implementation){
|
|---|
| 6 | ensureImplementation(implementation);
|
|---|
| 7 |
|
|---|
| 8 | var adapter = {}
|
|---|
| 9 |
|
|---|
| 10 | var baseAdapter = {
|
|---|
| 11 | removeSubsets: function (nodes){
|
|---|
| 12 | return removeSubsets(adapter, nodes);
|
|---|
| 13 | },
|
|---|
| 14 | existsOne: function(test, elems){
|
|---|
| 15 | return existsOne(adapter, test, elems);
|
|---|
| 16 | },
|
|---|
| 17 | getSiblings: function(elem){
|
|---|
| 18 | return getSiblings(adapter, elem);
|
|---|
| 19 | },
|
|---|
| 20 | hasAttrib: function(elem, name){
|
|---|
| 21 | return hasAttrib(adapter, elem, name);
|
|---|
| 22 | },
|
|---|
| 23 | findOne: function(test, arr){
|
|---|
| 24 | return findOne(adapter, test, arr);
|
|---|
| 25 | },
|
|---|
| 26 | findAll: function(test, elems){
|
|---|
| 27 | return findAll(adapter, test, elems)
|
|---|
| 28 | }
|
|---|
| 29 | };
|
|---|
| 30 |
|
|---|
| 31 | Object.assign(adapter, baseAdapter, implementation);
|
|---|
| 32 |
|
|---|
| 33 | return adapter;
|
|---|
| 34 | }
|
|---|
| 35 |
|
|---|
| 36 | var expectImplemented = [
|
|---|
| 37 | "isTag", "getAttributeValue", "getChildren", "getName", "getParent",
|
|---|
| 38 | "getText"
|
|---|
| 39 | ];
|
|---|
| 40 |
|
|---|
| 41 | function ensureImplementation(implementation){
|
|---|
| 42 | if(!implementation) throw new TypeError("Expected implementation")
|
|---|
| 43 |
|
|---|
| 44 | var notImplemented = expectImplemented.filter(function(fname){
|
|---|
| 45 | return typeof implementation[fname] !== "function";
|
|---|
| 46 | });
|
|---|
| 47 |
|
|---|
| 48 | if(notImplemented.length){
|
|---|
| 49 | var notList = "(" + notImplemented.join(", ") + ")";
|
|---|
| 50 | var message = "Expected functions " + notList + " to be implemented";
|
|---|
| 51 | throw new Error(message);
|
|---|
| 52 | }
|
|---|
| 53 | }
|
|---|
| 54 |
|
|---|
| 55 | function removeSubsets(adapter, nodes){
|
|---|
| 56 | var idx = nodes.length, node, ancestor, replace;
|
|---|
| 57 |
|
|---|
| 58 | // Check if each node (or one of its ancestors) is already contained in the
|
|---|
| 59 | // array.
|
|---|
| 60 | while(--idx > -1){
|
|---|
| 61 | node = ancestor = nodes[idx];
|
|---|
| 62 |
|
|---|
| 63 | // Temporarily remove the node under consideration
|
|---|
| 64 | nodes[idx] = null;
|
|---|
| 65 | replace = true;
|
|---|
| 66 |
|
|---|
| 67 | while(ancestor){
|
|---|
| 68 | if(nodes.indexOf(ancestor) > -1){
|
|---|
| 69 | replace = false;
|
|---|
| 70 | nodes.splice(idx, 1);
|
|---|
| 71 | break;
|
|---|
| 72 | }
|
|---|
| 73 | ancestor = adapter.getParent(ancestor)
|
|---|
| 74 | }
|
|---|
| 75 |
|
|---|
| 76 | // If the node has been found to be unique, re-insert it.
|
|---|
| 77 | if(replace){
|
|---|
| 78 | nodes[idx] = node;
|
|---|
| 79 | }
|
|---|
| 80 | }
|
|---|
| 81 |
|
|---|
| 82 | return nodes;
|
|---|
| 83 | }
|
|---|
| 84 |
|
|---|
| 85 | function existsOne(adapter, test, elems){
|
|---|
| 86 | return elems.some(function(elem){
|
|---|
| 87 | return adapter.isTag(elem) ?
|
|---|
| 88 | test(elem) || adapter.existsOne(test, adapter.getChildren(elem)) :
|
|---|
| 89 | false;
|
|---|
| 90 | });
|
|---|
| 91 | }
|
|---|
| 92 |
|
|---|
| 93 | function getSiblings(adapter, elem){
|
|---|
| 94 | var parent = adapter.getParent(elem);
|
|---|
| 95 | return parent && adapter.getChildren(parent);
|
|---|
| 96 | }
|
|---|
| 97 |
|
|---|
| 98 |
|
|---|
| 99 | function hasAttrib(adapter, elem, name){
|
|---|
| 100 | return adapter.getAttributeValue(elem,name) !== undefined
|
|---|
| 101 | }
|
|---|
| 102 |
|
|---|
| 103 | function findOne(adapter, test, arr){
|
|---|
| 104 | var elem = null;
|
|---|
| 105 |
|
|---|
| 106 | for(var i = 0, l = arr.length; i < l && !elem; i++){
|
|---|
| 107 | if(test(arr[i])){
|
|---|
| 108 | elem = arr[i];
|
|---|
| 109 | } else {
|
|---|
| 110 | var childs = adapter.getChildren(arr[i]);
|
|---|
| 111 | if(childs && childs.length > 0){
|
|---|
| 112 | elem = adapter.findOne(test, childs);
|
|---|
| 113 | }
|
|---|
| 114 | }
|
|---|
| 115 | }
|
|---|
| 116 |
|
|---|
| 117 | return elem;
|
|---|
| 118 | }
|
|---|
| 119 |
|
|---|
| 120 | function findAll(adapter, test, elems){
|
|---|
| 121 | var result = [];
|
|---|
| 122 |
|
|---|
| 123 | for(var i = 0, j = elems.length; i < j; i++){
|
|---|
| 124 | if(!adapter.isTag(elems[i])) continue;
|
|---|
| 125 | if(test(elems[i])) result.push(elems[i]);
|
|---|
| 126 | var childs = adapter.getChildren(elems[i]);
|
|---|
| 127 | if(childs) result = result.concat(adapter.findAll(test, childs));
|
|---|
| 128 | }
|
|---|
| 129 |
|
|---|
| 130 | return result;
|
|---|
| 131 | }
|
|---|