2 # Copyright Anton Khodakivskiy 2012, 2013, 2014.
3 # Copyright Simon Lydell 2013, 2014, 2015, 2016.
4 # Copyright Wang Zhuochun 2013, 2014.
6 # This file is part of VimFx.
8 # VimFx is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
13 # VimFx is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with VimFx. If not, see <http://www.gnu.org/licenses/>.
22 # This file defines all Normal mode commands. Commands that need to interact
23 # with web page content do so by running `vim._run(name)`, which invokes `name`
24 # in commands-frame.coffee.
26 # NOTE: Most tab related commands need to do their actual tab manipulations in
27 # the next tick (`utils.nextTick`) to work around bug 1200334.
29 config = require('./config')
30 help = require('./help')
31 hints = require('./hints')
32 prefs = require('./prefs')
33 translate = require('./l10n')
34 utils = require('./utils')
35 SelectionManager = require('./selection')
36 viewportUtils = require('./viewport')
38 {ContentClick} = Cu.import('resource:///modules/ContentClick.jsm', {})
39 {FORWARD, BACKWARD} = SelectionManager
45 commands.focus_location_bar = ({vim}) ->
46 vim.window.focusAndSelectUrlBar()
48 commands.focus_search_bar = ({vim, count}) ->
49 # The `.webSearch()` method opens a search engine in a tab if the search bar
50 # has been removed. Therefore we first check if it exists.
51 if vim.window.BrowserSearch.searchBar
52 vim.window.BrowserSearch.webSearch()
54 vim.notify(translate('notification.focus_search_bar.none'))
56 helper_paste_and_go = (props, {vim}) ->
57 {gURLBar} = vim.window
58 gURLBar.value = vim.window.readFromClipboard()
59 gURLBar.handleCommand(new vim.window.KeyboardEvent('keydown', props))
61 commands.paste_and_go = helper_paste_and_go.bind(null, null)
63 commands.paste_and_go_in_tab = helper_paste_and_go.bind(null, {altKey: true})
65 commands.copy_current_url = ({vim}) ->
66 utils.writeToClipboard(vim.window.gBrowser.currentURI.spec)
67 vim.notify(translate('notification.copy_current_url.success'))
69 commands.go_up_path = ({vim, count}) ->
70 vim._run('go_up_path', {count})
72 commands.go_to_root = ({vim}) ->
73 vim._run('go_to_root')
75 commands.go_home = ({vim}) ->
76 vim.window.BrowserHome()
78 helper_go_history = (direction, {vim, count = 1}) ->
80 {SessionStore, gBrowser} = window
82 if (direction == 'back' and not gBrowser.canGoBack) or
83 (direction == 'forward' and not gBrowser.canGoForward)
84 vim.notify(translate("notification.history_#{direction}.limit"))
87 # `SessionStore.getSessionHistory()` (used below to support counts) starts
88 # lots of asynchronous tasks internally, which is a bit unreliable, it has
89 # turned out. The primary use of the `history_back` and `history_forward`
90 # commands is to go _one_ step back or forward, though, so those cases are
91 # optimized to use more reliable ways of going back and forward. Also, some
92 # extensions override the following functions, so calling them also gives
93 # better interoperability.
95 if direction == 'back'
98 window.BrowserForward()
101 SessionStore.getSessionHistory(gBrowser.selectedTab, (sessionHistory) ->
102 {index} = sessionHistory
103 newIndex = index + count * (if direction == 'back' then -1 else 1)
104 newIndex = Math.max(newIndex, 0)
105 newIndex = Math.min(newIndex, sessionHistory.entries.length - 1)
106 gBrowser.gotoIndex(newIndex)
109 commands.history_back = helper_go_history.bind(null, 'back')
111 commands.history_forward = helper_go_history.bind(null, 'forward')
113 commands.history_list = ({vim}) ->
114 menu = vim.window.document.getElementById('backForwardMenu')
115 utils.openPopup(menu)
116 if menu.childElementCount == 0
117 vim.notify(translate('notification.history_list.none'))
119 commands.reload = ({vim}) ->
120 vim.window.BrowserReload()
122 commands.reload_force = ({vim}) ->
123 vim.window.BrowserReloadSkipCache()
125 commands.reload_all = ({vim}) ->
126 vim.window.gBrowser.reloadAllTabs()
128 commands.reload_all_force = ({vim}) ->
129 for tab in vim.window.gBrowser.visibleTabs
130 gBrowser = tab.linkedBrowser
131 consts = gBrowser.webNavigation
132 flags = consts.LOAD_FLAGS_BYPASS_PROXY | consts.LOAD_FLAGS_BYPASS_CACHE
133 gBrowser.reload(flags)
136 commands.stop = ({vim}) ->
137 vim.window.BrowserStop()
139 commands.stop_all = ({vim}) ->
140 for tab in vim.window.gBrowser.visibleTabs
141 tab.linkedBrowser.stop()
146 helper_scroll = (vim, uiEvent, args...) ->
148 method, type, directions, amounts
149 properties = null, adjustment = 0, name = 'scroll'
152 method, type, directions, amounts, properties, adjustment
154 prefs.root.get('general.smoothScroll') and
155 prefs.root.get("general.smoothScroll.#{type}")
158 reset = prefs.root.tmp(
159 'layout.css.scroll-behavior.spring-constant',
160 vim.options["smoothScroll.#{type}.spring-constant"]
163 helpScroll = help.getHelp(vim.window)?.querySelector('.wrapper')
164 if uiEvent or helpScroll
165 activeElement = helpScroll or utils.getActiveElement(vim.window)
166 if vim._state.scrollableElements.has(activeElement) or helpScroll
167 viewportUtils.scroll(activeElement, options)
171 vim._run(name, options, reset)
174 helper_scrollByLinesX = (amount, {vim, uiEvent, count = 1}) ->
175 distance = prefs.root.get('toolkit.scrollbox.horizontalScrollDistance')
177 vim, uiEvent, 'scrollBy', 'lines', ['left'], [amount * distance * count * 5]
180 helper_scrollByLinesY = (amount, {vim, uiEvent, count = 1}) ->
181 distance = prefs.root.get('toolkit.scrollbox.verticalScrollDistance')
183 vim, uiEvent, 'scrollBy', 'lines', ['top'], [amount * distance * count * 20]
186 helper_scrollByPagesY = (amount, type, {vim, uiEvent, count = 1}) ->
187 adjustment = vim.options["scroll.#{type}_page_adjustment"]
189 vim, uiEvent, 'scrollBy', 'pages', ['top'], [amount * count],
190 ['clientHeight'], adjustment
193 helper_scrollToX = (amount, {vim, uiEvent}) ->
194 helper_mark_last_scroll_position(vim)
196 vim, uiEvent, 'scrollTo', 'other', ['left'], [amount], ['scrollLeftMax']
199 helper_scrollToY = (amount, {vim, uiEvent}) ->
200 helper_mark_last_scroll_position(vim)
202 vim, uiEvent, 'scrollTo', 'other', ['top'], [amount], ['scrollTopMax']
205 commands.scroll_left = helper_scrollByLinesX.bind(null, -1)
206 commands.scroll_right = helper_scrollByLinesX.bind(null, +1)
207 commands.scroll_down = helper_scrollByLinesY.bind(null, +1)
208 commands.scroll_up = helper_scrollByLinesY.bind(null, -1)
209 commands.scroll_page_down = helper_scrollByPagesY.bind(null, +1, 'full')
210 commands.scroll_page_up = helper_scrollByPagesY.bind(null, -1, 'full')
211 commands.scroll_half_page_down = helper_scrollByPagesY.bind(null, +0.5, 'half')
212 commands.scroll_half_page_up = helper_scrollByPagesY.bind(null, -0.5, 'half')
213 commands.scroll_to_top = helper_scrollToY.bind(null, 0)
214 commands.scroll_to_bottom = helper_scrollToY.bind(null, Infinity)
215 commands.scroll_to_left = helper_scrollToX.bind(null, 0)
216 commands.scroll_to_right = helper_scrollToX.bind(null, Infinity)
218 helper_mark_last_scroll_position = (vim) ->
219 keyStr = vim.options['scroll.last_position_mark']
220 vim._run('mark_scroll_position', {keyStr, notify: false})
222 commands.mark_scroll_position = ({vim}) ->
223 vim.enterMode('marks', (keyStr) -> vim._run('mark_scroll_position', {keyStr}))
224 vim.notify(translate('notification.mark_scroll_position.enter'))
226 commands.scroll_to_mark = ({vim}) ->
227 vim.enterMode('marks', (keyStr) ->
228 unless keyStr == vim.options['scroll.last_position_mark']
229 helper_mark_last_scroll_position(vim)
231 vim, null, 'scrollTo', 'other', ['top', 'left'], keyStr,
232 ['scrollTopMax', 'scrollLeftMax'], 0, 'scroll_to_mark'
235 vim.notify(translate('notification.scroll_to_mark.enter'))
239 commands.tab_new = ({vim}) ->
240 utils.nextTick(vim.window, ->
241 vim.window.BrowserOpenTab()
244 commands.tab_new_after_current = ({vim}) ->
246 newTabPosition = window.gBrowser.selectedTab._tPos + 1
247 utils.nextTick(window, ->
248 utils.listenOnce(window, 'TabOpen', (event) ->
249 newTab = event.originalTarget
250 window.gBrowser.moveTabTo(newTab, newTabPosition)
252 window.BrowserOpenTab()
255 commands.tab_duplicate = ({vim}) ->
256 {gBrowser} = vim.window
257 utils.nextTick(vim.window, ->
258 gBrowser.duplicateTab(gBrowser.selectedTab)
261 absoluteTabIndex = (relativeIndex, gBrowser, {pinnedSeparate}) ->
262 tabs = gBrowser.visibleTabs
263 {selectedTab} = gBrowser
265 currentIndex = tabs.indexOf(selectedTab)
266 absoluteIndex = currentIndex + relativeIndex
267 numTabsTotal = tabs.length
268 numPinnedTabs = gBrowser._numPinnedTabs
270 [numTabs, min] = switch
271 when not pinnedSeparate
273 when selectedTab.pinned
276 [numTabsTotal - numPinnedTabs, numPinnedTabs]
278 # Wrap _once_ if at one of the ends of the tab bar and cannot move in the
280 if (relativeIndex < 0 and currentIndex == min) or
281 (relativeIndex > 0 and currentIndex == min + numTabs - 1)
282 if absoluteIndex < min
283 absoluteIndex += numTabs
284 else if absoluteIndex >= min + numTabs
285 absoluteIndex -= numTabs
287 absoluteIndex = Math.max(min, absoluteIndex)
288 absoluteIndex = Math.min(absoluteIndex, min + numTabs - 1)
292 helper_switch_tab = (direction, {vim, count = 1}) ->
293 {gBrowser} = vim.window
294 index = absoluteTabIndex(direction * count, gBrowser, {pinnedSeparate: false})
295 utils.nextTick(vim.window, ->
296 gBrowser.selectTabAtIndex(index)
299 commands.tab_select_previous = helper_switch_tab.bind(null, -1)
301 commands.tab_select_next = helper_switch_tab.bind(null, +1)
303 helper_is_visited = (tab) ->
304 return tab.getAttribute('VimFx-visited') or not tab.getAttribute('unread')
306 commands.tab_select_most_recent = ({vim, count = 1}) ->
307 {gBrowser} = vim.window
311 (tab) -> not tab.closing and helper_is_visited(tab)
312 ).sort((a, b) -> b.lastAccessed - a.lastAccessed)[1..] # Remove current tab.
313 tab = tabsSorted[Math.min(count - 1, tabsSorted.length - 1)]
315 gBrowser.selectedTab = tab
317 vim.notify(translate('notification.tab_select_most_recent.none'))
319 commands.tab_select_oldest_unvisited = ({vim, count = 1}) ->
320 {gBrowser} = vim.window
324 (tab) -> not tab.closing and not helper_is_visited(tab)
325 ).sort((a, b) -> a.lastAccessed - b.lastAccessed)
326 tab = tabsSorted[Math.min(count - 1, tabsSorted.length - 1)]
328 gBrowser.selectedTab = tab
330 vim.notify(translate('notification.tab_select_oldest_unvisited.none'))
332 helper_move_tab = (direction, {vim, count = 1}) ->
333 {gBrowser} = vim.window
334 index = absoluteTabIndex(direction * count, gBrowser, {pinnedSeparate: true})
335 utils.nextTick(vim.window, ->
336 gBrowser.moveTabTo(gBrowser.selectedTab, index)
339 commands.tab_move_backward = helper_move_tab.bind(null, -1)
341 commands.tab_move_forward = helper_move_tab.bind(null, +1)
343 commands.tab_move_to_window = ({vim}) ->
344 {gBrowser} = vim.window
345 gBrowser.replaceTabWithWindow(gBrowser.selectedTab)
347 commands.tab_select_first = ({vim, count = 1}) ->
348 utils.nextTick(vim.window, ->
349 vim.window.gBrowser.selectTabAtIndex(count - 1)
352 commands.tab_select_first_non_pinned = ({vim, count = 1}) ->
353 firstNonPinned = vim.window.gBrowser._numPinnedTabs
354 utils.nextTick(vim.window, ->
355 vim.window.gBrowser.selectTabAtIndex(firstNonPinned + count - 1)
358 commands.tab_select_last = ({vim, count = 1}) ->
359 utils.nextTick(vim.window, ->
360 vim.window.gBrowser.selectTabAtIndex(-count)
363 commands.tab_toggle_pinned = ({vim}) ->
364 currentTab = vim.window.gBrowser.selectedTab
366 vim.window.gBrowser.unpinTab(currentTab)
368 vim.window.gBrowser.pinTab(currentTab)
370 commands.tab_close = ({vim, count = 1}) ->
371 {gBrowser} = vim.window
372 return if gBrowser.selectedTab.pinned
373 currentIndex = gBrowser.visibleTabs.indexOf(gBrowser.selectedTab)
374 utils.nextTick(vim.window, ->
375 for tab in gBrowser.visibleTabs[currentIndex...(currentIndex + count)]
376 gBrowser.removeTab(tab)
380 commands.tab_restore = ({vim, count = 1}) ->
381 utils.nextTick(vim.window, ->
382 for index in [0...count] by 1
383 restoredTab = vim.window.undoCloseTab()
384 if not restoredTab and index == 0
385 vim.notify(translate('notification.tab_restore.none'))
390 commands.tab_restore_list = ({vim}) ->
392 fragment = window.RecentlyClosedTabsAndWindowsMenuUtils.getTabsFragment(
395 if fragment.childElementCount == 0
396 vim.notify(translate('notification.tab_restore.none'))
398 utils.openPopup(utils.injectTemporaryPopup(window.document, fragment))
400 commands.tab_close_to_end = ({vim}) ->
401 {gBrowser} = vim.window
402 gBrowser.removeTabsToTheEndFrom(gBrowser.selectedTab)
404 commands.tab_close_other = ({vim}) ->
405 {gBrowser} = vim.window
406 gBrowser.removeAllTabsBut(gBrowser.selectedTab)
410 helper_follow = (name, vim, callback, count = null) ->
411 vim.markPageInteraction()
412 help.removeHelp(vim.window)
414 # Enter hints mode immediately, with an empty set of markers. The user might
415 # press keys before the `vim._run` callback is invoked. Those key presses
416 # should be handled in hints mode, not normal mode.
418 storage = vim.enterMode(
419 'hints', initialMarkers, callback, count, vim.options.hints_sleep
422 setMarkers = ({wrappers, viewport}) ->
423 if wrappers.length > 0
424 {markers, markerMap} = hints.injectHints(
425 vim.window, wrappers, viewport, vim.options
427 storage.markers = markers
428 storage.markerMap = markerMap
430 vim.notify(translate('notification.follow.none'))
431 vim.enterMode('normal')
433 vim._run(name, {}, (result) ->
434 # The user might have exited hints mode (and perhaps even entered it again)
435 # before this callback is invoked. If so, `storage.markers` has been
436 # cleared, or set to a new value. Only proceed if it is unchanged.
437 return unless storage.markers == initialMarkers
439 storage.markEverything = ->
440 lastMarkers = storage.markers
441 vim._run(name, {markEverything: true}, (newResult) ->
442 return unless storage.markers == lastMarkers
443 setMarkers(newResult)
447 helper_follow_clickable = (options, {vim, count = 1}) ->
448 callback = (marker, timesLeft, keyStr) ->
449 {inTab, inBackground} = options
450 {type, elementIndex} = marker.wrapper
451 isLast = (timesLeft == 1)
452 isLink = (type == 'link')
455 when keyStr.startsWith(vim.options.hints_toggle_in_tab)
457 when keyStr.startsWith(vim.options.hints_toggle_in_background)
459 inBackground = not inBackground
465 inTab = false unless isLink
467 if type == 'text' or (isLink and not (inTab and inBackground))
470 vim._focusMarkerElement(elementIndex)
473 utils.nextTick(vim.window, ->
474 # `ContentClick.contentAreaClick` is what Firefox invokes when you click
475 # links using the mouse. Using that instead of simply
476 # `gBrowser.loadOneTab(url, options)` gives better interoperability with
477 # other add-ons, such as Tree Style Tab and BackTrack Tab History.
478 reset = prefs.root.tmp('browser.tabs.loadInBackground', true)
479 ContentClick.contentAreaClick({
480 href: marker.wrapper.href
481 shiftKey: not inBackground
488 vim._run('click_marker_element', {
490 preventTargetBlank: vim.options.prevent_target_blank
495 name = if options.inTab then 'follow_in_tab' else 'follow'
496 helper_follow(name, vim, callback, count)
499 helper_follow_clickable.bind(null, {inTab: false, inBackground: true})
501 commands.follow_in_tab =
502 helper_follow_clickable.bind(null, {inTab: true, inBackground: true})
504 commands.follow_in_focused_tab =
505 helper_follow_clickable.bind(null, {inTab: true, inBackground: false})
507 commands.follow_in_window = ({vim}) ->
508 callback = (marker) ->
509 vim._focusMarkerElement(marker.wrapper.elementIndex)
510 {href} = marker.wrapper
511 vim.window.openLinkIn(href, 'window', {}) if href
512 helper_follow('follow_in_tab', vim, callback)
514 commands.follow_multiple = (args) ->
515 args.count = Infinity
516 commands.follow(args)
518 commands.follow_copy = ({vim}) ->
519 callback = (marker) ->
520 property = switch marker.wrapper.type
525 when 'contenteditable', 'other'
527 helper_copy_marker_element(vim, marker.wrapper.elementIndex, property)
528 helper_follow('follow_copy', vim, callback)
530 commands.follow_focus = ({vim}) ->
531 callback = (marker) ->
532 vim._focusMarkerElement(marker.wrapper.elementIndex, {select: true})
533 helper_follow('follow_focus', vim, callback)
535 commands.click_browser_element = ({vim}) ->
538 filter = ({markEverything}, element, getElementShape) ->
539 document = element.ownerDocument
542 when vim._state.scrollableElements.has(element)
544 when utils.isFocusable(element) or
545 (element.onclick and element.localName != 'statuspanel')
548 if markEverything and not type
553 return unless shape = getElementShape(element)
554 length = markerElements.push(element)
555 return {type, semantic, shape, elementIndex: length - 1}
557 callback = (marker) ->
558 element = markerElements[marker.wrapper.elementIndex]
559 switch marker.wrapper.type
561 utils.focusElement(element, {flag: 'FLAG_BYKEY'})
562 when 'clickable', 'other'
564 if element.localName == 'tab'
568 utils.focusElement(element)
569 utils.simulateMouseEvents(element, sequence)
571 createMarkers = (wrappers) ->
572 viewport = viewportUtils.getWindowViewport(vim.window)
573 {markers} = hints.injectHints(vim.window, wrappers, viewport, {
574 hint_chars: vim.options.hint_chars
579 wrappers = hints.getMarkableElements(
580 vim.window, filter.bind(null, {markEverything: false})
583 if wrappers.length > 0
584 storage = vim.enterMode('hints', createMarkers(wrappers), callback)
585 storage.markEverything = ->
586 newWrappers = hints.getMarkableElements(
587 vim.window, filter.bind(null, {markEverything: true})
589 storage.markers = createMarkers(newWrappers)
591 vim.notify(translate('notification.follow.none'))
593 helper_follow_pattern = (type, {vim}) ->
595 pattern_selector: vim.options.pattern_selector
596 pattern_attrs: vim.options.pattern_attrs
597 patterns: vim.options["#{type}_patterns"]
599 vim._run('follow_pattern', {type, options})
601 commands.follow_previous = helper_follow_pattern.bind(null, 'prev')
603 commands.follow_next = helper_follow_pattern.bind(null, 'next')
605 commands.focus_text_input = ({vim, count}) ->
606 vim.markPageInteraction()
607 vim._run('focus_text_input', {count})
609 helper_follow_selectable = ({select}, {vim}) ->
610 callback = (marker) ->
611 vim._run('element_text_select', {
612 elementIndex: marker.wrapper.elementIndex
616 vim.enterMode('caret', select)
617 helper_follow('follow_selectable', vim, callback)
619 commands.element_text_caret =
620 helper_follow_selectable.bind(null, {select: false})
622 commands.element_text_select =
623 helper_follow_selectable.bind(null, {select: true})
625 commands.element_text_copy = ({vim}) ->
626 callback = (marker) ->
627 helper_copy_marker_element(vim, marker.wrapper.elementIndex, '_selection')
628 helper_follow('follow_selectable', vim, callback)
630 helper_copy_marker_element = (vim, elementIndex, property) ->
631 if property == '_selection'
632 # Selecting the text and then copying that selection is better than copying
633 # `.textContent`. Slack uses markdown-style backtick syntax for code spans
634 # and then includes those backticks in the compiled output (!), in hidden
635 # `<span>`s, so `.textContent` would copy those too. In `contenteditable`
636 # elements, text selection gives better whitespace than `.textContent`.
637 vim._run('element_text_select', {elementIndex, full: true}, ->
638 vim.window.goDoCommand('cmd_copy') # See `caret.copy_selection_and_exit`.
639 vim._run('clear_selection')
642 vim._run('copy_marker_element', {elementIndex, property})
646 findStorage = {lastSearchString: ''}
648 helper_find_from_top_of_viewport = (vim, direction, callback) ->
649 if vim.options.find_from_top_of_viewport
650 vim._run('find_from_top_of_viewport', {direction}, callback)
654 helper_find = ({highlight, linksOnly = false}, {vim}) ->
655 helpSearchInput = help.getSearchInput(vim.window)
657 helpSearchInput.select()
660 helper_mark_last_scroll_position(vim)
661 helper_find_from_top_of_viewport(vim, FORWARD, ->
662 findBar = vim.window.gBrowser.getFindBar()
664 mode = if linksOnly then findBar.FIND_LINKS else findBar.FIND_NORMAL
665 findBar.startFind(mode)
666 utils.focusElement(findBar._findField, {select: true})
669 return unless highlightButton = findBar.getElement('highlight')
670 if highlightButton.checked != highlight
671 highlightButton.click()
674 commands.find = helper_find.bind(null, {highlight: false})
676 commands.find_highlight_all = helper_find.bind(null, {highlight: true})
678 commands.find_links_only = helper_find.bind(null, {linksOnly: true})
680 helper_find_again = (direction, {vim}) ->
681 findBar = vim.window.gBrowser.getFindBar()
682 if findStorage.lastSearchString.length == 0
683 vim.notify(translate('notification.find_again.none'))
686 helper_mark_last_scroll_position(vim)
687 helper_find_from_top_of_viewport(vim, direction, ->
688 findBar._findField.value = findStorage.lastSearchString
689 findBar.onFindAgainCommand(not direction)
690 message = findBar._findStatusDesc.textContent
691 vim.notify(message) if message
694 commands.find_next = helper_find_again.bind(null, FORWARD)
696 commands.find_previous = helper_find_again.bind(null, BACKWARD)
700 commands.window_new = ({vim}) ->
701 vim.window.OpenBrowserWindow()
703 commands.window_new_private = ({vim}) ->
704 vim.window.OpenBrowserWindow({private: true})
706 commands.enter_mode_ignore = ({vim}) ->
707 vim.enterMode('ignore', {type: 'explicit'})
709 # Quote next keypress (pass it through to the page).
710 commands.quote = ({vim, count = 1}) ->
711 vim.enterMode('ignore', {type: 'explicit', count})
713 commands.enter_reader_view = ({vim}) ->
714 button = vim.window.document.getElementById('reader-mode-button')
715 if not button?.hidden
718 vim.notify(translate('notification.enter_reader_view.none'))
720 commands.reload_config_file = ({vim}) ->
721 vim._parent.emit('shutdown')
722 config.load(vim._parent, (status) -> switch status
724 vim.notify(translate('notification.reload_config_file.none'))
726 vim.notify(translate('notification.reload_config_file.success'))
728 vim.notify(translate('notification.reload_config_file.failure'))
731 commands.help = ({vim}) ->
732 help.injectHelp(vim.window, vim._parent)
734 commands.dev = ({vim}) ->
735 vim.window.DeveloperToolbar.show(true) # `true` to focus.
737 commands.esc = ({vim}) ->
739 utils.blurActiveBrowserElement(vim)
740 vim.window.DeveloperToolbar.hide()
741 vim.window.gBrowser.getFindBar().close()
742 hints.removeHints(vim.window) # Better safe than sorry.
744 unless help.getSearchInput(vim.window)?.getAttribute('focused')
745 help.removeHelp(vim.window)