]> git.gir.st - VimFx.git/blob - extension/lib/help.coffee
Improve largest scrollable element detection
[VimFx.git] / extension / lib / help.coffee
1 ###
2 # Copyright Simon Lydell 2015.
3 #
4 # This file is part of VimFx.
5 #
6 # VimFx is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # VimFx is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with VimFx. If not, see <http://www.gnu.org/licenses/>.
18 ###
19
20 # This file creates VimFx’s Keyboard Shortcuts help screen.
21
22 translate = require('./l10n')
23 utils = require('./utils')
24
25 CONTAINER_ID = 'VimFxHelpDialogContainer'
26 MAX_FONT_SIZE = 20
27
28 injectHelp = (window, vimfx) ->
29 removeHelp(window)
30
31 {document} = window
32
33 container = document.createElement('box')
34 container.id = CONTAINER_ID
35
36 wrapper = document.createElement('box')
37 container.appendChild(wrapper)
38
39 header = createHeader(document, vimfx)
40 wrapper.appendChild(header)
41
42 content = createContent(document, vimfx)
43 wrapper.appendChild(content)
44
45 window.gBrowser.mCurrentBrowser.parentNode.appendChild(container)
46
47 # The font size of menu items is used by default, which is usually quite
48 # small. Try to increase it without causing a scrollbar.
49 computedStyle = window.getComputedStyle(container)
50 fontSize = originalFontSize =
51 parseFloat(computedStyle.getPropertyValue('font-size'))
52 while wrapper.clientHeight < container.clientHeight and
53 fontSize <= MAX_FONT_SIZE
54 fontSize++
55 container.style.fontSize = "#{fontSize}px"
56 container.style.fontSize = "#{Math.max(fontSize - 1, originalFontSize)}px"
57
58 # Uncomment this line if you want to use `gulp help.html`!
59 # utils.writeToClipboard(container.outerHTML)
60
61 removeHelp = (window) ->
62 window.document.getElementById(CONTAINER_ID)?.remove()
63
64 createHeader = (document, vimfx) ->
65 $ = utils.createBox.bind(null, document)
66
67 header = $('header')
68
69 mainHeading = $('heading-main', header)
70 $('logo', mainHeading) # Content is added by CSS.
71 $('title', mainHeading, translate('help.title'))
72
73 closeButton = $('close-button', header, '×')
74 closeButton.onclick = removeHelp.bind(null, document.ownerGlobal)
75
76 return header
77
78 createContent = (document, vimfx) ->
79 $ = utils.createBox.bind(null, document)
80
81 content = $('content')
82
83 for mode in vimfx.getGroupedCommands({enabledOnly: true})
84 modeHeading = $('heading-mode', null, mode.name)
85
86 for category, index in mode.categories
87 categoryContainer = $('category', content)
88 # `data-` attributes are currently unused by VimFx, but provide a great
89 # way to customize the help dialog with custom CSS.
90 utils.setAttributes(categoryContainer, {
91 'data-mode': mode._name
92 'data-category': category._name
93 })
94
95 # Append the mode heading inside the first category container, rather than
96 # before it, for layout purposes.
97 if index == 0
98 categoryContainer.appendChild(modeHeading)
99 categoryContainer.classList.add('first')
100
101 $('heading-category', categoryContainer, category.name) if category.name
102
103 for {command, name, enabledSequences} in category.commands
104 commandContainer = $('command', categoryContainer)
105 utils.setAttributes(commandContainer, {'data-command': command.name})
106 commandContainer.setAttribute('data-command', name)
107 for sequence in enabledSequences
108 keySequence = $('key-sequence', commandContainer)
109 [specialKeys, rest] = splitSequence(sequence, vimfx.SPECIAL_KEYS)
110 $('key-sequence-special-keys', keySequence, specialKeys)
111 $('key-sequence-rest', keySequence, rest)
112 $('description', commandContainer, command.description())
113
114 return content
115
116 splitSequence = (sequence, specialKeys) ->
117 specialKeyEnds = specialKeys.map((key) ->
118 pos = sequence.lastIndexOf(key)
119 return if pos == -1 then 0 else pos + key.length
120 )
121 splitPos = Math.max(specialKeyEnds...)
122 return [sequence[0...splitPos], sequence[splitPos..]]
123
124 module.exports = {
125 injectHelp
126 removeHelp
127 }
Imprint / Impressum