1 # This file is the equivalent to vim.coffee. `vim.window` is called
2 # `vim.content` to be consistent with Firefox’s frame script terminology and to
3 # avoid confusion about what it represents. There is one `VimFrame` instance for
4 # each tab. It mostly tries to mimic the `Vim` class in vim.coffee, but also
5 # keeps track of web page state. `VimFrame` is not part of the config file API.
7 messageManager = require('./message-manager')
8 ScrollableElements = require('./scrollable-elements')
9 utils = require('./utils')
12 constructor: (@content) ->
18 messageManager.listen('modeChange', ({mode}) =>
22 messageManager.listen(
23 'markPageInteraction', @markPageInteraction.bind(this)
26 messageManager.listen('clearHover', @clearHover.bind(this))
28 # If the target is the topmost document, reset everything. Otherwise filter
29 # out elements belonging to the target frame. On some sites, such as Gmail,
30 # some elements might be dead at this point.
31 resetState: (target = @content.document) ->
32 if target == @content.document
39 explicitBodyFocus: false
40 hasFocusedTextInput: false
41 lastFocusedTextInput: null
44 browserOffset: {x: 0, y: 0}
46 scrollableElements: new ScrollableElements(@content)
53 return Cu.isDeadWrapper(element) or element.ownerDocument == target
54 check = (obj, prop) ->
55 obj[prop] = null if obj[prop] and isDead(obj[prop])
57 check(@state, 'lastFocusedTextInput')
58 check(@state.lastHover, 'element')
59 @state.scrollableElements.reject(isDead)
60 # `markerElements` and `inputs` could theoretically need to be filtered
61 # too at this point. YAGNI until an issue arises from it.
63 options: (prefs) -> messageManager.get('options', {prefs})
65 _enterMode: (@mode, args...) ->
66 messageManager.send('vimMethod', {
68 args: [@mode, args...]
72 messageManager.send('vimMethod', {method: 'notify', args})
75 messageManager.send('vimMethod', {method: 'hideNotification'})
77 markPageInteraction: (value = true) -> @state.hasInteraction = value
79 setHover: (element, browserOffset) ->
80 utils.simulateMouseEvents(element, 'hover-start', browserOffset)
81 @state.lastHover.element = element
82 @state.lastHover.browserOffset = browserOffset
85 if @state.lastHover.element
86 {element, browserOffset} = @state.lastHover
87 utils.simulateMouseEvents(element, 'hover-end', browserOffset)
88 @state.lastHover.element = null
91 [newX, newY] = position = @state.scrollableElements.getPageScrollPosition()
92 jumpList = @state.jumpList[..@state.jumpListIndex]
93 .filter(([x, y]) -> not (x == newX and y == newY))
95 @state.jumpList = jumpList
96 @state.jumpListIndex = jumpList.length - 1
98 module.exports = VimFrame