aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjez2011-01-03 20:24:55 +0800
committerjez2011-01-04 16:16:47 +0800
commita2e3ac7910630ac1233d91dec58e1f6f5f63f6b9 (patch)
tree2ec13ef3699055730adbafa3fef5e6ab550f978c
parentac0ffe13d9f517da8d35d386c9c75f2f25b20039 (diff)
downloadvimium-a2e3ac7910630ac1233d91dec58e1f6f5f63f6b9.tar.bz2
Add filtering for input and image elements, together with tests.
-rw-r--r--linkHints.js71
-rw-r--r--test_harnesses/automated.html39
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());
})
);