diff options
| author | jez | 2011-01-03 20:24:55 +0800 |
|---|---|---|
| committer | jez | 2011-01-04 16:16:47 +0800 |
| commit | a2e3ac7910630ac1233d91dec58e1f6f5f63f6b9 (patch) | |
| tree | 2ec13ef3699055730adbafa3fef5e6ab550f978c | |
| parent | ac0ffe13d9f517da8d35d386c9c75f2f25b20039 (diff) | |
| download | vimium-a2e3ac7910630ac1233d91dec58e1f6f5f63f6b9.tar.bz2 | |
Add filtering for input and image elements, together with tests.
| -rw-r--r-- | linkHints.js | 71 | ||||
| -rw-r--r-- | test_harnesses/automated.html | 39 |
2 files changed, 92 insertions, 18 deletions
diff --git a/linkHints.js b/linkHints.js index ca5d29dd..53ad08b7 100644 --- a/linkHints.js +++ b/linkHints.js @@ -111,9 +111,9 @@ var linkHintsBase = { /* * Sets the data attributes of the marker. Does not need to handle styling - * and positioning. MUST set the hintString property. + * and positioning. MUST set the hintString and innerHTML properties. */ - setMarkerAttributes: function(linkHintNumber) {}, + setMarkerAttributes: function(marker, linkHintNumber) {}, /* * A hook for any necessary initialization for setMarkerAttributes. Takes an @@ -310,8 +310,8 @@ var linkHintsBase = { createMarkerFor: function(link, linkHintNumber) { var marker = document.createElement("div"); marker.className = "internalVimiumHintMarker vimiumHintMarker"; - this.setMarkerAttributes(marker, link, linkHintNumber); - marker.innerHTML = this.spanWrap(marker.getAttribute("hintString")); + marker.clickableItem = link.element; + this.setMarkerAttributes(marker, linkHintNumber); // Note: this call will be expensive if we modify the DOM in between calls. var clientRect = link.rect; @@ -321,7 +321,6 @@ var linkHintsBase = { marker.style.left = clientRect.left + window.scrollX / zoomFactor + "px"; marker.style.top = clientRect.top + window.scrollY / zoomFactor + "px"; - marker.clickableItem = link.element; return marker; }, @@ -356,8 +355,9 @@ function initializeLinkHints() { visibleElements.length, settings.get('linkHintCharacters').length)); }, - setMarkerAttributes: function(marker, link, linkHintNumber) { + setMarkerAttributes: function(marker, linkHintNumber) { var hintString = this.numberToHintString(linkHintNumber, this.digitsNeeded); + marker.innerHTML = this.spanWrap(hintString); marker.setAttribute("hintString", hintString); return marker; }, @@ -415,14 +415,57 @@ function initializeLinkHints() { linkTextKeystrokeQueue: [], - setMarkerAttributes: function(marker, link, linkHintNumber) { + labelMap: {}, + + /* + * Generate a map of input element => label + */ + initSetMarkerAttributes: function() { + var labels = document.querySelectorAll("label"); + for (var i = 0; i < labels.length; i++) { + var forElement = labels[i].getAttribute("for"); + if (forElement) { + var labelText = labels[i].textContent.trim(); + // remove trailing : commonly found in labels + if (labelText[labelText.length-1] == ":") + labelText = labelText.substr(0, labelText.length-1); + this.labelMap[forElement] = labelText; + } + } + }, + + setMarkerAttributes: function(marker, linkHintNumber) { var hintString = (linkHintNumber + 1).toString(); - var linkText = link.element.innerHTML.toLowerCase(); - if (linkText == undefined) - linkText = ""; + var linkText = ""; + var showLinkText = false; + var element = marker.clickableItem; + // toLowerCase is necessary as html documents return 'IMG' + // and xhtml documents return 'img' + var nodeName = element.nodeName.toLowerCase(); + + if (nodeName == "input") { + if (this.labelMap[element.id]) { + linkText = this.labelMap[element.id]; + showLinkText = true; + } else if (element.type != "password") { + linkText = element.value; + } + // check if there is an image embedded in the <a> tag + } else if (nodeName == "a" && !element.textContent.trim() + && element.firstElementChild + && element.firstElementChild.nodeName.toLowerCase() == "img") { + showLinkText = true; + linkText = element.firstElementChild.alt || element.firstElementChild.title; + } + + if (!linkText) { + linkText = element.textContent || element.innerHTML; + } + linkText = linkText.trim().toLowerCase(); marker.setAttribute("hintString", hintString); + marker.innerHTML = this.spanWrap(hintString + + (showLinkText ? ": " + linkText : "")); marker.setAttribute("linkText", linkText); - return marker; }, normalKeyDownHandler: function(event) { @@ -495,9 +538,8 @@ function initializeLinkHints() { } else { if (linkMarker.style.display == "none") linkMarker.style.display = ""; - var newHintText = (linksMatched.length+1).toString(); - linkMarker.innerHTML = this.spanWrap(newHintText); - linkMarker.setAttribute("hintString", newHintText); + + this.setMarkerAttributes(linkMarker, linksMatched.length); linkMarker.setAttribute("filtered", "false"); linksMatched.push(linkMarker); } @@ -507,6 +549,7 @@ function initializeLinkHints() { deactivateMode: function() { this.linkTextKeystrokeQueue = []; + this.labelMap = {}; this._super('deactivateMode')(); } diff --git a/test_harnesses/automated.html b/test_harnesses/automated.html index b11bebc1..d59a31d1 100644 --- a/test_harnesses/automated.html +++ b/test_harnesses/automated.html @@ -142,7 +142,15 @@ "<a id='1' style='position: absolute; top: 17px; left: 19px;'>test</a>" + "<a id='2'>tress</a>" + "<a id='3'>trait</a>" + - "<a><img alt='alt text'/></a>"; + "<a>track<img alt='alt text'/></a>" + + "<a><img alt='alt text'/></a>" + + "<a><img alt='alt text' title='some title'/></a>" + + "<a><img title='some title'/></a>" + + "<input type='text' value='some value'/>" + + "<input type='password' value='some value'/>" + + "<textarea>some text</textarea>" + + "<label for='test-input'/>a label</label><input type='text' id='test-input' value='some value'/>" + + "<label for='test-input-2'/>a label: </label><input type='text' id='test-input-2' value='some value'/>"; document.getElementById("test-div").innerHTML = testContent; settings.values.filterLinkHints = "true"; initializeLinkHints(); @@ -152,10 +160,10 @@ document.getElementById("test-div").innerHTML = ""; linkHints.deactivateMode(); }), - should("label the hints correctly", function() { - for (var i = 0; i < 3; i++) + should("label the plain text hints", function() { + for (var i = 0; i < 4; i++) assert.equal((i + 1).toString(), - linkHints.hintMarkers[i].getAttribute("hintString")); + linkHints.hintMarkers[i].textContent.toLowerCase()); }), should("narrow the hints", function() { linkHints.onKeyDownInMode(mockKeyboardEvent("T")); @@ -166,6 +174,29 @@ linkHints.hintMarkers[1].getAttribute("hintString")); assert.equal("", linkHints.hintMarkers[1].style.display); + linkHints.onKeyDownInMode(mockKeyboardEvent("A")); + assert.equal("2", + linkHints.hintMarkers[3].getAttribute("hintString")); + }), + should("label the images", function() { + assert.equal("5: alt text", + linkHints.hintMarkers[4].textContent.toLowerCase()); + assert.equal("6: alt text", + linkHints.hintMarkers[5].textContent.toLowerCase()); + assert.equal("7: some title", + linkHints.hintMarkers[6].textContent.toLowerCase()); + }), + should("label the input elements", function() { + assert.equal("8", + linkHints.hintMarkers[7].textContent.toLowerCase()); + assert.equal("9", + linkHints.hintMarkers[8].textContent.toLowerCase()); + assert.equal("10", + linkHints.hintMarkers[9].textContent.toLowerCase()); + assert.equal("11: a label", + linkHints.hintMarkers[10].textContent.toLowerCase()); + assert.equal("12: a label", + linkHints.hintMarkers[11].textContent.toLowerCase()); }) ); |
