1 utils = require 'utils'
2 hints = require 'hints'
5 enter: (vim, storage, [ callback ]) ->
6 markers = hints.injectHints(vim.window.document)
10 storage.markers = markers
11 storage.callback = callback
13 # Processes the char, updates and hides/shows markers
14 handleKeyDown: (vim, storage, event) ->
15 { markers, callback } = storage
19 @rotateOverlappingMarkers(markers, true)
21 @rotateOverlappingMarkers(markers, false)
25 marker.deleteHintChar()
28 return false if vim.lastKeyStr not in utils.getHintChars() or event.ctrlKey or event.metaKey
30 marker.matchHintChar(vim.lastKeyStr)
33 marker.reward() # Add element features to the bloom filter
40 onEnterNormalMode: (vim, storage) ->
41 hints.removeHints(vim.window.document)
42 storage.markers = storage.callback = undefined
44 # Finds all stacks of markers that overlap each other (by using `getStackFor`) (#1), and rotates
45 # their `z-index`:es (#2), thus alternating which markers are visible.
46 rotateOverlappingMarkers: (originalMarkers, forward) ->
47 # Shallow working copy. This is necessary since `markers` will be mutated and eventually empty.
48 markers = originalMarkers[..]
51 stacks = (@getStackFor(markers.pop(), markers) while markers.length > 0)
54 # Stacks of length 1 don't participate in any overlapping, and can therefore be skipped.
55 for stack in stacks when stack.length > 1
56 # This sort is not required, but makes the rotation more predictable.
57 stack.sort((a, b) -> a.markerElement.style.zIndex - b.markerElement.style.zIndex)
60 indexStack = (m.markerElement.style.zIndex for m in stack)
61 # Shift the array of indices one item forward or back
63 indexStack.unshift(indexStack.pop())
65 indexStack.push(indexStack.shift())
67 for marker, index in stack
68 marker.markerElement.style.setProperty('z-index', indexStack[index], 'important')
72 # Get an array containing `marker` and all markers that overlap `marker`, if any, which is called a
73 # "stack". All markers in the returned stack are spliced out from `markers`, thus mutating it.
74 getStackFor: (marker, markers) ->
77 { top, bottom, left, right } = marker.position
80 while index < markers.length
81 nextMarker = markers[index]
83 { top: nextTop, bottom: nextBottom, left: nextLeft, right: nextRight } = nextMarker.position
84 overlapsVertically = (nextBottom >= top and nextTop <= bottom)
85 overlapsHorizontally = (nextRight >= left and nextLeft <= right)
87 if overlapsVertically and overlapsHorizontally
88 # Also get all markers overlapping this one
89 markers.splice(index, 1)
90 stack = stack.concat(@getStackFor(nextMarker, markers))
101 exports.modes = modes