]> git.gir.st - VimFx.git/blob - extension/packages/mode-hints/marker.coffee
Merge branch 'develop' into simpler-dom
[VimFx.git] / extension / packages / mode-hints / marker.coffee
1 { createElement } = require 'utils'
2 { SerializableBloomFilter
3 , DummyBloomFilter } = require 'mode-hints/bloomfilter'
4
5 { getPref } = require 'prefs'
6
7 HTMLDocument = Ci.nsIDOMHTMLDocument
8 HTMLAnchorElement = Ci.nsIDOMHTMLAnchorElement
9
10 realBloomFilter = new SerializableBloomFilter('hints_bloom_data', 256 * 32, 16)
11 dummyBloomFilter = new DummyBloomFilter()
12
13 # Wraps the markable element and provides 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 = createElement(document, 'div', {class: 'VimFxHintMarker'})
20
21 Object.defineProperty this, 'bloomFilter',
22 get: -> if getPref('hints_bloom_on') then realBloomFilter else dummyBloomFilter
23
24 show: -> @setVisibility(true)
25 hide: -> @setVisibility(false)
26 setVisibility: (visible) ->
27 method = if visible then 'remove' else 'add'
28 @markerElement.classList[method]('VimFxHiddenHintMarker')
29
30 setPosition: (top, left) ->
31 # The positioning is absulute
32 @markerElement.style.top = "#{ top }px"
33 @markerElement.style.left = "#{ left }px"
34
35 # For quick access
36 @position = {top, left}
37
38 # To be called when the marker has been both assigned a hint and inserted into the DOM, and thus
39 # gotten a height and width.
40 completePosition: ->
41 {
42 position: { top, left }
43 markerElement: { offsetHeight: height, offsetWidth: width }
44 } = this
45 @position = {top, bottom: top + height, left, right: left + width, height, width}
46
47 setHint: (@hintChars) ->
48 # Hint chars that have been matched so far
49 @enteredHintChars = ''
50
51 document = @element.ownerDocument
52
53 while @markerElement.hasChildNodes()
54 @markerElement.firstChild.remove()
55
56 fragment = document.createDocumentFragment()
57 for char in @hintChars
58 charContainer = createElement(document, 'span')
59 charContainer.textContent = char.toUpperCase()
60 fragment.appendChild(charContainer)
61
62 @markerElement.appendChild(fragment)
63
64 matchHintChar: (char) ->
65 @updateEnteredHintChars(char)
66
67 deleteHintChar: ->
68 @updateEnteredHintChars(false)
69
70 updateEnteredHintChars: (char) ->
71 if char == false
72 method = 'remove'
73 @enteredHintChars = @enteredHintChars[...-1]
74 offset = 0
75 else
76 method = 'add'
77 @enteredHintChars += char.toLowerCase()
78 offset = -1
79
80 @markerElement.children[@enteredHintChars.length + offset]?.classList[method]('VimFxCharMatch')
81 if @hintChars.startsWith(@enteredHintChars) then @show() else @hide()
82
83 isMatched: ->
84 return @hintChars == @enteredHintChars
85
86 reset: ->
87 @setHint(@hintChars)
88 @show()
89
90 # Returns string features of the element that can be used in the bloom filter
91 # in order to add relevance to the hint marker
92 extractBloomFeatures: ->
93 features = {}
94
95 # Class name of an element (walks up the node tree to find first element with at least one class)
96 suffix = ''
97 el = @element
98 while el.classList?.length == 0 and el not instanceof HTMLDocument
99 suffix += " #{ el.tagName }"
100 el = el.parentNode
101 if el?.classList?
102 for className in el.classList
103 features["#{ el.tagName }.#{ className }#{ suffix }"] = 10
104
105 if @element.id
106 features["#{ el.tagName }.#{ @element.id }"] = 5
107
108 if @element instanceof HTMLAnchorElement
109 features["a"] = 20 # Reward links no matter what
110 features["#{ el.tagName }.#{ @element.href }"] = 60
111 features["#{ el.tagName }.#{ @element.title }"] = 40
112
113 return features
114
115 # Returns rating of all present bloom features (plus 1)
116 calcBloomRating: ->
117 rating = 1
118 for feature, weight of @extractBloomFeatures()
119 rating += if @bloomFilter.test(feature) then weight else 0
120
121 return rating
122
123 reward: ->
124 for feature, weight of @extractBloomFeatures()
125 @bloomFilter.add(feature)
126 @bloomFilter.save()
127
128 exports.Marker = Marker
Imprint / Impressum