]> git.gir.st - VimFx.git/blob - extension/packages/find-link.coffee
Workaround for command shortcuts that start with letter c
[VimFx.git] / extension / packages / find-link.coffee
1 utils = require 'utils'
2
3 # All the following elements qualify as a link
4 LINK_ELEMENTS = [
5 "a"
6 "area[@href]"
7 "button"
8 ]
9
10 # All elements that have one or more of the following properties
11 # qualify as a link
12 LINK_ELEMENT_PROPERTIES = [
13 "@onclick"
14 "@onmousedown"
15 "@onmouseup"
16 "@oncommand"
17 "@role='link'"
18 "@role='button'"
19 "contains(@class, 'button')"
20 ]
21
22 # Find a link that match with the patterns
23 findLinkMatchPattern = (document, patterns) ->
24 links = getLinkElements(document)
25 candidateLinks = []
26
27 # filter visible links that contain patterns and put in candidateLinks
28 for i in [0...links.snapshotLength] by 1
29 link = links.snapshotItem(i)
30
31 if isVisibleElement(link) and isElementMatchPattern(link, patterns)
32 candidateLinks.push(link)
33
34 return if candidateLinks.length == 0
35
36 for link in candidateLinks
37 link.wordCount = link.textContent.trim().split(/\s+/).length
38
39 # favor shorter links, links near the end of a page
40 candidateLinks = candidateLinks.sort (a, b) ->
41 if a.wordCount == b.wordCount then 1 else a.wordCount - b.wordCount
42
43 results = []
44
45 # match patterns. Sort them to match shorter patterns first.
46 # The latter is to prevent matching first links that contain
47 # longer words like `next`, `more`, etc.
48 for pattern in patterns.sort((a, b) -> a.length > b.length)
49 console.log(pattern)
50 # if the pattern is a word, wrapped it in word boundaries.
51 # thus we won't match words like 'previously' to 'previous'
52 exactWordRegex =
53 if /^\b|\b$/.test(pattern)
54 new RegExp('\\b' + pattern + '\\b', 'i')
55 else
56 new RegExp(pattern, 'i')
57
58 for candidateLink in candidateLinks
59 if exactWordRegex.test(candidateLink.textContent)
60 results.push(candidateLink)
61
62 return results
63
64
65 # Returns elements that qualify as links
66 getLinkElements = do ->
67 elements = [
68 LINK_ELEMENTS...
69 "*[#{ LINK_ELEMENT_PROPERTIES.join(' or ') }]"
70 ]
71
72 return utils.getDomElements(elements)
73
74
75 # Determine if the link is visible
76 isVisibleElement = (element) ->
77 document = element.ownerDocument
78 window = document.defaultView
79
80 # element that isn't visible on the page
81 computedStyle = window.getComputedStyle(element, null)
82 if computedStyle.getPropertyValue('visibility') != 'visible' or
83 computedStyle.getPropertyValue('display') == 'none' or
84 computedStyle.getPropertyValue('opacity') == '0'
85 return false
86
87 # element that has zero dimension
88 clientRect = element.getBoundingClientRect()
89 if clientRect.width == 0 or clientRect.height == 0
90 return false
91
92 return true
93
94
95 # Determine if the link has a pattern matched
96 isElementMatchPattern = (element, patterns) ->
97 for pattern in patterns
98 if element.textContent.toLowerCase().contains(pattern)
99 return true
100
101 return false
102
103 exports.find = findLinkMatchPattern
Imprint / Impressum