| 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 |
|
saroyanm
2016/11/23 17:44:37
Irrelevant: Why is this file called Aadvark ?
Wladimir Palant
2016/11/24 14:02:00
The origin of this code is the Aardvark extension
| |
| 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 let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); | 7 let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); |
| 8 | 8 |
| 9 let {Prefs} = require("prefs"); | 9 let {Prefs} = require("prefs"); |
| 10 | 10 |
| 11 // Make sure to stop selection when we are uninstalled | 11 let messageManager = Cc["@mozilla.org/parentprocessmessagemanager;1"] |
| 12 onShutdown.add(() => Aardvark.quit()); | 12 .getService(Ci.nsIMessageListenerManager) |
| 13 .QueryInterface(Ci.nsIMessageBroadcaster); | |
| 13 | 14 |
| 14 // To be replaced when selection starts | 15 // To be replaced when selection starts |
| 15 function E(id) {return null;} | 16 function E(id) {return null;} |
| 16 | 17 |
| 17 let messageCounter = 0; | 18 messageManager.addMessageListener("ElemHideHelper:SelectionStarted", selectionSt arted); |
|
saroyanm
2016/11/23 17:44:37
Nit: Exceeding 80 chars
Wladimir Palant
2016/11/24 14:02:01
Done.
| |
| 19 messageManager.addMessageListener("ElemHideHelper:SelectionSucceeded", selection Succeeded); | |
| 20 messageManager.addMessageListener("ElemHideHelper:SelectionStopped", selectionSt opped); | |
| 21 onShutdown.add(() => | |
| 22 { | |
| 23 messageManager.removeMessageListener("ElemHideHelper:SelectionStarted", select ionStarted); | |
| 24 messageManager.removeMessageListener("ElemHideHelper:SelectionSucceeded", sele ctionSucceeded); | |
| 25 messageManager.removeMessageListener("ElemHideHelper:SelectionStopped", select ionStopped); | |
| 18 | 26 |
| 19 /********************************* | 27 selectionStopped(); |
| 20 * Minimal element creation code * | 28 }); |
| 21 *********************************/ | |
| 22 | 29 |
| 23 function createElement(doc, tagName, attrs, children) | 30 function selectionStarted(message) |
| 24 { | 31 { |
| 25 let el = doc.createElement(tagName); | 32 Aardvark.selectionStarted(); |
| 26 if (attrs) | 33 } |
| 27 for (let key in attrs) | 34 |
| 28 el.setAttribute(key, attrs[key]); | 35 function selectionSucceeded(message) |
| 29 if (children) | 36 { |
| 30 for (let child of children) | 37 Aardvark.selectionSucceeded(message.data); |
| 31 el.appendChild(child) | 38 } |
| 32 return el; | 39 |
| 33 }; | 40 function selectionStopped(message) |
| 41 { | |
| 42 Aardvark.selectionStopped(); | |
| 43 } | |
| 34 | 44 |
| 35 /********************************** | 45 /********************************** |
| 36 * General element selection code * | 46 * General element selection code * |
| 37 **********************************/ | 47 **********************************/ |
| 38 | 48 |
| 39 let Aardvark = exports.Aardvark = | 49 let Aardvark = exports.Aardvark = |
| 40 { | 50 { |
| 41 window: null, | 51 window: null, |
| 42 browser: null, | 52 browser: null, |
| 43 anchorElem: null, | 53 rememberedWrapper: null, |
|
saroyanm
2016/11/23 17:44:37
Curious: Why rememberedWrapper, but not just wrapp
Wladimir Palant
2016/11/24 14:02:00
Its a temporary state, a bit of a hack so that we
| |
| 44 selectedElem: null, | |
| 45 isUserSelected: false, | |
| 46 lockedAnchor: null, | |
| 47 commentElem: null, | |
| 48 mouseX: -1, | 54 mouseX: -1, |
| 49 mouseY: -1, | 55 mouseY: -1, |
| 50 prevSelectionUpdate: -1, | |
| 51 commandLabelTimer: null, | 56 commandLabelTimer: null, |
| 52 viewSourceTimer: null, | 57 viewSourceTimer: null, |
| 53 boxElem: null, | |
| 54 paintNode: null, | |
| 55 prevPos: null, | |
| 56 | 58 |
| 57 start: function(wrapper) | 59 start: function(wrapper) |
| 58 { | 60 { |
| 59 if (!this.canSelect(wrapper.browser)) | 61 this.rememberedWrapper = wrapper; |
| 60 return; | 62 let browser = wrapper.browser; |
| 63 if ("selectedBrowser" in browser) | |
|
saroyanm
2016/11/23 17:44:38
What is "selectedBrowser" property ?
Are we assig
Wladimir Palant
2016/11/24 14:02:01
You need to look at https://developer.mozilla.org/
| |
| 64 browser = browser.selectedBrowser; | |
| 65 messageManager.broadcastAsyncMessage( | |
| 66 "ElemHideHelper:StartSelection", | |
| 67 browser.outerWindowID | |
| 68 ); | |
| 69 }, | |
| 61 | 70 |
| 62 if (this.browser) | 71 selectionStarted: function() |
| 63 this.quit(); | 72 { |
| 73 let wrapper = this.rememberedWrapper; | |
| 74 this.rememberedWrapper = null; | |
| 64 | 75 |
| 65 this.window = wrapper.window; | 76 this.window = wrapper.window; |
| 66 this.browser = wrapper.browser; | 77 this.browser = wrapper.browser; |
|
saroyanm
2016/11/23 17:44:38
We already assigning this.rememberedWrapper value
Wladimir Palant
2016/11/24 14:02:01
No, we are only assigning it to the local browser
| |
| 67 E = id => wrapper.E(id); | 78 E = id => wrapper.E(id); |
| 68 | 79 |
| 69 this.browser.addEventListener("click", this.onMouseClick, true); | |
| 70 this.browser.addEventListener("DOMMouseScroll", this.onMouseScroll, true); | |
| 71 this.browser.addEventListener("keypress", this.onKeyPress, true); | 80 this.browser.addEventListener("keypress", this.onKeyPress, true); |
| 72 this.browser.addEventListener("mousemove", this.onMouseMove, true); | 81 this.browser.addEventListener("mousemove", this.onMouseMove, false); |
| 73 this.browser.addEventListener("select", this.quit, false); | 82 this.browser.addEventListener("select", this.onTabSelect, false); |
| 74 this.browser.contentWindow.addEventListener("pagehide", this.onPageHide, tru e); | |
| 75 | |
| 76 this.browser.contentWindow.focus(); | |
| 77 | |
| 78 let doc = this.browser.contentDocument; | |
| 79 let {elementMarkerClass} = require("main"); | |
| 80 this.boxElem = createElement(doc, "div", {"class": elementMarkerClass}, [ | |
| 81 createElement(doc, "div", {"class": "ehh-border"}), | |
| 82 createElement(doc, "div", {"class": "ehh-label"}, [ | |
| 83 createElement(doc, "span", {"class": "ehh-labelTag"}), | |
| 84 createElement(doc, "span", {"class": "ehh-labelAddition"}) | |
| 85 ]) | |
| 86 ]); | |
| 87 | 83 |
| 88 this.initHelpBox(); | 84 this.initHelpBox(); |
| 89 | 85 |
| 90 if (Prefs.showhelp) | 86 if (Prefs.showhelp) |
| 91 this.showMenu(); | 87 this.showMenu(); |
| 92 | |
| 93 // Make sure to select some element immeditely (whichever is in the center o f the browser window) | |
| 94 let [wndWidth, wndHeight] = this.getWindowSize(doc.defaultView); | |
| 95 this.isUserSelected = false; | |
| 96 this.onMouseMove({clientX: wndWidth / 2, clientY: wndHeight / 2, screenX: -1 , screenY: -1, target: null}); | |
| 97 }, | 88 }, |
| 98 | 89 |
| 99 canSelect: function(browser) | 90 selectionSucceeded: function(nodeInfo) |
| 100 { | 91 { |
| 101 if (!browser || !browser.contentWindow || | 92 this.window.openDialog("chrome://elemhidehelper/content/composer.xul", |
|
saroyanm
2016/11/23 17:44:37
Shouldn't we also remove eventlisteners on selecti
Wladimir Palant
2016/11/24 14:02:01
No, the select command (in lib/child/commands.js)
| |
| 102 !(browser.contentDocument instanceof Ci.nsIDOMHTMLDocument)) | 93 "_blank", "chrome,centerscreen,resizable,dialog=no", nodeInfo); |
|
Wladimir Palant
2016/11/17 13:54:47
This function is pretty much what Aardvark.select(
saroyanm
2016/11/23 17:44:38
Acknowledged.
| |
| 103 { | 94 }, |
| 104 return false; | |
| 105 } | |
| 106 | 95 |
| 107 let location = browser.contentWindow.location; | 96 selectionStopped: function() |
| 108 if (location.href == "about:blank") | 97 { |
| 109 return false; | 98 if (!this.browser) |
| 99 return; | |
| 110 | 100 |
| 111 if (!Prefs.acceptlocalfiles && | 101 if (this.commandLabelTimer) |
| 112 location.hostname == "" && | 102 this.commandLabelTimer.cancel(); |
| 113 location.protocol != "mailbox:" && | 103 if (this.viewSourceTimer) |
| 114 location.protocol != "imap:" && | 104 this.viewSourceTimer.cancel(); |
| 115 location.protocol != "news:" && | 105 this.commandLabelTimer = null; |
| 116 location.protocol != "snews:") | 106 this.viewSourceTimer = null; |
| 117 { | |
| 118 return false; | |
| 119 } | |
| 120 | 107 |
| 121 return true; | 108 this.hideTooltips(); |
| 109 | |
| 110 this.browser.removeEventListener("keypress", this.onKeyPress, true); | |
| 111 this.browser.removeEventListener("mousemove", this.onMouseMove, false); | |
| 112 this.browser.removeEventListener("select", this.onTabSelect, false); | |
| 113 | |
| 114 this.window = null; | |
| 115 this.browser = null; | |
| 116 E = id => null; | |
|
Wladimir Palant
2016/11/17 13:54:47
This function is what Aardvark.quit() used to be.
saroyanm
2016/11/23 17:44:37
Acknowledged.
| |
| 122 }, | 117 }, |
| 123 | 118 |
| 124 doCommand: function(command, event) | 119 doCommand: function(command, event) |
| 125 { | 120 { |
| 126 if (this[command](this.selectedElem)) | 121 let showFeedback; |
| 122 if (this.hasOwnProperty(command)) | |
| 123 showFeedback = this[command](); | |
|
Wladimir Palant
2016/11/17 13:54:47
The command handler no longer gets the selected el
saroyanm
2016/11/23 17:44:38
Acknowledged.
| |
| 124 else | |
| 125 { | |
| 126 showFeedback = (command != "select" && command != "quit"); | |
|
Wladimir Palant
2016/11/17 13:54:47
This changes behavior slightly - e.g. you will get
saroyanm
2016/11/23 17:44:37
Acknowledged.
| |
| 127 messageManager.broadcastAsyncMessage("ElemHideHelper:Command", command); | |
| 128 } | |
| 129 | |
| 130 if (showFeedback) | |
| 127 { | 131 { |
| 128 this.showCommandLabel(this.commands[command + "_key"], this.commands[comma nd + "_altkey"], this.commands[command + "_label"]); | 132 this.showCommandLabel(this.commands[command + "_key"], this.commands[comma nd + "_altkey"], this.commands[command + "_label"]); |
| 129 if (event) | 133 if (event) |
| 130 event.stopPropagation(); | 134 event.stopPropagation(); |
| 131 } | 135 } |
| 132 if (event) | 136 if (event) |
| 133 event.preventDefault(); | 137 event.preventDefault(); |
| 134 }, | 138 }, |
| 135 | 139 |
| 136 showCommandLabel: function(key, alternativeKey, label) | 140 showCommandLabel: function(key, alternativeKey, label) |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 197 { | 201 { |
| 198 let tooltips = ["ehh-helpbox", "ehh-commandlabel", "ehh-viewsource"]; | 202 let tooltips = ["ehh-helpbox", "ehh-commandlabel", "ehh-viewsource"]; |
| 199 for (let i = 0; i < tooltips.length; i++) | 203 for (let i = 0; i < tooltips.length; i++) |
| 200 { | 204 { |
| 201 let tooltip = E(tooltips[i]); | 205 let tooltip = E(tooltips[i]); |
| 202 if (tooltip) | 206 if (tooltip) |
| 203 tooltip.hidePopup(); | 207 tooltip.hidePopup(); |
| 204 } | 208 } |
| 205 }, | 209 }, |
| 206 | 210 |
| 207 onMouseClick: function(event) | |
| 208 { | |
| 209 if (event.button != 0 || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) | |
| 210 return; | |
| 211 | |
| 212 this.doCommand("select", event); | |
| 213 }, | |
| 214 | |
| 215 onMouseScroll: function(event) | |
| 216 { | |
| 217 if (!event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) | |
| 218 return; | |
| 219 | |
| 220 if ("axis" in event && event.axis != event.VERTICAL_AXIS) | |
| 221 return; | |
| 222 | |
| 223 this.doCommand(event.detail > 0 ? "wider" : "narrower", event); | |
| 224 }, | |
| 225 | |
| 226 onKeyPress: function(event) | 211 onKeyPress: function(event) |
| 227 { | 212 { |
| 228 if (event.altKey || event.ctrlKey || event.metaKey) | 213 if (event.altKey || event.ctrlKey || event.metaKey) |
| 229 return; | 214 return; |
| 230 | 215 |
| 231 var command = null; | 216 var command = null; |
| 232 if (event.keyCode == event.DOM_VK_ESCAPE) | 217 if (event.keyCode == event.DOM_VK_ESCAPE) |
|
saroyanm
2016/11/23 17:44:38
Note: keyCode is a deprecated property.
You want m
Wladimir Palant
2016/11/24 14:02:01
Yes, definitely.
saroyanm
2016/11/25 16:18:13
Done -> #4666
| |
| 233 command = "quit"; | 218 command = "quit"; |
| 234 else if (event.keyCode == event.DOM_VK_RETURN) | 219 else if (event.keyCode == event.DOM_VK_RETURN) |
| 235 command = "select"; | 220 command = "select"; |
| 236 else if (event.charCode) | 221 else if (event.charCode) |
| 237 { | 222 { |
| 238 var key = String.fromCharCode(event.charCode).toLowerCase(); | 223 var key = String.fromCharCode(event.charCode).toLowerCase(); |
| 239 var commands = this.commands; | 224 var commands = this.commands; |
| 240 for (var i = 0; i < commands.length; i++) | 225 for (var i = 0; i < commands.length; i++) |
| 241 if (commands[commands[i] + "_key"] == key || commands[commands[i] + "_al tkey"] == key) | 226 if (commands[commands[i] + "_key"] == key || commands[commands[i] + "_al tkey"] == key) |
| 242 command = commands[i]; | 227 command = commands[i]; |
| 243 } | 228 } |
| 244 | 229 |
| 245 if (command) | 230 if (command) |
| 246 this.doCommand(command, event); | 231 this.doCommand(command, event); |
| 247 }, | 232 }, |
| 248 | 233 |
| 249 onPageHide: function(event) | |
| 250 { | |
| 251 this.doCommand("quit", null); | |
| 252 }, | |
| 253 | |
| 254 onMouseMove: function(event) | 234 onMouseMove: function(event) |
| 255 { | 235 { |
| 256 this.mouseX = event.screenX; | 236 this.mouseX = event.screenX; |
| 257 this.mouseY = event.screenY; | 237 this.mouseY = event.screenY; |
| 258 | |
| 259 this.hideSelection(); | |
| 260 if (!this.browser) | |
| 261 { | |
| 262 // hideSelection() called quit() | |
| 263 return; | |
| 264 } | |
| 265 | |
| 266 let x = event.clientX; | |
| 267 let y = event.clientY; | |
| 268 | |
| 269 // We might have coordinates relative to a frame, recalculate relative to to p window | |
| 270 let node = event.target; | |
| 271 while (node && node.ownerDocument && node.ownerDocument.defaultView && node. ownerDocument.defaultView.frameElement) | |
| 272 { | |
| 273 node = node.ownerDocument.defaultView.frameElement; | |
| 274 let rect = node.getBoundingClientRect(); | |
| 275 x += rect.left; | |
| 276 y += rect.top; | |
| 277 } | |
| 278 | |
| 279 let elem = this.browser.contentDocument.elementFromPoint(x, y); | |
| 280 while (elem && "contentDocument" in elem && this.canSelect(elem)) | |
| 281 { | |
| 282 let rect = elem.getBoundingClientRect(); | |
| 283 x -= rect.left; | |
| 284 y -= rect.top; | |
| 285 elem = elem.contentDocument.elementFromPoint(x, y); | |
| 286 } | |
| 287 | |
| 288 if (elem) | |
| 289 { | |
| 290 if (!this.lockedAnchor) | |
| 291 this.setAnchorElement(elem); | |
| 292 else | |
| 293 { | |
| 294 this.lockedAnchor = elem; | |
| 295 this.selectElement(this.selectedElem); | |
| 296 } | |
| 297 } | |
| 298 }, | 238 }, |
| 299 | 239 |
| 300 onAfterPaint: function() | 240 onTabSelect: function(event) |
| 301 { | 241 { |
| 302 // Don't update position too often | 242 this.doCommand("quit", null); |
| 303 if (this.selectedElem && Date.now() - this.prevSelectionUpdate > 20) | |
| 304 { | |
| 305 let pos = this.getElementPosition(this.selectedElem); | |
| 306 if (!this.prevPos || this.prevPos.left != pos.left || this.prevPos.right ! = pos.right | |
| 307 || this.prevPos.top != pos.top || this.prevPos.bottom != pos.bottom) | |
| 308 { | |
| 309 this.selectElement(this.selectedElem); | |
| 310 } | |
| 311 } | |
| 312 }, | |
| 313 | |
| 314 setAnchorElement: function(anchor) | |
| 315 { | |
| 316 this.anchorElem = anchor; | |
| 317 | |
| 318 let newSelection = anchor; | |
| 319 if (this.isUserSelected) | |
| 320 { | |
| 321 // User chose an element via wider/narrower commands, keep the selection i f | |
| 322 // out new anchor is still a child of that element | |
| 323 let e = newSelection; | |
| 324 while (e && e != this.selectedElem) | |
| 325 e = this.getParentElement(e); | |
| 326 | |
| 327 if (e) | |
| 328 newSelection = this.selectedElem; | |
| 329 else | |
| 330 this.isUserSelected = false; | |
| 331 } | |
| 332 | |
| 333 this.selectElement(newSelection); | |
| 334 }, | 243 }, |
| 335 | 244 |
| 336 appendDescription: function(node, value, className) | 245 appendDescription: function(node, value, className) |
| 337 { | 246 { |
| 338 var descr = this.window.document.createElement("description"); | 247 var descr = this.window.document.createElement("description"); |
| 339 descr.setAttribute("value", value); | 248 descr.setAttribute("value", value); |
| 340 if (className) | 249 if (className) |
| 341 descr.setAttribute("class", className); | 250 descr.setAttribute("class", className); |
| 342 node.appendChild(descr); | 251 node.appendChild(descr); |
| 343 }, | 252 }, |
| 344 | 253 |
| 345 /************************** | |
| 346 * Element marker display * | |
| 347 **************************/ | |
| 348 | |
| 349 getElementLabel: function(elem) | |
| 350 { | |
| 351 let tagName = elem.tagName.toLowerCase(); | |
| 352 let addition = ""; | |
| 353 if (elem.id != "") | |
| 354 addition += ", id: " + elem.id; | |
| 355 if (elem.className != "") | |
| 356 addition += ", class: " + elem.className; | |
| 357 if (elem.style.cssText != "") | |
| 358 addition += ", style: " + elem.style.cssText; | |
| 359 | |
| 360 return [tagName, addition]; | |
| 361 }, | |
| 362 | |
| 363 selectElement: function(elem) | |
| 364 { | |
| 365 this.selectedElem = elem; | |
| 366 this.prevSelectionUpdate = Date.now(); | |
| 367 | |
| 368 let border = this.boxElem.getElementsByClassName("ehh-border")[0]; | |
| 369 let label = this.boxElem.getElementsByClassName("ehh-label")[0]; | |
| 370 let labelTag = this.boxElem.getElementsByClassName("ehh-labelTag")[0]; | |
| 371 let labelAddition = this.boxElem.getElementsByClassName("ehh-labelAddition") [0]; | |
| 372 | |
| 373 if (this.boxElem.parentNode) | |
| 374 this.boxElem.parentNode.removeChild(this.boxElem); | |
| 375 | |
| 376 let doc = this.browser.contentDocument; | |
| 377 let [wndWidth, wndHeight] = this.getWindowSize(doc.defaultView); | |
| 378 | |
| 379 let pos = this.getElementPosition(elem); | |
| 380 this.boxElem.style.left = Math.min(pos.left - 1, wndWidth - 2) + "px"; | |
| 381 this.boxElem.style.top = Math.min(pos.top - 1, wndHeight - 2) + "px"; | |
| 382 border.style.width = Math.max(pos.right - pos.left - 2, 0) + "px"; | |
| 383 border.style.height = Math.max(pos.bottom - pos.top - 2, 0) + "px"; | |
| 384 | |
| 385 [labelTag.textContent, labelAddition.textContent] = this.getElementLabel(ele m); | |
| 386 | |
| 387 // If there is not enough space to show the label move it up a little | |
| 388 if (pos.bottom < wndHeight - 25) | |
| 389 label.className = "ehh-label"; | |
| 390 else | |
| 391 label.className = "ehh-label onTop"; | |
| 392 | |
| 393 doc.documentElement.appendChild(this.boxElem); | |
| 394 | |
| 395 this.paintNode = doc.defaultView; | |
| 396 if (this.paintNode) | |
| 397 { | |
| 398 this.prevPos = pos; | |
| 399 this.paintNode.addEventListener("MozAfterPaint", this.onAfterPaint, false) ; | |
| 400 } | |
| 401 }, | |
| 402 | |
| 403 hideSelection: function() | |
| 404 { | |
| 405 try | |
| 406 { | |
| 407 if (this.boxElem.parentNode) | |
| 408 this.boxElem.parentNode.removeChild(this.boxElem); | |
| 409 } | |
| 410 catch (e) | |
| 411 { | |
| 412 // Are we using CPOW whose process is gone? Quit! | |
| 413 // Clear some variables to prevent recursion (quit will call us again). | |
| 414 this.boxElem = {}; | |
| 415 this.paintNode = null; | |
| 416 this.quit(); | |
| 417 return; | |
| 418 } | |
| 419 | |
| 420 if (this.paintNode) | |
| 421 this.paintNode.removeEventListener("MozAfterPaint", this.onAfterPaint, fal se); | |
| 422 | |
| 423 this.paintNode = null; | |
| 424 this.prevPos = null; | |
| 425 }, | |
| 426 | |
| 427 getWindowSize: function(wnd) | |
| 428 { | |
| 429 return [wnd.innerWidth, wnd.document.documentElement.clientHeight]; | |
| 430 }, | |
| 431 | |
| 432 getElementPosition: function(element) | |
| 433 { | |
| 434 // Restrict rectangle coordinates by the boundaries of a window's client are a | |
| 435 function intersectRect(rect, wnd) | |
| 436 { | |
| 437 let [wndWidth, wndHeight] = this.getWindowSize(wnd); | |
| 438 rect.left = Math.max(rect.left, 0); | |
| 439 rect.top = Math.max(rect.top, 0); | |
| 440 rect.right = Math.min(rect.right, wndWidth); | |
| 441 rect.bottom = Math.min(rect.bottom, wndHeight); | |
| 442 } | |
| 443 | |
| 444 let rect = element.getBoundingClientRect(); | |
| 445 let wnd = element.ownerDocument.defaultView; | |
| 446 | |
| 447 rect = {left: rect.left, top: rect.top, | |
| 448 right: rect.right, bottom: rect.bottom}; | |
| 449 while (true) | |
| 450 { | |
| 451 intersectRect.call(this, rect, wnd); | |
| 452 | |
| 453 if (!wnd.frameElement) | |
| 454 break; | |
| 455 | |
| 456 // Recalculate coordinates to be relative to frame's parent window | |
| 457 let frameElement = wnd.frameElement; | |
| 458 wnd = frameElement.ownerDocument.defaultView; | |
| 459 | |
| 460 let frameRect = frameElement.getBoundingClientRect(); | |
| 461 let frameStyle = wnd.getComputedStyle(frameElement, null); | |
| 462 let relLeft = frameRect.left + parseFloat(frameStyle.borderLeftWidth) + pa rseFloat(frameStyle.paddingLeft); | |
| 463 let relTop = frameRect.top + parseFloat(frameStyle.borderTopWidth) + parse Float(frameStyle.paddingTop); | |
| 464 | |
| 465 rect.left += relLeft; | |
| 466 rect.right += relLeft; | |
| 467 rect.top += relTop; | |
| 468 rect.bottom += relTop; | |
| 469 } | |
| 470 | |
| 471 return rect; | |
| 472 }, | |
| 473 | |
| 474 getParentElement: function(elem) | |
| 475 { | |
| 476 let result = elem.parentNode; | |
| 477 if (result && result.nodeType == Ci.nsIDOMElement.DOCUMENT_NODE && result.de faultView && result.defaultView.frameElement) | |
| 478 result = result.defaultView.frameElement; | |
| 479 | |
| 480 if (result && result.nodeType != Ci.nsIDOMElement.ELEMENT_NODE) | |
| 481 return null; | |
| 482 | |
| 483 return result; | |
| 484 }, | |
| 485 | |
| 486 /*************************** | 254 /*************************** |
| 487 * Commands implementation * | 255 * Commands implementation * |
| 488 ***************************/ | 256 ***************************/ |
| 489 | 257 |
| 490 commands: [ | 258 commands: [ |
| 491 "select", | 259 "select", |
| 492 "wider", | 260 "wider", |
| 493 "narrower", | 261 "narrower", |
| 494 "lock", | 262 "lock", |
| 495 "quit", | 263 "quit", |
| 496 "blinkElement", | 264 "blinkElement", |
| 497 "viewSource", | 265 "viewSource", |
| 498 "viewSourceWindow", | 266 "viewSourceWindow", |
| 499 "showMenu" | 267 "showMenu" |
| 500 ], | 268 ], |
| 501 | 269 |
| 502 wider: function(elem) | |
| 503 { | |
| 504 if (!elem) | |
| 505 return false; | |
| 506 | |
| 507 let newElem = this.getParentElement(elem); | |
| 508 if (!newElem) | |
| 509 return false; | |
| 510 | |
| 511 this.isUserSelected = true; | |
| 512 this.selectElement(newElem); | |
| 513 return true; | |
| 514 }, | |
| 515 | |
| 516 narrower: function(elem) | |
| 517 { | |
| 518 if (elem) | |
| 519 { | |
| 520 // Search selected element in the parent chain, starting with the anchor e lement. | |
| 521 // We need to select the element just before the selected one. | |
| 522 let e = this.anchorElem; | |
| 523 let newElem = null; | |
| 524 while (e && e != elem) | |
| 525 { | |
| 526 newElem = e; | |
| 527 e = this.getParentElement(e); | |
| 528 } | |
| 529 | |
| 530 if (!e || !newElem) | |
| 531 return false; | |
| 532 | |
| 533 this.isUserSelected = true; | |
| 534 this.selectElement(newElem); | |
| 535 return true; | |
| 536 } | |
| 537 return false; | |
| 538 }, | |
| 539 | |
| 540 lock: function(elem) | |
| 541 { | |
| 542 if (!elem) | |
| 543 return false; | |
| 544 | |
| 545 if (this.lockedAnchor) | |
| 546 { | |
| 547 this.setAnchorElement(this.lockedAnchor); | |
| 548 this.lockedAnchor = null; | |
| 549 } | |
| 550 else | |
| 551 this.lockedAnchor = this.anchorElem; | |
| 552 | |
| 553 return true; | |
| 554 }, | |
| 555 | |
| 556 quit: function() | |
| 557 { | |
| 558 if (!this.browser) | |
| 559 return false; | |
| 560 | |
| 561 if ("blinkTimer" in this) | |
| 562 this.stopBlinking(); | |
| 563 | |
| 564 if (this.commandLabelTimer) | |
| 565 this.commandLabelTimer.cancel(); | |
| 566 if (this.viewSourceTimer) | |
| 567 this.viewSourceTimer.cancel(); | |
| 568 this.commandLabelTimer = null; | |
| 569 this.viewSourceTimer = null; | |
| 570 | |
| 571 this.hideSelection(); | |
| 572 this.hideTooltips(); | |
| 573 | |
| 574 this.browser.removeEventListener("click", this.onMouseClick, true); | |
| 575 this.browser.removeEventListener("DOMMouseScroll", this.onMouseScroll, true) ; | |
| 576 this.browser.removeEventListener("keypress", this.onKeyPress, true); | |
| 577 this.browser.removeEventListener("mousemove", this.onMouseMove, true); | |
| 578 this.browser.removeEventListener("select", this.quit, false); | |
| 579 this.browser.contentWindow.removeEventListener("pagehide", this.onPageHide, true); | |
| 580 | |
| 581 this.anchorElem = null; | |
| 582 this.selectedElem = null; | |
| 583 this.window = null; | |
| 584 this.browser = null; | |
| 585 this.commentElem = null; | |
| 586 this.lockedAnchor = null; | |
| 587 this.boxElem = null; | |
| 588 E = id => null; | |
| 589 return false; | |
| 590 }, | |
| 591 | |
| 592 select: function(elem) | |
| 593 { | |
| 594 if (!elem || !this.window) | |
| 595 return false; | |
| 596 | |
| 597 let messageManager = Cc["@mozilla.org/parentprocessmessagemanager;1"] | |
| 598 .getService(Ci.nsIMessageBroadcaster); | |
| 599 let messageId = ++messageCounter; | |
| 600 let callback = (message) => | |
| 601 { | |
| 602 let response = message.data; | |
| 603 if (response.messageId != messageId) | |
| 604 return; | |
| 605 | |
| 606 messageManager.removeMessageListener( | |
| 607 "ElemHideHelper:GetNodeInfo:Response", | |
| 608 callback | |
| 609 ); | |
| 610 | |
| 611 if (!response.nodeData) | |
| 612 return; | |
| 613 | |
| 614 this.window.openDialog("chrome://elemhidehelper/content/composer.xul", | |
| 615 "_blank", "chrome,centerscreen,resizable,dialog=no", response); | |
| 616 this.quit(); | |
| 617 }; | |
| 618 | |
| 619 messageManager.addMessageListener( | |
| 620 "ElemHideHelper:GetNodeInfo:Response", | |
| 621 callback | |
| 622 ); | |
| 623 messageManager.broadcastAsyncMessage( | |
| 624 "ElemHideHelper:GetNodeInfo", | |
| 625 messageId, | |
| 626 { | |
| 627 element: elem | |
| 628 } | |
| 629 ); | |
| 630 return false; | |
| 631 }, | |
| 632 | |
| 633 blinkElement: function(elem) | |
| 634 { | |
| 635 if (!elem) | |
| 636 return false; | |
| 637 | |
| 638 if ("blinkTimer" in this) | |
| 639 this.stopBlinking(); | |
| 640 | |
| 641 let counter = 0; | |
| 642 this.blinkElem = elem; | |
| 643 this.blinkOrigValue = elem.style.visibility; | |
| 644 this.blinkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); | |
| 645 this.blinkTimer.initWithCallback(function() | |
| 646 { | |
| 647 counter++; | |
| 648 elem.style.visibility = (counter % 2 == 0 ? "visible" : "hidden"); | |
| 649 if (counter == 6) | |
| 650 Aardvark.stopBlinking(); | |
| 651 }, 250, Ci.nsITimer.TYPE_REPEATING_SLACK); | |
| 652 | |
| 653 return true; | |
| 654 }, | |
| 655 | |
| 656 stopBlinking: function() | |
| 657 { | |
| 658 this.blinkTimer.cancel(); | |
| 659 this.blinkElem.style.visibility = this.blinkOrigValue; | |
| 660 | |
| 661 delete this.blinkElem; | |
| 662 delete this.blinkOrigValue; | |
| 663 delete this.blinkTimer; | |
| 664 }, | |
| 665 | |
| 666 viewSource: function(elem) | 270 viewSource: function(elem) |
| 667 { | 271 { |
| 668 if (!elem) | 272 if (!elem) |
| 669 return false; | 273 return false; |
| 670 | 274 |
| 671 var sourceBox = E("ehh-viewsource"); | 275 var sourceBox = E("ehh-viewsource"); |
| 672 if (sourceBox.state == "open" && this.commentElem == elem) | 276 if (sourceBox.state == "open") |
|
Wladimir Palant
2016/11/17 13:54:47
This is a behavior change, originally we would onl
| |
| 673 { | 277 { |
| 674 sourceBox.hidePopup(); | 278 sourceBox.hidePopup(); |
| 675 return true; | 279 return true; |
| 676 } | 280 } |
| 677 sourceBox.hidePopup(); | 281 sourceBox.hidePopup(); |
| 678 | 282 |
| 679 while (sourceBox.firstElementChild) | 283 while (sourceBox.firstElementChild) |
| 680 sourceBox.removeChild(sourceBox.firstElementChild); | 284 sourceBox.removeChild(sourceBox.firstElementChild); |
| 681 this.getOuterHtmlFormatted(elem, sourceBox); | 285 this.getOuterHtmlFormatted(elem, sourceBox); |
| 682 this.commentElem = elem; | |
| 683 | 286 |
| 684 let anchor = this.window.document.documentElement; | 287 let anchor = this.window.document.documentElement; |
| 685 let x = this.mouseX; | 288 let x = this.mouseX; |
| 686 let y = this.mouseY; | 289 let y = this.mouseY; |
| 687 this.viewSourceTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer ); | 290 this.viewSourceTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer ); |
| 688 this.viewSourceTimer.initWithCallback(function() | 291 this.viewSourceTimer.initWithCallback(function() |
| 689 { | 292 { |
| 690 sourceBox.showPopup(anchor, x, y, "tooltip", "topleft", "topleft"); | 293 sourceBox.showPopup(anchor, x, y, "tooltip", "topleft", "topleft"); |
| 691 Aardvark.viewSourceTimer = null; | 294 Aardvark.viewSourceTimer = null; |
| 692 }, 500, Ci.nsITimer.TYPE_ONE_SHOT); | 295 }, 500, Ci.nsITimer.TYPE_ONE_SHOT); |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 817 } | 420 } |
| 818 | 421 |
| 819 // Show help box | 422 // Show help box |
| 820 helpBox.showPopup(this.browser, -1, -1, "tooltip", "topleft", "topleft"); | 423 helpBox.showPopup(this.browser, -1, -1, "tooltip", "topleft", "topleft"); |
| 821 return true; | 424 return true; |
| 822 } | 425 } |
| 823 } | 426 } |
| 824 | 427 |
| 825 // Makes sure event handlers like Aardvark.onKeyPress always have the correct | 428 // Makes sure event handlers like Aardvark.onKeyPress always have the correct |
| 826 // this pointer set. | 429 // this pointer set. |
| 827 for (let method of ["onMouseClick", "onMouseScroll", "onKeyPress", "onPageHide", "onMouseMove", "onAfterPaint", "quit"]) | 430 for (let method of ["onKeyPress", "onMouseMove", "onTabSelect"]) |
| 828 Aardvark[method] = Aardvark[method].bind(Aardvark); | 431 Aardvark[method] = Aardvark[method].bind(Aardvark); |
| OLD | NEW |