diff --git a/content_scripts/inject_script.coffee b/content_scripts/inject_script.coffee
index 8da49d39e..db9a8f1d6 100644
--- a/content_scripts/inject_script.coffee
+++ b/content_scripts/inject_script.coffee
@@ -8,7 +8,7 @@ fetchFileContents = (extensionFileName) ->
eventName = "reset"
listenerName = "on#{eventName}"
-injectScripts = ["pages/addEventListener_hook.js"]
+injectScripts = ["pages/jQuery_delegatedEvents_hook.js", "pages/addEventListener_hook.js"]
# Store the original value of the event listener if one exists, or null otherwise.
oldValue =
diff --git a/content_scripts/link_hints.coffee b/content_scripts/link_hints.coffee
index 6fde8bfb0..8b63bce5c 100644
--- a/content_scripts/link_hints.coffee
+++ b/content_scripts/link_hints.coffee
@@ -124,6 +124,22 @@ LinkHints =
marker
+ #
+ # Find children elements that have delegated onclick event listener assigned,
+ # and mark them with `vimium-has-delegated-onclick-listener` attribute.
+ # This will make sure those elements are discovered during `getVisibleClickableElements` call.
+ #
+ markChildrenThatHaveDelegatedOnClickListener: (element) ->
+ return unless element.hasAttribute "vimium-jquery-delegated-events-selectors"
+
+ selectorsStr = element.getAttribute "vimium-jquery-delegated-events-selectors"
+ selectors = selectorsStr.split("|").filter (x) -> !!x
+
+ for selector in selectors
+ for child in element.querySelectorAll(selector)
+ unless child.hasAttribute "vimium-has-delegated-onclick-listener"
+ child.setAttribute "vimium-has-delegated-onclick-listener", ""
+
#
# Determine whether the element is visible and clickable. If it is, find the rect bounding the element in
# the viewport. There may be more than one part of element which is clickable (for example, if it's an
@@ -156,9 +172,13 @@ LinkHints =
if (element.hasAttribute("onclick") or
element.getAttribute("role")?.toLowerCase() in ["button", "link"] or
element.getAttribute("contentEditable")?.toLowerCase() in ["", "contentEditable", "true"] or
- element.hasAttribute("vimium-has-onclick-listener"))
+ element.hasAttribute("vimium-has-onclick-listener") or
+ element.hasAttribute("vimium-has-delegated-onclick-listener"))
isClickable = true
+ # Dispose the attribute so next time it is not included, in case listener has been removed
+ element.removeAttribute "vimium-has-delegated-onclick-listener"
+
# Check for jsaction event listeners on the element.
if element.hasAttribute "jsaction"
jsactionRules = element.getAttribute("jsaction").split(";")
@@ -198,6 +218,8 @@ LinkHints =
if clientRect != null
visibleElements.push {element: element, rect: clientRect, secondClassCitizen: onlyHasTabIndex}
+ @markChildrenThatHaveDelegatedOnClickListener element
+
visibleElements
#
@@ -208,6 +230,7 @@ LinkHints =
# element.
#
getVisibleClickableElements: ->
+ @markChildrenThatHaveDelegatedOnClickListener document.documentElement
elements = document.documentElement.getElementsByTagName "*"
visibleElements = []
diff --git a/manifest.json b/manifest.json
index a5dbec21e..236cdb10c 100644
--- a/manifest.json
+++ b/manifest.json
@@ -68,6 +68,7 @@
},
"web_accessible_resources": [
"pages/vomnibar.html",
+ "pages/jQuery_delegatedEvents_hook.js",
"pages/addEventListener_hook.js"
]
}
diff --git a/pages/jQuery_delegatedEvents_hook.coffee b/pages/jQuery_delegatedEvents_hook.coffee
new file mode 100644
index 000000000..2166bacab
--- /dev/null
+++ b/pages/jQuery_delegatedEvents_hook.coffee
@@ -0,0 +1,26 @@
+markHookSet = "vimium-hooked-delegated-onclick-listeners"
+return if document.documentElement.hasAttribute(markHookSet)
+
+
+Object.defineProperty window, "jQuery",
+ enumerable: yes
+ configurable: yes
+ set: (jQuery) ->
+ on_ = jQuery.fn.on
+
+ jQuery.fn.on = (evnt, selector, handlerFn) ->
+ if evnt is "click" and typeof selector is "string"
+ attrKey = "vimium-jquery-delegated-events-selectors"
+ sep = "|"
+
+ element = if @[0] is document then document.documentElement else @[0]
+ selectors = element.getAttribute(attrKey) || sep
+ if selectors.indexOf("#{sep}#{selector}#{sep}") < 0
+ element.setAttribute attrKey, selectors + selector + sep
+
+ return on_.apply @, arguments
+
+ return jQuery
+
+
+document.documentElement.setAttribute markHookSet, ""
diff --git a/tests/dom_tests/dom_tests.html b/tests/dom_tests/dom_tests.html
index 8c51a810d..b7542f9b7 100644
--- a/tests/dom_tests/dom_tests.html
+++ b/tests/dom_tests/dom_tests.html
@@ -29,6 +29,7 @@
+