diff options
| -rw-r--r-- | README.markdown | 5 | ||||
| -rw-r--r-- | background_page.html | 10 | ||||
| -rw-r--r-- | commands.js | 2 | ||||
| -rw-r--r-- | linkHints.js | 6 | ||||
| -rw-r--r-- | test_harnesses/form.html | 2 | ||||
| -rw-r--r-- | test_harnesses/visibility_test.html | 175 | ||||
| -rw-r--r-- | vimiumFrontend.js | 24 | 
7 files changed, 173 insertions, 51 deletions
diff --git a/README.markdown b/README.markdown index ba16e643..04e7375d 100644 --- a/README.markdown +++ b/README.markdown @@ -84,6 +84,11 @@ When you're done, send us a pull request on Github. Feel free to include a chang  Release Notes  ------------- +1.22 + +-  Some sites are now excluded by default. +-  Bugfixes. +  1.21 (10/24/2010)  -  Critical bugfix for an excluded URLs regression due to frame support. diff --git a/background_page.html b/background_page.html index 8f0cad23..10de4aca 100644 --- a/background_page.html +++ b/background_page.html @@ -20,7 +20,7 @@    // Keys are either literal characters, or "named" - for example <a-b> (alt+b), <left> (the left arrow) or <f12>    // This regular expression captures two groups, the first is a named key, the second is the remainder of the string. -  var namedKeyRegex = /^(<[amc-].|(?:[amc]-)?[a-z0-9]{2,5}>)(.*)$/; +  var namedKeyRegex = /^(<(?:[amc]-.|(?:[amc]-)?[a-z0-9]{2,5})>)(.*)$/;    var defaultSettings = {      scrollStepSize: 60, @@ -29,7 +29,9 @@      narrowLinkHints: false,      userDefinedLinkHintCss:        ".vimiumHintMarker {\n\n}\n" + -      ".vimiumHintMarker > .matchingCharacter {\n\n}" +      ".vimiumHintMarker > .matchingCharacter {\n\n}", +    excludedUrls: "http*://mail.google.com/*\n" + +                  "http*://www.google.com/reader/*\n"    };    // This is the base internal link hints CSS. It's combined with the userDefinedLinkHintCss before @@ -137,7 +139,7 @@     */    function isEnabledForUrl(request) {      // excludedUrls are stored as a series of URL expressions separated by newlines. -    var excludedUrls = (localStorage["excludedUrls"] || "").split("\n"); +    var excludedUrls = (localStorage["excludedUrls"] || defaultSettings.excludedUrls).split("\n");      var isEnabled = true;      for (var i = 0; i < excludedUrls.length; i++) {        // The user can add "*" to the URL which means ".*" @@ -551,7 +553,7 @@        // The second key might be a valid command by its self.        if (keyToCommandRegistry[splitKey.second]) -        newKeyQueue = checkKeyQueue(splitKey.second); +        newKeyQueue = checkKeyQueue(splitKey.second, tabId, frameId);        else          newKeyQueue = (validFirstKeys[splitKey.second] ? splitKey.second : "");      } else { diff --git a/commands.js b/commands.js index 1518f113..e4cef0c2 100644 --- a/commands.js +++ b/commands.js @@ -170,7 +170,7 @@ addCommand('goBack',              'Go back in history');  addCommand('goForward',           'Go forward in history');  // Navigating the URL hierarchy -addCommand('goUp',                'Go up the URL hierarchy'); +addCommand('goUp',                'Go up the URL hierarchy', false, true);  // Manipulating tabs:  addCommand('nextTab',             'Go one tab right',  true); diff --git a/linkHints.js b/linkHints.js index 8aed5fff..1367a827 100644 --- a/linkHints.js +++ b/linkHints.js @@ -30,11 +30,11 @@ var linkHintsPrototype = {     * The final expression will be something like "//button | //xhtml:button | ..."     */    clickableElementsXPath: (function() { -    var clickableElements = ["a", "textarea", "button", "select", "input[not(@type='hidden')]"]; +    var clickableElements = ["a", "textarea", "button", "select", "input[not(@type='hidden')]", +                             "*[@onclick or @tabindex or @role='link' or @role='button']"];      var xpath = [];      for (var i in clickableElements)        xpath.push("//" + clickableElements[i], "//xhtml:" + clickableElements[i]); -    xpath.push("//*[@onclick]");      return xpath.join(" | ")    })(), @@ -90,7 +90,7 @@ var linkHintsPrototype = {      this.hintMarkerContainingDiv.className = "internalVimiumHintMarker";      for (var i = 0; i < this.hintMarkers.length; i++)        this.hintMarkerContainingDiv.appendChild(this.hintMarkers[i]); -    document.body.appendChild(this.hintMarkerContainingDiv); +    document.documentElement.appendChild(this.hintMarkerContainingDiv);    },    hintStringGenerator: function() {}, diff --git a/test_harnesses/form.html b/test_harnesses/form.html index 740edb46..d7104ac2 100644 --- a/test_harnesses/form.html +++ b/test_harnesses/form.html @@ -10,6 +10,8 @@      <p>        Text: <input type="text" name="text" value="" />        Text 2: <input type="text" name="text" value="" /> +      Email: <input type="email" name="text" value="" /> +      No Type: <input name="text" value="" />      </p>      <p>        Search: <input type="search" /> diff --git a/test_harnesses/visibility_test.html b/test_harnesses/visibility_test.html index 5fa4d728..7cfab412 100644 --- a/test_harnesses/visibility_test.html +++ b/test_harnesses/visibility_test.html @@ -7,65 +7,166 @@  <head>    <title>Visibility test</title>    <style type="text/css" media="screen"> +    * { +      font-family: sans; +      font-size: 14px; +    }      span {        display:block;        width:30px;        height:20px;        background-color:blue;      } +    table { +      border-collapse: separate; +    } +    tr, td { +      border: 2px solid black; +      margin: 0; +      padding: 2px; +    }    </style>    <script type="text/javascript" charset="utf-8"> +    window.addEventListener("load", displayTests, false);      window.addEventListener("load", checkDivsForVisibility, false); -     -    function checkDivsForVisibility() { -      var divs = document.getElementsByTagName("span"); -      for (var i = 0; i < divs.length; i++) { -        console.log(divs[i].id, isVisible(divs[i])); + +    var visibilityTests = [ +      { +        'description': 'BoundingClientRect is inside viewport', +        'test': function(element) { +           var rect = element.getBoundingClientRect(); +           if (!rect || rect.top > window.innerHeight || rect.bottom < 0 || rect.left > window.innerWidth || rect.right < 0) +               return false; +           return true; +        }, +      }, +      { +        'description': 'BoundingClientRect has nonzero dimensions', +        'test': function(element) { +           var rect = element.getBoundingClientRect(); +           if (!rect || rect.width == 0 || rect.height == 0) +               return false; +           return true; +        }, +      }, +      { +        'description': 'Is visible and displayed', +        'test': function(element) { +          var computedStyle = window.getComputedStyle(element, null); +          if (computedStyle.getPropertyValue('visibility') != 'visible' ||  +              computedStyle.getPropertyValue('display') == 'none') +              return false; +           return true; +        }, +      }, +      { +        'description': 'Has ClientRect', +        'test': function(element) { +          var clientRect = element.getClientRects()[0]; +          if (!clientRect) +            return false; +           return true; +        }, +      }, +      { +        'description': 'ClientRect has nonzero dimensions', +        'test': function(element) { +          var clientRect = element.getClientRects()[0]; +          if (!clientRect || clientRect.width == 0 || clientRect.height == 0) +            return false; +           return true; +        }, +      }, +    ]; + +    function displayTests() { +      for (var i = 0; i < visibilityTests.length; i++) { +        document.getElementById("testDescriptions").innerHTML += +          "<b>Test " + (i+1) + ": </b>" + visibilityTests[i].description + "<br/>";        }      } -    /* -     * Determine whether elements are visible. -     * Inspired by Vimperator. -     */ -    function isVisible(element) { -      // eliminate offscreen elements (case 4) -      var rect = element.getBoundingClientRect(); -      if (!rect || rect.top > window.innerHeight || rect.bottom < 0 || rect.left > window.innerWidth || rect.right < 0) -          return false; -      // this catches cases 2, 3, & 5 -      var computedStyle = window.getComputedStyle(element, null); -      if (computedStyle.getPropertyValue('visibility') != 'visible' ||  -          computedStyle.getPropertyValue('display') == 'none') -          return false; +    function makeBoolTd(bool) { +      var td = document.createElement("td"); +      td.style.width = '15px'; +      td.style.background = bool ? '#0f0' : "#f00"; +      return td; +    } -      // this catches cases 3 & 6 -      var clientRect = element.getClientRects()[0]; -      if (!clientRect) -        return false; +    function makeTag(tag, text) { +      var td = document.createElement(tag); +      td.innerHTML = text; +      return td; +    } +     +    function checkDivsForVisibility() { +      var table = document.getElementById("resultsDisplay"); +      var tr = document.getElementsByTagName("tr")[0]; +      for (var i = 0; i < visibilityTests.length; i++) +        tr.appendChild(makeTag("th", i+1)); +      tr.appendChild(makeTag("th", "Expected Result")); +      tr.appendChild(makeTag("th", "Comments")); + +      var divs = document.getElementsByClassName("testElement"); +      for (var i = 0; i < divs.length; i++) { +        var tr = document.createElement("tr"); +        table.appendChild(tr); +        table.appendChild(makeTag("td", i+1)); +        var netResult = true; +        for (var j = 0; j < visibilityTests.length; j++) { +          result = visibilityTests[j].test(divs[i]); +          table.appendChild(makeBoolTd(result)); +          netResult = netResult && result; +        } +        var expectedResult = divs[i].getAttribute('data-expectedresult') == 1; +        var td = makeTag("td", expectedResult); +        td.style.background = netResult === expectedResult ? '#fff' : '#ccf'; +        table.appendChild(td); +        table.appendChild(makeTag("td", divs[i].getAttribute('data-comment'))); -      return true; +        // hide the test cases once we're done with them +        divs[i].style.visibility = 'hidden'; +      }      }    </script>  </head>  <body> -  <span id="div1true"></span> -   -  <span id="div2false" style="visibility:hidden"></span> +  <div id='testDescriptions' style='margin: 6px 0 6px 0;'></div> +  <table id='resultsDisplay'> +    <tr> +      <th>Node/Test</th> +    </tr> +  </table> + +  <div id='testContainer' style='position: absolute; top: 0; left:0'> +    <span class='testElement' data-expectedresult=1 data-comment="default">test</span> +     +    <span class='testElement' data-expectedresult=0 style="visibility:hidden" data-comment="visibility: hidden">test</span> -  <span id="div3false" style="display:none"></span> +    <div style="visibility:hidden"> +      <span class='testElement' data-expectedresult=0 data-comment="nested in an element that has visibility: hidden">test</span> +    </div> -  <span id="div4false" style="position:absolute;top:2000px"></span> +    <span class='testElement' data-expectedresult=0 style="display:none" data-comment="display: none">test</span> -  <div style="visibility:hidden"> -    <span id="div5false"></span> -  </div> -  <div style="display:none"> -    <span id="div6false"></span> -  </div> -  <div style="opacity:0"> -    <span id="div7true" style="opacity:0"></span> +    <div style="display:none"> +      <span class='testElement' data-expectedresult=0 data-comment="nested in an element that has display: none">test</span> +    </div> + +    <span class='testElement' data-expectedresult=0 style="position:absolute;top:2000px" data-comment="outside viewport">test</span> + +    <div style="opacity:0"> +      <span class='testElement' data-expectedresult=1 data-comment="nested in an element that has opacity:0">test</span> +    </div> +    <div class='testElement' data-expectedresult=1 data-comment="Contains only a floated span. We must recurse into the div to find it."> +      <span style="float: left">test</span> +    </div> +    <svg>  +      <a class='testElement' data-expectedresult=1 xlink:href='http://www.example.com/' data-comment="This link is contained within an SVG."> +        <text x='0' y='68'  >test</text> +      </a>  +    </svg>    </div>  </html> diff --git a/vimiumFrontend.js b/vimiumFrontend.js index dac778cb..7289c135 100644 --- a/vimiumFrontend.js +++ b/vimiumFrontend.js @@ -26,6 +26,17 @@ var linkHintCss;  // TODO(philc): This should be pulled from the extension's storage when the page loads.  var currentZoomLevel = 100; +// The types in <input type="..."> that we consider for focusInput command. Right now this is recalculated in +// each content script. Alternatively we could calculate it once in the background page and use a request to +// fetch it each time. +// +// Should we include the HTML5 date pickers here? +var textInputTypes = ["text", "search", "email", "url", "number"]; +// The corresponding XPath for such elements. +var textInputXPath = '//input[' + +                     textInputTypes.map(function (type) { return '@type="' + type + '"'; }).join(" or ") + +                     ' or not(@type)]'; +  /*   * Give this frame a unique id.   */ @@ -245,8 +256,8 @@ function scrollLeft() { window.scrollBy(-1 * settings["scrollStepSize"], 0); }  function scrollRight() { window.scrollBy(settings["scrollStepSize"], 0); }  function focusInput(count) { -  var xpath = '//input[@type="text" or @type="search"]'; -  var results = document.evaluate(xpath, document.documentElement, null, +  var results = document.evaluate(textInputXPath, +                                  document.documentElement, null,                                    XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);    var lastInputBox; @@ -268,7 +279,7 @@ function reload() { window.location.reload(); }  function goBack() { history.back(); }  function goForward() { history.forward(); } -function goUp() { +function goUp(count) {    var url = window.location.href;    if (url[url.length-1] == '/')      url = url.substring(0, url.length - 1); @@ -276,7 +287,7 @@ function goUp() {    var urlsplit = url.split('/');    // make sure we haven't hit the base domain yet    if (urlsplit.length > 3) { -    delete urlsplit[urlsplit.length-1]; +    urlsplit = urlsplit.slice(0, Math.max(3, urlsplit.length - count));      window.location.href = urlsplit.join('/');    }  } @@ -638,6 +649,7 @@ HUD = {        "bottom: 0px;" +        "color: black;" +        "height: 13px;" + +      "width: auto;" +        "max-width: 400px;" +        "min-width: 150px;" +        "text-align: left;" + @@ -800,8 +812,8 @@ Tween = {  function addCssToPage(css) {    var head = document.getElementsByTagName("head")[0];    if (!head) { -    console.log("Warning: unable to add CSS to the page."); -    return; +    head = document.createElement("head"); +    document.documentElement.appendChild(head);    }    var style = document.createElement("style");    style.type = "text/css";  | 
