aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormrmr19932014-12-17 12:27:40 +0000
committermrmr19932014-12-17 12:27:40 +0000
commit5f9290693ab0f35c46cea6cea0a9f5c06b4ee0ad (patch)
tree06aa6fb072fa39cd5bc1ca5c050389072d873355
parent28c275ae4128f0a2907c7ad3d27cedc81efe129a (diff)
downloadvimium-5f9290693ab0f35c46cea6cea0a9f5c06b4ee0ad.tar.bz2
Combine rectangle calculation and clickable element detection
-rw-r--r--content_scripts/link_hints.coffee51
-rw-r--r--lib/dom_utils.coffee28
2 files changed, 44 insertions, 35 deletions
diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee
index 18e9741d..dd359a70 100644
--- a/content_scripts/link_hints.coffee
+++ b/content_scripts/link_hints.coffee
@@ -131,19 +131,23 @@ LinkHints =
#
getVisibleClickableElements: ->
elements = Array::slice.call(document.documentElement.getElementsByTagName "*")
- resultSet = []
+ visibleElements = []
for element in elements
tagName = element.tagName.toLowerCase()
+ isClickable = false
# Insert area elements that provide click functionality to an img.
if tagName == "img"
mapName = element.getAttribute "usemap"
if mapName
+ imgClientRects = element.getClientRects()
mapName = mapName.replace(/^#/, "").replace("\"", "\\\"")
map = document.querySelector "map[name=\"#{mapName}\"]"
- areas = if map then Array::slice.call(map.getElementsByTagName "area") else []
- resultSet = resultSet.concat areas
+ if map and imgClientRects.length > 0
+ areas = map.getElementsByTagName "area"
+ areaRects = DomUtils.getClientRectsForAreas imgClientRects[0], areas
+ visibleElements = visibleElements.concat areaRects
# Check for attributes that make an element clickable regardless of its tagName.
if (element.hasAttribute "onclick" or
@@ -151,46 +155,23 @@ LinkHints =
element.getAttribute "role" in ["button", "link"] or
element.getAttribute("class")?.toLowerCase().indexOf("button") >= 0 or
element.getAttribute("contentEditable")?.toLowerCase() in ["", "contentEditable", "true"])
- resultSet.push element
- continue
+ isClickable = true
+ # Check for tagNames which are natively clickable.
switch tagName
when "a"
- resultSet.push element
+ isClickable = true
when "textarea", "input"
unless (tagName == "input" and element.getAttribute("type")?.toLowerCase() == "hidden") or
element.disabled or (element.readOnly and DomUtils.isSelectable element)
- resultSet.push element
+ isClickable = true
when "button", "select"
- resultSet.push element unless element.disabled
-
- visibleElements = []
+ isClickable = not element.disabled
- # Find all visible clickable elements.
- for element in resultSet
- clientRect = DomUtils.getVisibleClientRect(element, clientRect)
- if (clientRect != null)
- visibleElements.push({element: element, rect: clientRect})
-
- if (element.localName == "area")
- map = element.parentElement
- continue unless map
- img = document.querySelector("img[usemap='#" + map.getAttribute("name") + "']")
- continue unless img
- imgClientRects = img.getClientRects()
- continue if (imgClientRects.length == 0)
- c = element.coords.split(/,/)
- coords = [parseInt(c[0], 10), parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10)]
- rect = {
- top: imgClientRects[0].top + coords[1],
- left: imgClientRects[0].left + coords[0],
- right: imgClientRects[0].left + coords[2],
- bottom: imgClientRects[0].top + coords[3],
- width: coords[2] - coords[0],
- height: coords[3] - coords[1]
- }
-
- visibleElements.push({element: element, rect: rect})
+ continue unless isClickable # If the element isn't clickable, do nothing.
+ clientRect = DomUtils.getVisibleClientRect element
+ if clientRect != null
+ visibleElements.push {element: element, rect: clientRect}
visibleElements
diff --git a/lib/dom_utils.coffee b/lib/dom_utils.coffee
index a0ac0bd3..3d7e805f 100644
--- a/lib/dom_utils.coffee
+++ b/lib/dom_utils.coffee
@@ -90,6 +90,34 @@ DomUtils =
return childClientRect
null
+ getClientRectsForAreas: (imgClientRect, areas) ->
+ rects = []
+ for area in areas
+ coords = area.coords.split(",").map((coord) -> parseInt(coord, 10))
+ shape = area.shape.toLowerCase()
+ if shape == "rect"
+ [x1, y1, x2, y2] = coords
+ else if shape == "circle"
+ [x, y, r] = coords
+ x1 = x - r
+ x2 = x + r
+ y1 = y - r
+ y2 = y + r
+ else # For polygons and unknown shapes, don't return a rectangle.
+ # TODO(mrmr1993): revisit this.
+ continue
+
+ rect =
+ top: imgClientRect.top + y1
+ left: imgClientRect.left + x1
+ right: imgClientRect.left + x2
+ bottom: imgClientRect.top + y2
+ width: x2 - x1
+ height: y2 - y1
+
+ rects.push {element: area, rect: rect} unless isNaN rect.top
+ rects
+
#
# Selectable means that we should use the simulateSelect method to activate the element instead of a click.
#