]> git.gir.st - VimFx.git/blob - extension/packages/marker.coffee
Merge pull request #173 from sirodoht/develop
[VimFx.git] / extension / packages / marker.coffee
1 { SerializableBloomFilter
2 , DummyBloomFilter } = require 'bloomfilter'
3
4 { getPref } = require 'prefs'
5
6 HTMLDocument = Ci.nsIDOMHTMLDocument
7 HTMLAnchorElement = Ci.nsIDOMHTMLAnchorElement
8
9 realBloomFilter = new SerializableBloomFilter('hints_bloom_data', 256 * 32, 16)
10 dummyBloomFilter = new DummyBloomFilter()
11
12 # Marker class wraps the markable element and provides
13 # methods to manipulate the markers
14 class Marker
15 # Creates the marker DOM node
16 constructor: (@element) ->
17 document = @element.ownerDocument
18 window = document.defaultView
19 @markerElement = document.createElement('div')
20 @markerElement.className = 'VimFxReset VimFxHintMarker'
21
22 Object.defineProperty(this, 'bloomFilter', get: ->
23 if getPref('hints_bloom_on') then realBloomFilter else dummyBloomFilter)
24
25 # Shows the marker
26 show: -> @markerElement.className = 'VimFxReset VimFxHintMarker'
27
28 # Hides the marker
29 hide: -> @markerElement.className = 'VimFxReset VimFxHiddenHintMarker'
30
31 # Positions the marker on the page. The positioning is absulute
32 setPosition: (rect) ->
33 @markerElement.style.left = rect.left + 'px'
34 @markerElement.style.top = rect.top + 'px'
35
36 # Assigns hint string to the marker
37 setHint: (@hintChars) ->
38 # Hint chars that have been matched so far
39 @enteredHintChars = ''
40
41 document = @element.ownerDocument
42
43 while @markerElement.hasChildNodes()
44 @markerElement.removeChild(@markerElement.firstChild)
45
46 fragment = document.createDocumentFragment()
47 for char in @hintChars
48 span = document.createElement('span')
49 span.className = 'VimFxReset'
50 span.textContent = char.toUpperCase()
51 fragment.appendChild(span)
52
53 @markerElement.appendChild(fragment)
54
55 # Add another char to the `enteredHintString`,
56 # see if it still matches `hintString`, apply classes to
57 # the distinct hint characters and show/hide marker when
58 # the entered string partially (not) matches the hint string
59 matchHintChar: (char) ->
60 # Handle backspace key by removing a previously entered hint char
61 # and resetting its class
62 if char == 'Backspace'
63 if @enteredHintChars.length > 0
64 @enteredHintChars = @enteredHintChars[0...-1]
65 @markerElement.children[@enteredHintChars.length]?.className = 'VimFxReset'
66 # Otherwise append hint char and change hint class
67 else
68 @markerElement.children[@enteredHintChars.length]?.className = 'VimFxReset VimFxCharMatch'
69 @enteredHintChars += char.toLowerCase()
70
71 # If entered hint chars no longer partially match the hint chars
72 # then hide the marker. Othersie show it back
73 if @hintChars.search(@enteredHintChars) == 0 then @show() else @hide()
74
75 # Checks if the marker will be matched if the next character entered is `char`
76 willMatch: (char) ->
77 char == 'Backspace' or @hintChars.search(@enteredHintChars + char.toLowerCase()) == 0
78
79 # Checks if enterd hint chars completely match the hint chars
80 isMatched: ->
81 return @hintChars == @enteredHintChars
82
83 # Returns string features of the element that can be used in the bloom filter
84 # in order to add relevance to the hint marker
85 extractBloomFeatures: ->
86 features = {}
87
88 # Class name of an element (walks up the node tree to find first element with at least one class)
89 suffix = ''
90 el = @element
91 while el.classList?.length == 0 and el not instanceof HTMLDocument
92 suffix = "#{ suffix } #{ el.tagName }"
93 el = el.parentNode
94 if el and el.classList
95 for className in el.classList
96 features["#{ el.tagName }.#{ className }#{ suffix }"] = 10
97
98 # Element id
99 if @element.id
100 features["#{ el.tagName }.#{ @element.id }"] = 5
101
102 if @element instanceof HTMLAnchorElement
103 features["a"] = 20 # Reward links no matter what
104 features["#{ el.tagName }.#{ @element.href }"] = 60
105 features["#{ el.tagName }.#{ @element.title }"] = 40
106
107 return features
108
109 # Returns rating of all present bloom features (plus 1)
110 calcBloomRating: ->
111 rating = 1
112 for feature, weight of @extractBloomFeatures()
113 rating += if @bloomFilter.test(feature) then weight else 0
114
115 return rating
116
117 reward: ->
118 for feature, weight of @extractBloomFeatures()
119 @bloomFilter.add(feature)
120 @bloomFilter.save()
121
122 exports.Marker = Marker
Imprint / Impressum