| Left: | ||
| Right: |
| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * This Source Code is subject to the terms of the Mozilla Public License | 2 * This Source Code is subject to the terms of the Mozilla Public License |
| 3 * version 2.0 (the "License"). You can obtain a copy of the License at | 3 * version 2.0 (the "License"). You can obtain a copy of the License at |
| 4 * http://mozilla.org/MPL/2.0/. | 4 * http://mozilla.org/MPL/2.0/. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 const Ci = Components.interfaces; | 7 "use strict"; |
| 8 const Cu = Components.utils; | |
| 9 | 8 |
| 10 let console; | 9 let console; |
|
saroyanm
2016/11/22 14:58:31
Why do we load console ? Are we outputing/planing
Wladimir Palant
2016/11/24 14:16:29
We are not, this is a debugging helper. In fact, I
saroyanm
2016/11/24 17:46:10
Acknowledged.
| |
| 11 try | 10 try |
| 12 { | 11 { |
| 13 // Gecko 44+ | 12 // Gecko 44+ |
| 14 ({console} = Cu.import("resource://gre/modules/Console.jsm", {})); | 13 ({console} = Cu.import("resource://gre/modules/Console.jsm", {})); |
| 15 } | 14 } |
| 16 catch (e) | 15 catch (e) |
| 17 { | 16 { |
| 18 ({console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {})); | 17 ({console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {})); |
| 19 } | 18 } |
| 20 | 19 |
| 21 let DebuggerServer; | 20 let DebuggerServer; |
| 22 try | 21 try |
| 23 { | 22 { |
| 24 // Firefox 44+ | 23 // Firefox 44+ |
| 25 let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); | 24 let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); |
| 26 ({DebuggerServer} = require("devtools/server/main")); | 25 ({DebuggerServer} = require("devtools/server/main")); |
| 27 } | 26 } |
| 28 catch (e) | 27 catch (e) |
| 29 { | 28 { |
| 30 ({DebuggerServer} = Cu.import("resource://gre/modules/devtools/dbg-server.jsm" , {})); | 29 ({DebuggerServer} = Cu.import("resource://gre/modules/devtools/dbg-server.jsm" , {})); |
| 31 } | 30 } |
| 32 | 31 |
| 33 let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); | 32 let {getNodeInfo} = require("./nodeInfo"); |
| 34 | |
| 35 let processID = Services.appinfo.processID; | |
| 36 let maxNodeID = 0; | |
| 37 let nodes = new Map(); | |
|
Wladimir Palant
2016/11/17 08:42:58
I copied the same file (chrome/content/processScri
| |
| 38 | 33 |
| 39 let name = "elemhidehelper"; | 34 let name = "elemhidehelper"; |
| 40 let actor = { | 35 let actor = { |
| 41 constructorFun: Actor, | 36 constructorFun: Actor, |
| 42 constructorName: name, | 37 constructorName: name, |
| 43 name: name | 38 name: name |
| 44 }; | 39 }; |
| 45 | 40 |
| 46 addMessageListener("ElemHideHelper:Shutdown", onShutdown); | |
| 47 addMessageListener("ElemHideHelper:GetNodeInfo", onGetNodeInfo); | |
| 48 addMessageListener("ElemHideHelper:Preview", onTogglePreview); | |
| 49 | |
| 50 DebuggerServer.addTabActor(actor, name); | 41 DebuggerServer.addTabActor(actor, name); |
| 51 | 42 onShutdown.add(() => |
| 52 function onShutdown() | |
| 53 { | 43 { |
| 54 removeMessageListener("ElemHideHelper:Shutdown", onShutdown); | |
| 55 removeMessageListener("ElemHideHelper:GetNodeInfo", onGetNodeInfo); | |
| 56 removeMessageListener("ElemHideHelper:Preview", onTogglePreview); | |
| 57 | |
| 58 try | 44 try |
| 59 { | 45 { |
| 60 DebuggerServer.removeTabActor(actor); | 46 DebuggerServer.removeTabActor(actor); |
| 61 } | 47 } |
| 62 catch (e) | 48 catch (e) |
| 63 { | 49 { |
| 64 // The call above will throw in the content process despite succeeding, | 50 // The call above will throw in the content process despite succeeding, |
| 65 // see https://bugzilla.mozilla.org/show_bug.cgi?id=1189780. | 51 // see https://bugzilla.mozilla.org/show_bug.cgi?id=1189780. |
| 66 Cu.reportError(e); | 52 Cu.reportError(e); |
| 67 } | 53 } |
| 68 } | 54 }); |
| 69 | |
| 70 function onGetNodeInfo(message) | |
| 71 { | |
| 72 if (Cu.isCrossProcessWrapper(message.objects.element)) | |
| 73 return; | |
| 74 | |
| 75 let nodeInfo = getNodeInfo(message.objects.element); | |
| 76 nodeInfo.messageId = message.data; | |
| 77 sendAsyncMessage("ElemHideHelper:GetNodeInfo:Response", nodeInfo); | |
| 78 } | |
| 79 | |
| 80 function onTogglePreview(message) | |
| 81 { | |
| 82 togglePreview(message.data.nodeID, message.data.stylesheetData); | |
| 83 if (message.data.forgetNode) | |
| 84 forgetNode(message.data.nodeID); | |
| 85 } | |
| 86 | 55 |
| 87 function Actor(connection, tabActor) | 56 function Actor(connection, tabActor) |
|
saroyanm
2016/11/22 14:58:31
Detail: Why do we need this empty constructor ?
At
saroyanm
2016/11/22 14:58:31
Detail: Maybe it's personal preference, but what a
Wladimir Palant
2016/11/24 14:16:29
Well, DebuggerServer.addTabActor() requires a cons
saroyanm
2016/11/24 17:46:10
Acknowledged.
| |
| 88 { | 57 { |
| 89 } | 58 } |
| 90 | 59 |
| 91 Actor.prototype = { | 60 Actor.prototype = { |
| 92 requestTypes: { | 61 requestTypes: { |
| 93 nodeinfo: function(request, connection) | 62 nodeinfo: function(request, connection) |
| 94 { | 63 { |
| 95 let nodeActor = connection.getActor(request.nodeActor); | 64 let nodeActor = connection.getActor(request.nodeActor); |
| 96 return getNodeInfo(nodeActor ? nodeActor.rawNode: null); | 65 return getNodeInfo(nodeActor ? nodeActor.rawNode: null); |
|
saroyanm
2016/11/22 14:58:31
Detail: missing space after first expression.
Wladimir Palant
2016/11/24 14:16:29
Done.
| |
| 97 } | 66 } |
| 98 } | 67 } |
| 99 }; | 68 }; |
| 100 | |
| 101 function getNodeInfo(node) | |
| 102 { | |
| 103 let nodeData = getNodeData(node); | |
| 104 if (nodeData) | |
| 105 { | |
| 106 let nodeID = processID + "-" + (++maxNodeID); | |
| 107 nodes.set(nodeID, {document: node.ownerDocument, style: null}); | |
| 108 return { | |
| 109 host: node.ownerDocument.defaultView.location.hostname, | |
| 110 nodeData: nodeData, | |
| 111 nodeID: nodeID | |
| 112 }; | |
| 113 } | |
| 114 | |
| 115 return {}; | |
| 116 } | |
| 117 | |
| 118 function getNodeData(node, parentNode) | |
| 119 { | |
| 120 if (!node || node.nodeType != Ci.nsIDOMNode.ELEMENT_NODE) | |
| 121 return null; | |
| 122 | |
| 123 let result = {}; | |
| 124 result.tagName = {value: node.tagName, checked: false}; | |
| 125 | |
| 126 if (typeof parentNode != "undefined") | |
| 127 result.parentNode = parentNode; | |
| 128 else | |
| 129 result.parentNode = getNodeData(node.parentElement); | |
| 130 | |
| 131 let prevSibling = node.previousElementSibling; | |
| 132 result.prevSibling = getNodeData(prevSibling, result.parentNode); | |
| 133 | |
| 134 if (result.parentNode && !prevSibling) | |
| 135 result.firstChild = {checked: false}; | |
| 136 | |
| 137 let nextSibling = node.nextElementSibling; | |
| 138 if (result.parentNode && !nextSibling) | |
| 139 result.lastChild = {checked: false}; | |
| 140 | |
| 141 result.attributes = []; | |
| 142 for (let attribute of node.attributes) | |
| 143 { | |
| 144 let data = { | |
| 145 name: attribute.name, | |
| 146 value: attribute.value, | |
| 147 selected: attribute.value, | |
| 148 checked: false | |
| 149 }; | |
| 150 if (data.name == "id" || data.name == "class") | |
| 151 result.attributes.unshift(data); | |
| 152 else | |
| 153 result.attributes.push(data); | |
| 154 } | |
| 155 | |
| 156 if (result.attributes.length >= 2 && result.attributes[1].name == "id") | |
| 157 { | |
| 158 // Make sure ID attribute comes first | |
| 159 let tmp = result.attributes[1]; | |
| 160 result.attributes[1] = result.attributes[0]; | |
| 161 result.attributes[0] = tmp; | |
| 162 } | |
| 163 | |
| 164 result.customCSS = {selected: "", checked: false}; | |
| 165 return result; | |
| 166 } | |
| 167 | |
| 168 function togglePreview(nodeID, stylesheetData) | |
| 169 { | |
| 170 let context = nodes.get(nodeID); | |
| 171 if (!context) | |
| 172 return; | |
| 173 | |
| 174 if (stylesheetData) | |
| 175 { | |
| 176 if (!context.style || !context.style.parentNode) | |
| 177 { | |
| 178 context.style = context.document.createElementNS( | |
| 179 "http://www.w3.org/1999/xhtml", "style"); | |
| 180 context.style.setAttribute("type", "text/css"); | |
| 181 context.document.documentElement.appendChild(context.style); | |
| 182 } | |
| 183 context.style.textContent = stylesheetData; | |
| 184 } | |
| 185 else | |
| 186 { | |
| 187 try | |
| 188 { | |
| 189 if (context.style && context.style.parentNode) | |
| 190 context.style.parentNode.removeChild(context.style); | |
| 191 context.style = null; | |
| 192 } | |
| 193 catch (e) | |
| 194 { | |
| 195 // If the window was closed (reloaded) we end up with a dead object | |
| 196 // reference (https://bugzilla.mozilla.org/show_bug.cgi?id=695480). Just | |
| 197 // forget this node then. | |
| 198 forgetNode(nodeID); | |
| 199 } | |
| 200 } | |
| 201 } | |
| 202 | |
| 203 function forgetNode(nodeID) | |
| 204 { | |
| 205 nodes.delete(nodeID); | |
| 206 } | |
| OLD | NEW |