OLD | NEW |
(Empty) | |
| 1 |
| 2 |
| 3 (function(scope) { |
| 4 |
| 5 scope = scope || (window.Inspector = {}); |
| 6 |
| 7 var inspector; |
| 8 |
| 9 window.sinspect = function(inNode, inProxy) { |
| 10 if (!inspector) { |
| 11 inspector = window.open('', 'ShadowDOM Inspector', null, true); |
| 12 inspector.document.write(inspectorHTML); |
| 13 //inspector.document.close(); |
| 14 inspector.api = { |
| 15 shadowize: shadowize |
| 16 }; |
| 17 } |
| 18 inspect(inNode || wrap(document.body), inProxy); |
| 19 }; |
| 20 |
| 21 var inspectorHTML = [ |
| 22 '<!DOCTYPE html>', |
| 23 '<html>', |
| 24 ' <head>', |
| 25 ' <title>ShadowDOM Inspector</title>', |
| 26 ' <style>', |
| 27 ' body {', |
| 28 ' }', |
| 29 ' pre {', |
| 30 ' font: 9pt "Courier New", monospace;', |
| 31 ' line-height: 1.5em;', |
| 32 ' }', |
| 33 ' tag {', |
| 34 ' color: purple;', |
| 35 ' }', |
| 36 ' ul {', |
| 37 ' margin: 0;', |
| 38 ' padding: 0;', |
| 39 ' list-style: none;', |
| 40 ' }', |
| 41 ' li {', |
| 42 ' display: inline-block;', |
| 43 ' background-color: #f1f1f1;', |
| 44 ' padding: 4px 6px;', |
| 45 ' border-radius: 4px;', |
| 46 ' margin-right: 4px;', |
| 47 ' }', |
| 48 ' button {', |
| 49 ' display: inline-block;', |
| 50 ' color: purple;', |
| 51 ' font-weight: bold;', |
| 52 ' background: none;', |
| 53 ' border: none;', |
| 54 ' outline: none;', |
| 55 ' padding: 0;', |
| 56 ' margin: 0;', |
| 57 ' }', |
| 58 ' </style>', |
| 59 ' </head>', |
| 60 ' <body>', |
| 61 ' <ul id="crumbs">', |
| 62 ' </ul>', |
| 63 ' <div id="tree"></div>', |
| 64 ' </body>', |
| 65 '</html>' |
| 66 ].join('\n'); |
| 67 |
| 68 var crumbs = []; |
| 69 |
| 70 var displayCrumbs = function() { |
| 71 // alias our document |
| 72 var d = inspector.document; |
| 73 // get crumbbar |
| 74 var cb = d.querySelector('#crumbs'); |
| 75 // clear crumbs |
| 76 cb.textContent = ''; |
| 77 // build new crumbs |
| 78 for (var i=0, c; c=crumbs[i]; i++) { |
| 79 var a = d.createElement('a'); |
| 80 a.href = '#'; |
| 81 a.textContent = c.localName; |
| 82 a.idx = i; |
| 83 a.onclick = function(event) { |
| 84 var c; |
| 85 while (crumbs.length > this.idx) { |
| 86 c = crumbs.pop(); |
| 87 } |
| 88 inspect(c.shadow || c, c); |
| 89 event.preventDefault(); |
| 90 }; |
| 91 cb.appendChild(d.createElement('li')).appendChild(a); |
| 92 } |
| 93 }; |
| 94 |
| 95 var inspect = function(inNode, inProxy) { |
| 96 // alias our document |
| 97 var d = inspector.document; |
| 98 // reset list of drillable nodes |
| 99 drillable = []; |
| 100 // memoize our crumb proxy |
| 101 var proxy = inProxy || inNode; |
| 102 crumbs.push(proxy); |
| 103 // update crumbs |
| 104 displayCrumbs(); |
| 105 // reflect local tree |
| 106 d.body.querySelector('#tree').innerHTML = |
| 107 '<pre>' + output(inNode, getLocalNodes(inNode)) + '</pre>'; |
| 108 }; |
| 109 |
| 110 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); |
| 111 |
| 112 var blacklisted = {STYLE:1, SCRIPT:1, "#comment": 1, TEMPLATE: 1}; |
| 113 var blacklist = function(inNode) { |
| 114 return blacklisted[inNode.nodeName]; |
| 115 }; |
| 116 |
| 117 var output = function(inNode, inChildNodes, inIndent) { |
| 118 if (blacklist(inNode)) { |
| 119 return ''; |
| 120 } |
| 121 var indent = inIndent || ''; |
| 122 if (inNode.localName || inNode.domRoot) { |
| 123 var name = inNode.localName || ROOT_NAME; |
| 124 //inChildNodes = ShadowDOM.localNodes(inNode); |
| 125 var info = indent + describe(inNode); |
| 126 // if only textNodes |
| 127 // TODO(sjmiles): make correct for ShadowDOM |
| 128 /*if (!inNode.children.length && inNode.localName !== 'content' && inNode.
localName !== 'shadow') { |
| 129 info += catTextContent(inChildNodes); |
| 130 } else*/ { |
| 131 // TODO(sjmiles): native <shadow> has no reference to its projection |
| 132 if (name == 'content' /*|| name == 'shadow'*/) { |
| 133 inChildNodes = getDistributedNodes(inNode); |
| 134 } |
| 135 info += '<br/>'; |
| 136 var ind = indent + ' '; |
| 137 //console.group('output ' + inNode.localName); |
| 138 //console.log(inChildNodes); |
| 139 forEach(inChildNodes, function(n) { |
| 140 info += output(n, getLightNodes(n), ind); |
| 141 }); |
| 142 //console.groupEnd('output ' + inNode.localName); |
| 143 info += indent; |
| 144 } |
| 145 if (!({br:1}[name])) { |
| 146 info += '<tag></' + name + '></tag>'; |
| 147 info += '<br/>'; |
| 148 } |
| 149 } else { |
| 150 var text = inNode.textContent.trim(); |
| 151 info = text ? indent + '"' + text + '"' + '<br/>' : ''; |
| 152 } |
| 153 return info; |
| 154 }; |
| 155 |
| 156 var catTextContent = function(inChildNodes) { |
| 157 var info = ''; |
| 158 forEach(inChildNodes, function(n) { |
| 159 info += n.textContent.trim(); |
| 160 }); |
| 161 return info; |
| 162 }; |
| 163 |
| 164 var drillable = []; |
| 165 |
| 166 var describe = function(inNode) { |
| 167 var tag = '<tag>' + '<'; |
| 168 var name = inNode.localName || ROOT_NAME; |
| 169 if (hasRoot(inNode)) { |
| 170 tag += '<button idx="' + drillable.length + |
| 171 '" onclick="api.shadowize.call(this)">' + name + '</button>'; |
| 172 drillable.push(inNode); |
| 173 } else { |
| 174 tag += name || ROOT_NAME; |
| 175 } |
| 176 if (inNode.attributes) { |
| 177 forEach(inNode.attributes, function(a) { |
| 178 tag += ' ' + a.name + (a.value ? '="' + a.value + '"' : ''); |
| 179 }); |
| 180 } |
| 181 tag += '>'+ '</tag>'; |
| 182 return tag; |
| 183 }; |
| 184 |
| 185 // remote api |
| 186 |
| 187 shadowize = function() { |
| 188 var idx = Number(this.attributes.idx.value); |
| 189 //alert(idx); |
| 190 var node = drillable[idx]; |
| 191 if (node) { |
| 192 inspect(node, node) |
| 193 } else { |
| 194 console.log("bad shadowize node"); |
| 195 console.dir(this); |
| 196 } |
| 197 }; |
| 198 |
| 199 // util |
| 200 |
| 201 var ROOT_NAME = 'local-root'; |
| 202 |
| 203 function hasRoot(node) { |
| 204 return (node.shadyRoot || node.shadowRoot); |
| 205 } |
| 206 |
| 207 function getLocalNodes(n) { |
| 208 return Polymer.dom.childNodes(n.root); |
| 209 } |
| 210 |
| 211 function getLightNodes(n) { |
| 212 return Polymer.dom.childNodes(n); |
| 213 } |
| 214 |
| 215 function getDistributedNodes(node) { |
| 216 Polymer.dom.distributedNodes(node); |
| 217 } |
| 218 |
| 219 |
| 220 // export |
| 221 |
| 222 scope.output = output; |
| 223 |
| 224 })(window.Inspector); |
| 225 |
OLD | NEW |