2 # Copyright Anton Khodakivskiy 2012, 2013, 2014.
3 # Copyright Simon Lydell 2013, 2014.
5 # This file is part of VimFx.
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.
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.
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/>.
22 , setPref } = require 'prefs'
23 { injectHelp } = require 'help'
24 { commands } = require 'commands'
25 utils = require 'utils'
26 { unloader } = require 'unloader'
27 { _ } = require 'l10n'
29 KEYSET_ID = 'vimfx-keyset'
30 BUTTON_ID = 'vimfx-toolbar-button'
32 MENUPOPUP_ID = 'vimfx-menupopup'
33 MENU_ITEM_PREF = 'vimfx-menu-item-preferences'
34 MENU_ITEM_HELP = 'vimfx-menu-item-help'
35 TEXTBOX_BLACKLIST_ID = 'vimfx-textbox-blacklist-id'
36 BUTTON_BLACKLIST_ID = 'vimfx-button-blacklist-id'
38 $ = (document, selector) -> document.getElementById(selector)
39 $$ = (document, selector) -> document.querySelectorAll(selector)
43 setButtonInstallPosition = (toolbarId, beforeId) ->
44 positions[BUTTON_ID] = {toolbarId, beforeId}
46 addToolbarButton = (vimBucket, window) ->
47 document = window.document
48 win = document.querySelector('window')
50 [ button, keyset ] = createButton(vimBucket, window)
52 # Namespace to put the VimFx state on, for example.
55 restorePosition(document, button)
57 if tabWindow = utils.getCurrentTabWindow(window)
58 blacklisted = utils.isBlacklisted(tabWindow.location.href)
59 disabled = getPref('disabled')
60 updateToolbarButton(window, {disabled, blacklisted})
62 win.appendChild(keyset)
67 $(document, 'navigator-toolbox').palette.removeChild(button)
70 createButton = (vimBucket, window) ->
71 document = window.document
73 button = utils.createElement(document, 'toolbarbutton', {
77 class: 'toolbarbutton-1'
80 menupopup = createMenupopup(window, button)
82 onButtonCommand = (event) ->
84 when button.VimFx.blacklisted
85 menupopup.openPopup(button, 'after_start')
86 when button.VimFx.insertMode
87 return unless currentTabWindow = utils.getEventCurrentTabWindow(event)
88 return unless vim = vimBucket.get(currentTabWindow)
89 updateToolbarButton(window, {insertMode: false})
90 vim.enterMode('normal')
92 disabled = not getPref('disabled')
93 setPref('disabled', disabled)
94 updateToolbarButton(window, {disabled})
96 event.stopPropagation()
98 button.addEventListener('command', onButtonCommand, false)
100 vimkey = utils.createElement(document, 'key', {
103 modifiers: 'shift,alt'
104 oncommand: 'void(0);'
106 vimkey.addEventListener('command', onButtonCommand, false)
108 keyset = utils.createElement(document, 'keyset', {id: KEYSET_ID})
109 keyset.appendChild(vimkey)
111 return [button, keyset]
113 createMenupopup = (window, button) ->
114 document = window.document
116 blacklistTextbox = utils.createElement(document, 'textbox', {
117 id: TEXTBOX_BLACKLIST_ID
119 blacklistButton = utils.createElement(document, 'toolbarbutton', {
120 id: BUTTON_BLACKLIST_ID
121 class: 'toolbarbutton-1'
123 blacklistControls = utils.createElement(document, 'hbox')
124 blacklistControls.appendChild(blacklistTextbox)
125 blacklistControls.appendChild(blacklistButton)
127 itemPreferences = utils.createElement(document, 'menuitem', {
129 label: _('item_preferences')
132 itemHelp = utils.createElement(document, 'menuitem', {
134 label: _('help_title')
137 menupopup = utils.createElement(document, 'menupopup', {
141 menupopup.appendChild(blacklistControls)
142 menupopup.appendChild(itemPreferences)
143 menupopup.appendChild(itemHelp)
145 onPopupShowing = (event) ->
146 return unless tabWindow = utils.getCurrentTabWindow(window)
148 if button.VimFx.blacklisted
149 matchingRules = utils.getMatchingBlacklistRules(tabWindow.location.href)
150 blacklistTextbox.value = matchingRules.join(', ')
151 blacklistTextbox.setAttribute('readonly', true)
152 blacklistButton.setAttribute('tooltiptext',
153 _('item_blacklist_button_inverse_tooltip'))
154 blacklistButton.style.listStyleImage = iconUrl('blacklist_inverse')
156 blacklistTextbox.value =
157 # In `about:` pages, the `host` property is an empty string. Fall back
159 if tabWindow.location.host != ''
160 "*#{ tabWindow.location.host }*"
162 tabWindow.location.href
163 blacklistTextbox.removeAttribute('readonly')
164 blacklistButton.setAttribute('tooltiptext',
165 _('item_blacklist_button_tooltip'))
166 blacklistButton.style.listStyleImage = iconUrl('blacklist')
168 onBlacklistButtonCommand = (event) ->
169 return unless tabWindow = utils.getCurrentTabWindow(window)
171 if button.VimFx.blacklisted
172 utils.updateBlacklist({remove: blacklistTextbox.value})
174 utils.updateBlacklist({add: blacklistTextbox.value})
176 menupopup.hidePopup()
178 tabWindow.location.reload(false)
180 event.stopPropagation()
182 onPreferencesCommand = (event) ->
183 id = encodeURIComponent(utils.ADDON_ID)
184 window.BrowserOpenAddonsMgr("addons://detail/#{ id }/preferences")
186 event.stopPropagation()
188 onHelpCommand = (event) ->
189 if tabWindow = utils.getCurrentTabWindow(window)
190 injectHelp(tabWindow.document, commands)
192 event.stopPropagation()
194 menupopup.addEventListener('popupshowing', onPopupShowing, false)
195 blacklistButton.addEventListener('command', onBlacklistButtonCommand, false)
196 itemPreferences.addEventListener('command', onPreferencesCommand, false)
197 itemHelp.addEventListener('command', onHelpCommand, false)
199 button.appendChild(menupopup)
202 restorePosition = (document, button) ->
203 $(document, 'navigator-toolbox').palette.appendChild(button)
205 for tb in $$(document, 'toolbar')
206 currentset = tb.getAttribute('currentset').split(',')
207 idx = currentset.indexOf(button.id)
212 # Saved position not found, using the default one, after persisting it.
213 if not toolbar and button.id of positions
214 { toolbarId, beforeId } = positions[button.id]
215 if toolbar = $(document, toolbarId)
216 [ currentset, idx ] = persist(document, toolbar, button.id, beforeId)
218 if toolbar and idx != -1
219 # Inserting the button before the first item in `currentset`
220 # after `idx` that is present in the document.
221 for id in currentset[idx+1..]
222 if before = $(document, id)
223 toolbar.insertItem(button.id, before)
226 toolbar.insertItem(button.id)
228 persist = (document, toolbar, buttonId, beforeId) ->
229 currentset = toolbar.currentSet.split(',')
230 idx = if beforeId then currentset.indexOf(beforeId) else -1
232 currentset.splice(idx, 0, buttonId)
234 currentset.push(buttonId)
236 toolbar.setAttribute('currentset', currentset.join(','))
237 document.persist(toolbar.id, 'currentset')
238 return [currentset, idx]
240 updateToolbarButton = (window, { disabled, blacklisted, insertMode }) ->
241 return unless button = $(window.document, BUTTON_ID)
243 button.VimFx.disabled = disabled if disabled?
244 button.VimFx.blacklisted = blacklisted if blacklisted?
245 button.VimFx.insertMode = insertMode if insertMode?
247 [ icon, tooltip ] = switch
248 when button.VimFx.disabled
250 when button.VimFx.blacklisted
251 ['red', 'blacklisted']
252 when button.VimFx.insertMode
253 ['grey', 'insertMode']
255 ['normal', 'enabled']
257 button.style.listStyleImage = iconUrl(icon)
258 button.setAttribute('tooltiptext', _("button_tooltip_#{ tooltip }"))
261 url = utils.getResourceURI("resources/icon16-#{ kind }.png").spec
262 return "url(#{ url })"
264 exports.setButtonInstallPosition = setButtonInstallPosition
265 exports.addToolbarButton = addToolbarButton
266 exports.updateToolbarButton = updateToolbarButton