]> git.gir.st - VimFx.git/blob - extension/lib/help.coffee
Merge branch 'more-tab-related-commands' of https://github.com/zhuochun/VimFx into...
[VimFx.git] / extension / lib / help.coffee
1 ###
2 # Copyright Anton Khodakivskiy 2012, 2013.
3 # Copyright Simon Lydell 2013, 2014.
4 #
5 # This file is part of VimFx.
6 #
7 # VimFx is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # VimFx is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with VimFx. If not, see <http://www.gnu.org/licenses/>.
19 ###
20
21 utils = require('./utils')
22 prefs = require('./prefs')
23 _ = require('./l10n')
24
25 { classes: Cc, interfaces: Ci, utils: Cu } = Components
26
27 XULDocument = Ci.nsIDOMXULDocument
28
29 CONTAINER_ID = 'VimFxHelpDialogContainer'
30
31 # coffeelint: disable=max_line_length
32
33 removeHelp = (document) ->
34 document.getElementById(CONTAINER_ID)?.remove()
35
36 injectHelp = (document, commands) ->
37 if document.documentElement
38 removeHelp(document)
39
40 type = if document instanceof XULDocument then 'box' else 'div'
41 container = utils.createElement(document, type, {id: CONTAINER_ID})
42
43 container.appendChild(utils.parseHTML(document, helpDialogHtml(commands)))
44 for element in container.getElementsByTagName('*')
45 element.classList.add('VimFxReset')
46
47 document.documentElement.appendChild(container)
48
49 container.addEventListener('click',
50 removeHandler.bind(undefined, document, commands), false)
51 container.addEventListener('click',
52 addHandler.bind(undefined, document, commands), false)
53
54 if button = document.getElementById('VimFxClose')
55 clickHandler = (event) ->
56 event.stopPropagation()
57 event.preventDefault()
58 removeHelp(document)
59 button.addEventListener('click', clickHandler, false)
60
61 promptService = Cc['@mozilla.org/embedcomp/prompt-service;1']
62 .getService(Ci.nsIPromptService)
63
64 removeHandler = (document, commands, event) ->
65 return unless event.target.classList.contains('VimFxKeyLink')
66 event.preventDefault()
67 event.stopPropagation()
68 key = event.target.getAttribute('data-key')
69 name = event.target.getAttribute('data-command')
70 if cmd = commands.reduce(((m, v) -> if (v.name == name) then v else m), null)
71 title = _('help_remove_shortcut_title')
72 text = _('help_remove_shortcut_text')
73 if promptService.confirm(document.defaultView, title, text)
74 cmd.keys(cmd.keys().filter((a) -> a != key))
75 event.target.remove()
76
77 addHandler = (document, commands, event) ->
78 return unless event.target.classList.contains('VimFxAddShortcutLink')
79 event.preventDefault()
80 event.stopPropagation()
81 name = event.target.getAttribute('data-command')
82 if cmd = commands.reduce(((m, v) -> if (v.name == name) then v else m), null)
83 title = _('help_add_shortcut_title')
84 text = _('help_add_shortcut_text')
85 value = {value: null}
86 check = {value: null}
87 if promptService.prompt(document.defaultView, title, text, value, null, check)
88 return if value.value.length == 0
89 conflicts = getConflicts(commands, value.value)
90 if conflicts.length == 0 or overwriteCmd(document, conflicts, value.value)
91 cmd.keys(cmd.keys().concat(value.value))
92 for div in document.getElementsByClassName('VimFxKeySequence')
93 if div.getAttribute('data-command') == cmd.name
94 div.insertAdjacentHTML('beforeend', hint(cmd, value.value))
95 return
96
97 getConflicts = (commands, value) ->
98 conflicts = []
99 for command in commands
100 conflictingKeys = []
101 for key in command.keys()
102 shortest = Math.min(value.length, key.length)
103 if "#{ value },"[..shortest] == "#{ key },"[..shortest]
104 conflictingKeys.push(key)
105 if conflictingKeys.length > 0
106 conflicts.push({command, conflictingKeys})
107 return conflicts
108
109 overwriteCmd = (document, conflicts, key) ->
110 title = _('help_add_shortcut_title')
111 conflictSummary = conflicts.map((conflict) ->
112 return "#{ conflict.command.help() }: #{ conflict.conflictingKeys.join(' ') }"
113 ).join('\n')
114 text = """
115 #{ _('help_add_shortcut_text_overwrite', key) }
116
117 #{ conflictSummary }
118 """
119 if promptService.confirm(document.defaultView, title, text)
120 for { command, conflictingKeys } in conflicts
121 command.keys(command.keys().filter((key) -> key not in conflictingKeys))
122 for key in conflictingKeys
123 document.querySelector("a[data-key='#{ key }']").remove()
124 return true
125 else
126 return false
127
128 td = (text, klass = '') ->
129 """<td class="#{ klass }">#{ text }</td>"""
130
131 hint = (cmd, key) ->
132 keyDisplay = key.replace(/,/g, '')
133 """<a href="#" class="VimFxReset VimFxKeyLink" title="#{ _('help_remove_shortcut') }"
134 data-command="#{ cmd.name }" data-key="#{ key }">#{ keyDisplay }</a>"""
135
136 tr = (cmd) ->
137 hints = """
138 <div class="VimFxKeySequence" data-command="#{ cmd.name }">
139 #{ (hint(cmd, key) for key in cmd.keys()).join('\n') }
140 </div>
141 """
142 dot = '<span class="VimFxDot">&#8729;</span>'
143 a = """#{ cmd.help() }"""
144 add = """
145 <a href="#" data-command="#{ cmd.name }"
146 class="VimFxAddShortcutLink" title="#{ _('help_add_shortcut') }">&#8862;</a>
147 """
148
149 return """
150 <tr>
151 #{ td(hints) }
152 #{ td(add) }
153 #{ td(dot) }
154 #{ td(a) }
155 </tr>
156 """
157
158 table = (commands) ->
159 """
160 <table>
161 #{ (tr(cmd) for cmd in commands).join('') }
162 </table>
163 """
164
165 section = (title, commands) ->
166 """
167 <div class="VimFxSectionTitle">#{ title }</div>
168 #{ table(commands) }
169 """
170
171 helpDialogHtml = (commands) ->
172 return """
173 <div id="VimFxHelpDialog">
174 <div class="VimFxHeader">
175 <div class="VimFxTitle">
176 <span class="VimFxTitleVim">Vim</span><span class="VimFxTitleFx">Fx</span>
177 <span>#{ _('help_title') }</span>
178 </div>
179 <span class="VimFxVersion">#{ _('help_version') } #{ utils.getVersion() }</span>
180 <a class="VimFxClose" id="VimFxClose" href="#">&#10006;</a>
181 <div class="VimFxClearFix"></div>
182 <p>Did you know that you can add/remove shortucts in this dialog?</p>
183 <div class="VimFxClearFix"></div>
184 <p>Click the shortcut to remove it, and click &#8862; to add new shortcut!</p>
185 </div>
186
187 <div class="VimFxBody">
188 <div class="VimFxColumn">
189 #{ section(_('help_section_urls'), commands.filter((a) -> a.group == 'urls')) }
190 #{ section(_('help_section_nav'), commands.filter((a) -> a.group == 'nav')) }
191 </div>
192 <div class="VimFxColumn">
193 #{ section(_('help_section_tabs'), commands.filter((a) -> a.group == 'tabs')) }
194 #{ section(_('help_section_browse'), commands.filter((a) -> a.group == 'browse')) }
195 #{ section(_('help_section_misc'), commands.filter((a) -> a.group == 'misc')) }
196 </div>
197 <div class="VimFxClearFix"></div>
198 </div>
199
200 <div class="VimFxFooter">
201 <p>#{ _('help_overlapping_hints') }</p>
202 <p>
203 #{ _('help_found_bug') }
204 <a target="_blank" href="https://github.com/akhodakivskiy/VimFx/issues">
205 #{ _('help_report_bug') }
206 </a>
207 </p>
208 <p>
209 #{ _('help_enjoying') }
210 <a target="_blank" href="https://addons.mozilla.org/en-US/firefox/addon/vimfx/">
211 #{ _('help_feedback') }
212 </a>
213 </p>
214 </div>
215 </div>
216 """
217
218 exports.injectHelp = injectHelp
219 exports.removeHelp = removeHelp
Imprint / Impressum