Index: lib/aardvark.js
===================================================================
--- a/lib/aardvark.js
+++ b/lib/aardvark.js
@@ -33,69 +33,69 @@ let Aardvark = exports.Aardvark =
   boxElem: null,
   paintNode: null,
   prevPos: null,
 
   start: function(wrapper)
   {
     if (!this.canSelect(wrapper.browser))
       return;
-  
+
     if (this.browser)
       this.quit();
-  
+
     this.window = wrapper.window;
     this.browser = wrapper.browser;
     E = function(id) wrapper.E(id);
-  
+
     this.browser.addEventListener("click", this.onMouseClick, true);
     this.browser.addEventListener("DOMMouseScroll", this.onMouseScroll, true);
     this.browser.addEventListener("keypress", this.onKeyPress, true);
     this.browser.addEventListener("mousemove", this.onMouseMove, true);
     this.browser.addEventListener("select", this.quit, false);
     this.browser.contentWindow.addEventListener("pagehide", this.onPageHide, true);
-  
+
     this.browser.contentWindow.focus();
-  
+
     let doc = this.browser.contentDocument;
     this.boxElem = doc.importNode(E("ehh-elementmarker").firstElementChild.cloneNode(true), true);
-  
+
     this.initHelpBox();
-  
+
     if (Prefs.showhelp)
       this.showMenu();
-  
+
     // Make sure to select some element immeditely (whichever is in the center of the browser window)
     let [wndWidth, wndHeight] = this.getWindowSize(doc.defaultView);
     this.isUserSelected = false;
     this.onMouseMove({clientX: wndWidth / 2, clientY: wndHeight / 2, screenX: -1, screenY: -1, target: null});
   },
 
   canSelect: function(browser)
   {
     if (!browser || !browser.contentWindow ||
         !(browser.contentDocument instanceof Ci.nsIDOMHTMLDocument))
     {
       return false;
     }
-  
+
     let location = browser.contentWindow.location;
     if (location.href == "about:blank")
       return false;
-  
+
     if (!Prefs.acceptlocalfiles &&
         location.hostname == "" &&
         location.protocol != "mailbox:" &&
         location.protocol != "imap:" &&
         location.protocol != "news:" &&
         location.protocol != "snews:")
     {
       return false;
     }
-  
+
     return true;
   },
 
   doCommand: function(command, event)
   {
     if (this[command](this.selectedElem))
     {
       this.showCommandLabel(this.commands[command + "_key"], this.commands[command + "_altkey"], this.commands[command + "_label"]);
@@ -105,65 +105,65 @@ let Aardvark = exports.Aardvark =
     if (event)
       event.preventDefault();
   },
 
   showCommandLabel: function(key, alternativeKey, label)
   {
     if (this.commandLabelTimer)
       this.commandLabelTimer.cancel();
-  
+
     E("ehh-commandlabel-key").textContent = key.toUpperCase();
     E("ehh-commandlabel-alternativeKey").textContent = alternativeKey.toUpperCase();
     E("ehh-commandlabel-label").setAttribute("value", label);
-  
+
     var commandLabel = E("ehh-commandlabel");
     commandLabel.showPopup(this.window.document.documentElement, this.mouseX, this.mouseY, "tooltip", "topleft", "topleft");
-  
+
     this.commandLabelTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     this.commandLabelTimer.initWithCallback(function()
     {
       commandLabel.hidePopup();
       Aardvark.commandLabelTimer = null;
     }, 400, Ci.nsITimer.TYPE_ONE_SHOT);
   },
 
   initHelpBox: function()
   {
     var helpBoxRows = E("ehh-helpbox-rows");
     if (helpBoxRows.firstElementChild)
       return;
-  
+
     // Help box hasn't been filled yet, need to do it now
     var stringService = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
     var strings = stringService.createBundle("chrome://elemhidehelper/locale/global.properties");
-  
+
     for (var i = 0; i < this.commands.length; i++)
     {
       var command = this.commands[i];
       var key = strings.GetStringFromName("command." + command + ".key");
       var alternativeKey = strings.GetStringFromName("command." + command + ".alternativeKey");
       var label = strings.GetStringFromName("command." + command + ".label");
       this.commands[command + "_key"] = key.toLowerCase();
       this.commands[command + "_altkey"] = alternativeKey.toLowerCase();
       this.commands[command + "_label"] = label;
-  
+
       var row = this.window.document.createElement("row");
       helpBoxRows.appendChild(row);
-  
+
       var element = this.window.document.createElement("description");
       element.textContent = key.toUpperCase();
       element.className = "key";
       row.appendChild(element);
-  
+
       var element = this.window.document.createElement("description");
       element.textContent = alternativeKey.toUpperCase();
       element.className = "key";
       row.appendChild(element);
-  
+
       element = this.window.document.createElement("description");
       element.setAttribute("value", label);
       element.className = "label";
       row.appendChild(element);
     }
   },
 
   hideTooltips: function()
@@ -176,89 +176,88 @@ let Aardvark = exports.Aardvark =
         tooltip.hidePopup();
     }
   },
 
   onMouseClick: function(event)
   {
     if (event.button != 0 || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey)
       return;
-  
+
     this.doCommand("select", event);
   },
 
   onMouseScroll: function(event)
   {
     if (!event.shiftKey || event.altKey || event.ctrlKey || event.metaKey)
       return;
-  
+
     if ("axis" in event && event.axis != event.VERTICAL_AXIS)
       return;
-  
-    for (let i = 0; i < Math.abs(event.detail); i++)
-      this.doCommand(event.detail > 0 ? "wider" : "narrower", event);
+
+    this.doCommand(event.detail > 0 ? "wider" : "narrower", event);
   },
 
   onKeyPress: function(event)
   {
     if (event.altKey || event.ctrlKey || event.metaKey)
       return;
-  
+
     var command = null;
     if (event.keyCode == event.DOM_VK_ESCAPE)
       command = "quit";
     else if (event.keyCode == event.DOM_VK_RETURN)
       command = "select";
     else if (event.charCode)
     {
       var key = String.fromCharCode(event.charCode).toLowerCase();
       var commands = this.commands;
       for (var i = 0; i < commands.length; i++)
         if (commands[commands[i] + "_key"] == key || commands[commands[i] + "_altkey"] == key)
           command = commands[i];
     }
-  
+
     if (command)
       this.doCommand(command, event);
   },
 
   onPageHide: function(event)
   {
     this.doCommand("quit", null);
   },
 
   onMouseMove: function(event)
   {
     this.mouseX = event.screenX;
     this.mouseY = event.screenY;
-  
+
     this.hideSelection();
-  
+
     let x = event.clientX;
     let y = event.clientY;
-  
+
     // We might have coordinates relative to a frame, recalculate relative to top window
     let node = event.target;
     while (node && node.ownerDocument && node.ownerDocument.defaultView && node.ownerDocument.defaultView.frameElement)
     {
       node = node.ownerDocument.defaultView.frameElement;
       let rect = node.getBoundingClientRect();
       x += rect.left;
       y += rect.top;
     }
-  
+
     let elem = this.browser.contentDocument.elementFromPoint(x, y);
     while (elem && "contentDocument" in elem && this.canSelect(elem))
     {
       let rect = elem.getBoundingClientRect();
       x -= rect.left;
       y -= rect.top;
       elem = elem.contentDocument.elementFromPoint(x, y);
     }
-  
+
     if (elem)
     {
       if (!this.lockedAnchor)
         this.setAnchorElement(elem);
       else
       {
         this.lockedAnchor = elem;
         this.selectElement(this.selectedElem);
@@ -278,32 +277,32 @@ let Aardvark = exports.Aardvark =
         this.selectElement(this.selectedElem);
       }
     }
   },
 
   setAnchorElement: function(anchor)
   {
     this.anchorElem = anchor;
-  
+
     let newSelection = anchor;
     if (this.isUserSelected)
     {
       // User chose an element via wider/narrower commands, keep the selection if
       // out new anchor is still a child of that element
       let e = newSelection;
       while (e && e != this.selectedElem)
         e = this.getParentElement(e);
-  
+
       if (e)
         newSelection = this.selectedElem;
       else
         this.isUserSelected = false;
     }
-  
+
     this.selectElement(newSelection);
   },
 
   appendDescription: function(node, value, className)
   {
     var descr = this.window.document.createElement("description");
     descr.setAttribute("value", value);
     if (className)
@@ -320,50 +319,50 @@ let Aardvark = exports.Aardvark =
     let tagName = elem.tagName.toLowerCase();
     let addition = "";
     if (elem.id != "")
       addition += ", id: " + elem.id;
     if (elem.className != "")
       addition += ", class: " + elem.className;
     if (elem.style.cssText != "")
       addition += ", style: " + elem.style.cssText;
-      
+
     return [tagName, addition];
   },
 
   selectElement: function(elem)
   {
     this.selectedElem = elem;
     this.prevSelectionUpdate = Date.now();
-  
+
     let border = this.boxElem.getElementsByClassName("ehh-border")[0];
     let label = this.boxElem.getElementsByClassName("ehh-label")[0];
     let labelTag = this.boxElem.getElementsByClassName("ehh-labelTag")[0];
     let labelAddition = this.boxElem.getElementsByClassName("ehh-labelAddition")[0];
 
     if (this.boxElem.parentNode)
       this.boxElem.parentNode.removeChild(this.boxElem);
-  
+
     let doc = this.browser.contentDocument;
     let [wndWidth, wndHeight] = this.getWindowSize(doc.defaultView);
 
     let pos = this.getElementPosition(elem);
     this.boxElem.style.left = Math.min(pos.left - 1, wndWidth - 2) + "px";
     this.boxElem.style.top = Math.min(pos.top - 1, wndHeight - 2) + "px";
     border.style.width = Math.max(pos.right - pos.left - 2, 0) + "px";
     border.style.height = Math.max(pos.bottom - pos.top - 2, 0) + "px";
-  
+
     [labelTag.textContent, labelAddition.textContent] = this.getElementLabel(elem);
-  
+
     // If there is not enough space to show the label move it up a little
     if (pos.bottom < wndHeight - 25)
       label.className = "ehh-label";
     else
       label.className = "ehh-label onTop";
-    
+
     doc.documentElement.appendChild(this.boxElem);
 
     this.paintNode = doc.defaultView;
     if (this.paintNode)
     {
       this.prevPos = pos;
       this.paintNode.addEventListener("MozAfterPaint", this.onAfterPaint, false);
     }
@@ -391,56 +390,56 @@ let Aardvark = exports.Aardvark =
     function intersectRect(rect, wnd)
     {
       let [wndWidth, wndHeight] = this.getWindowSize(wnd);
       rect.left = Math.max(rect.left, 0);
       rect.top = Math.max(rect.top, 0);
       rect.right = Math.min(rect.right, wndWidth);
       rect.bottom = Math.min(rect.bottom, wndHeight);
     }
-  
+
     let rect = element.getBoundingClientRect();
     let wnd = element.ownerDocument.defaultView;
-  
+
     rect = {left: rect.left, top: rect.top,
             right: rect.right, bottom: rect.bottom};
     while (true)
     {
       intersectRect.call(this, rect, wnd);
-  
+
       if (!wnd.frameElement)
         break;
-  
+
       // Recalculate coordinates to be relative to frame's parent window
       let frameElement = wnd.frameElement;
       wnd = frameElement.ownerDocument.defaultView;
-  
+
       let frameRect = frameElement.getBoundingClientRect();
       let frameStyle = wnd.getComputedStyle(frameElement, null);
       let relLeft = frameRect.left + parseFloat(frameStyle.borderLeftWidth) + parseFloat(frameStyle.paddingLeft);
       let relTop = frameRect.top + parseFloat(frameStyle.borderTopWidth) + parseFloat(frameStyle.paddingTop);
-  
+
       rect.left += relLeft;
       rect.right += relLeft;
       rect.top += relTop;
       rect.bottom += relTop;
     }
-  
+
     return rect;
   },
 
   getParentElement: function(elem)
   {
     let result = elem.parentNode;
     if (result && result.nodeType == Ci.nsIDOMElement.DOCUMENT_NODE && result.defaultView && result.defaultView.frameElement)
       result = result.defaultView.frameElement;
-  
+
     if (result && result.nodeType != Ci.nsIDOMElement.ELEMENT_NODE)
       return null;
-  
+
     return result;
   },
 
   /***************************
    * Commands implementation *
    ***************************/
 
   commands: [
@@ -454,21 +453,21 @@ let Aardvark = exports.Aardvark =
     "viewSourceWindow",
     "showMenu"
   ],
 
   wider: function(elem)
   {
     if (!elem)
       return false;
-  
+
     let newElem = this.getParentElement(elem);
     if (!newElem)
       return false;
-    
+
     this.isUserSelected = true;
     this.selectElement(newElem);
     return true;
   },
 
   narrower: function(elem)
   {
     if (elem)
@@ -477,61 +476,61 @@ let Aardvark = exports.Aardvark =
       // We need to select the element just before the selected one.
       let e = this.anchorElem;
       let newElem = null;
       while (e && e != elem)
       {
         newElem = e;
         e = this.getParentElement(e);
       }
-  
+
       if (!e || !newElem)
         return false;
-  
+
       this.isUserSelected = true;
       this.selectElement(newElem);
       return true;
     }
     return false;
   },
 
   lock: function(elem)
   {
     if (!elem)
       return false;
-  
+
     if (this.lockedAnchor)
     {
       this.setAnchorElement(this.lockedAnchor);
       this.lockedAnchor = null;
     }
     else
       this.lockedAnchor = this.anchorElem;
-  
+
     return true;
   },
-  
+
   quit: function()
   {
     if (!this.browser)
       return false;
-  
+
     if ("blinkTimer" in this)
       this.stopBlinking();
-  
+
     if (this.commandLabelTimer)
       this.commandLabelTimer.cancel();
     if (this.viewSourceTimer)
       this.viewSourceTimer.cancel();
     this.commandLabelTimer = null;
     this.viewSourceTimer = null;
-  
+
     this.hideSelection();
     this.hideTooltips();
-    
+
     this.browser.removeEventListener("click", this.onMouseClick, true);
     this.browser.removeEventListener("DOMMouseScroll", this.onMouseScroll, true);
     this.browser.removeEventListener("keypress", this.onKeyPress, true);
     this.browser.removeEventListener("mousemove", this.onMouseMove, true);
     this.browser.removeEventListener("select", this.quit, false);
     this.browser.contentWindow.removeEventListener("pagehide", this.onPageHide, true);
 
     this.anchorElem = null;
@@ -544,189 +543,189 @@ let Aardvark = exports.Aardvark =
     E = function(id) null;
     return false;
   },
 
   select: function(elem)
   {
     if (!elem)
       return false;
-  
+
     this.window.openDialog("chrome://elemhidehelper/content/composer.xul", "_blank",
                            "chrome,centerscreen,resizable,dialog=no", elem);
     this.quit();
     return false;
   },
 
   blinkElement: function(elem)
   {
     if (!elem)
       return false;
-  
+
     if ("blinkTimer" in this)
       this.stopBlinking();
-  
+
     let counter = 0;
     this.blinkElem = elem;
     this.blinkOrigValue = elem.style.visibility;
     this.blinkTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     this.blinkTimer.initWithCallback(function()
     {
       counter++;
       elem.style.visibility = (counter % 2 == 0 ? "visible" : "hidden");
       if (counter == 6)
         Aardvark.stopBlinking();
     }, 250, Ci.nsITimer.TYPE_REPEATING_SLACK);
-  
+
     return true;
   },
 
   stopBlinking: function()
   {
     this.blinkTimer.cancel();
     this.blinkElem.style.visibility = this.blinkOrigValue;
-  
+
     delete this.blinkElem;
     delete this.blinkOrigValue;
     delete this.blinkTimer;
   },
 
   viewSource: function(elem)
   {
     if (!elem)
       return false;
-  
+
     var sourceBox = E("ehh-viewsource");
     if (sourceBox.state == "open" && this.commentElem == elem)
     {
       sourceBox.hidePopup();
       return true;
     }
     sourceBox.hidePopup();
-  
+
     while (sourceBox.firstElementChild)
       sourceBox.removeChild(sourceBox.firstElementChild);
     this.getOuterHtmlFormatted(elem, sourceBox);
     this.commentElem = elem;
-  
+
     let anchor = this.window.document.documentElement;
     let x = this.mouseX;
     let y = this.mouseY;
     this.viewSourceTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     this.viewSourceTimer.initWithCallback(function()
     {
       sourceBox.showPopup(anchor, x, y, "tooltip", "topleft", "topleft");
       Aardvark.viewSourceTimer = null;
     }, 500, Ci.nsITimer.TYPE_ONE_SHOT);
     return true;
   },
 
   viewSourceWindow: function(elem)
   {
     if (!elem)
       return false;
-  
+
     var range = elem.ownerDocument.createRange();
     range.selectNodeContents(elem);
     var selection = {rangeCount: 1, getRangeAt: function() {return range}};
-  
+
     this.window.openDialog("chrome://global/content/viewPartialSource.xul", "_blank", "scrollbars,resizable,chrome,dialog=no",
                            null, null, selection, "selection");
     return true;
   },
 
   getOuterHtmlFormatted: function(node, container)
   {
     var type = null;
     switch (node.nodeType)
     {
       case node.ELEMENT_NODE:
         var box = this.window.document.createElement("vbox");
         box.className = "elementBox";
-  
+
         var startTag = this.window.document.createElement("hbox");
         startTag.className = "elementStartTag";
         if (!node.firstElementChild)
           startTag.className += " elementEndTag";
-  
+
         this.appendDescription(startTag, "<", null);
         this.appendDescription(startTag, node.tagName, "tagName");
-  
+
         for (var i = 0; i < node.attributes.length; i++)
         {
           var attr = node.attributes[i];
           this.appendDescription(startTag, attr.name, "attrName");
           if (attr.value != "")
           {
             this.appendDescription(startTag, "=", null);
             this.appendDescription(startTag, '"' + attr.value.replace(/"/, "&quot;") + '"', "attrValue");
           }
         }
-  
+
         this.appendDescription(startTag, node.firstElementChild ? ">" : " />", null);
         box.appendChild(startTag);
-  
+
         if (node.firstElementChild)
         {
           for (var child = node.firstElementChild; child; child = child.nextElementSibling)
             this.getOuterHtmlFormatted(child, box);
-  
+
           var endTag = this.window.document.createElement("hbox");
           endTag.className = "elementEndTag";
           this.appendDescription(endTag, "<", null);
           this.appendDescription(endTag, "/" + node.tagName, "tagName");
           this.appendDescription(endTag, ">", null);
           box.appendChild(endTag);
         }
         container.appendChild(box);
         return;
-  
+
       case node.TEXT_NODE:
         type = "text";
         break;
       case node.CDATA_SECTION_NODE:
         type = "cdata";
         break;
       case node.COMMENT_NODE:
         type = "comment";
         break;
       default:
         return;
     }
-  
+
     var text = node.nodeValue.replace(/\r/g, '').replace(/^\s+/, '').replace(/\s+$/, '');
     if (text == "")
       return;
-  
+
     if (type != "cdata")
     {
       text = text.replace(/&/g, "&amp;")
                  .replace(/</g, "&lt;")
                  .replace(/>/g, "&gt;");
     }
     text = text.replace(/\t/g, "  ");
     if (type == "cdata")
       text = "<![CDATA[" + text + "]]>";
     else if (type == "comment")
       text = "<!--" + text + "-->";
-  
+
     var lines = text.split("\n");
     for (var i = 0; i < lines.length; i++)
       this.appendDescription(container, lines[i].replace(/^\s+/, '').replace(/\s+$/, ''), type);
   },
 
   showMenu: function()
   {
     var helpBox = E("ehh-helpbox");
     if (helpBox.state == "open")
     {
       helpBox.hidePopup();
       return true;
     }
-  
+
     // Show help box
     helpBox.showPopup(this.browser, -1, -1, "tooltip", "topleft", "topleft");
     return true;
   }
 }
 
 // Makes sure event handlers like Aardvark.onKeyPress always have the correct
 // this pointer set.
