]> git.gir.st - VimFx.git/blob - extension/packages/help.coffee
Generate install.rdf and chrome.manifest
[VimFx.git] / extension / packages / 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 removeHelp = (document) ->
32 document.getElementById(CONTAINER_ID)?.remove()
33
34 injectHelp = (document, commands) ->
35 if document.documentElement
36 removeHelp(document)
37
38 type = if document instanceof XULDocument then 'box' else 'div'
39 container = utils.createElement(document, type, {id: CONTAINER_ID})
40
41 container.appendChild(utils.parseHTML(document, helpDialogHtml(commands)))
42 for element in container.getElementsByTagName('*')
43 element.classList.add('VimFxReset')
44
45 document.documentElement.appendChild(container)
46
47 container.addEventListener('click',
48 removeHandler.bind(undefined, document, commands), false)
49 container.addEventListener('click',
50 addHandler.bind(undefined, document, commands), false)
51
52 if button = document.getElementById('VimFxClose')
53 clickHandler = (event) ->
54 event.stopPropagation()
55 event.preventDefault()
56 removeHelp(document)
57 button.addEventListener('click', clickHandler, false)
58
59 promptService = Cc['@mozilla.org/embedcomp/prompt-service;1']
60 .getService(Ci.nsIPromptService)
61
62 removeHandler = (document, commands, event) ->
63 return unless event.target.classList.contains('VimFxKeyLink')
64 event.preventDefault()
65 event.stopPropagation()
66 key = event.target.getAttribute('data-key')
67 name = event.target.getAttribute('data-command')
68 if cmd = commands.reduce(((m, v) -> if (v.name == name) then v else m), null)
69 title = _('help_remove_shortcut_title')
70 text = _('help_remove_shortcut_text')
71 if promptService.confirm(document.defaultView, title, text)
72 cmd.keys(cmd.keys().filter((a) -> a != key))
73 event.target.remove()
74
75 addHandler = (document, commands, event) ->
76 return unless event.target.classList.contains('VimFxAddShortcutLink')
77 event.preventDefault()
78 event.stopPropagation()
79 name = event.target.getAttribute('data-command')
80 if cmd = commands.reduce(((m, v) -> if (v.name == name) then v else m), null)
81 title = _('help_add_shortcut_title')
82 text = _('help_add_shortcut_text')
83 value = {value: null}
84 check = {value: null}
85 if promptService.prompt(document.defaultView, title, text, value, null, check)
86 return if value.value.length == 0
87 conflicts = getConflicts(commands, value.value)
88 if conflicts.length == 0 or overwriteCmd(document, conflicts, value.value)
89 cmd.keys(cmd.keys().concat(value.value))
90 for div in document.getElementsByClassName('VimFxKeySequence')
91 if div.getAttribute('data-command') == cmd.name
92 div.insertAdjacentHTML('beforeend', hint(cmd, value.value))
93 return
94
95 getConflicts = (commands, value) ->
96 conflicts = []
97 for command in commands
98 conflictingKeys = []
99 for key in command.keys()
100 shortest = Math.min(value.length, key.length)
101 if "#{ value },"[..shortest] == "#{ key },"[..shortest]
102 conflictingKeys.push(key)
103 if conflictingKeys.length > 0
104 conflicts.push({command, conflictingKeys})
105 return conflicts
106
107 overwriteCmd = (document, conflicts, key) ->
108 title = _('help_add_shortcut_title')
109 conflictSummary = conflicts.map((conflict) ->
110 return "#{ conflict.command.help() }: #{ conflict.conflictingKeys.join(' ') }"
111 ).join("\n")
112 text = """
113 #{ _('help_add_shortcut_text_overwrite', key) }
114
115 #{ conflictSummary }
116 """
117 if promptService.confirm(document.defaultView, title, text)
118 for { command, conflictingKeys } in conflicts
119 command.keys(command.keys().filter((key) -> key not in conflictingKeys))
120 for key in conflictingKeys
121 document.querySelector("a[data-key='#{ key }']").remove()
122 return true
123 else
124 return false
125
126 td = (text, klass='') ->
127 """<td class="#{ klass }">#{ text }</td>"""
128
129 hint = (cmd, key) ->
130 keyDisplay = key.replace(/,/g, '')
131 """<a href="#" class="VimFxReset VimFxKeyLink" title="#{ _('help_remove_shortcut') }"
132 data-command="#{ cmd.name }" data-key="#{ key }">#{ keyDisplay }</a>"""
133
134 tr = (cmd) ->
135 hints = """
136 <div class="VimFxKeySequence" data-command="#{ cmd.name }">
137 #{ (hint(cmd, key) for key in cmd.keys()).join('\n') }
138 </div>
139 """
140 dot = """<span class="VimFxDot">&#8729;</span>"""
141 a = """#{ cmd.help() }"""
142 add = """
143 <a href="#" data-command="#{ cmd.name }"
144 class="VimFxAddShortcutLink" title="#{ _('help_add_shortcut') }">&#8862;</a>
145 """
146
147 return """
148 <tr>
149 #{ td(hints) }
150 #{ td(add) }
151 #{ td(dot) }
152 #{ td(a) }
153 </tr>
154 """
155
156 table = (commands) ->
157 """
158 <table>
159 #{ (tr(cmd) for cmd in commands).join('') }
160 </table>
161 """
162
163 section = (title, commands) ->
164 """
165 <div class="VimFxSectionTitle">#{ title }</div>
166 #{ table(commands) }
167 """
168
169 helpDialogHtml = (commands) ->
170 return """
171 <div id="VimFxHelpDialog">
172 <div class="VimFxHeader">
173 <div class="VimFxTitle">
174 <span class="VimFxTitleVim">Vim</span><span class="VimFxTitleFx">Fx</span>
175 <span>#{ _('help_title') }</span>
176 </div>
177 <span class="VimFxVersion">#{ _('help_version') } #{ utils.getVersion() }</span>
178 <a class="VimFxClose" id="VimFxClose" href="#">&#10006;</a>
179 <div class="VimFxClearFix"></div>
180 <p>Did you know that you can add/remove shortucts in this dialog?</p>
181 <div class="VimFxClearFix"></div>
182 <p>Click the shortcut to remove it, and click &#8862; to add new shortcut!</p>
183 </div>
184
185 <div class="VimFxBody">
186 <div class="VimFxColumn">
187 #{ section(_('help_section_urls'), commands.filter((a) -> a.group == 'urls')) }
188 #{ section(_('help_section_nav'), commands.filter((a) -> a.group == 'nav')) }
189 </div>
190 <div class="VimFxColumn">
191 #{ section(_('help_section_tabs'), commands.filter((a) -> a.group == 'tabs')) }
192 #{ section(_('help_section_browse'), commands.filter((a) -> a.group == 'browse')) }
193 #{ section(_('help_section_misc'), commands.filter((a) -> a.group == 'misc')) }
194 </div>
195 <div class="VimFxClearFix"></div>
196 </div>
197
198 <div class="VimFxFooter">
199 <p>#{ _('help_overlapping_hints') }</p>
200 <p>
201 #{ _('help_found_bug') }
202 <a target="_blank" href="https://github.com/akhodakivskiy/VimFx/issues">
203 #{ _('help_report_bug') }
204 </a>
205 </p>
206 <p>
207 #{ _('help_enjoying') }
208 <a target="_blank" href="https://addons.mozilla.org/en-US/firefox/addon/vimfx/">
209 #{ _('help_feedback') }
210 </a>
211 </p>
212 </div>
213 </div>
214 """
215
216 exports.injectHelp = injectHelp
217 exports.removeHelp = removeHelp
Imprint / Impressum