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 |