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 @@ +