aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--background_scripts/commands.coffee19
-rw-r--r--background_scripts/main.coffee51
-rw-r--r--content_scripts/vimium.css5
-rw-r--r--content_scripts/vimium_frontend.coffee3
-rw-r--r--pages/help_dialog.coffee83
-rw-r--r--pages/help_dialog.html23
-rw-r--r--pages/options.coffee4
7 files changed, 114 insertions, 74 deletions
diff --git a/background_scripts/commands.coffee b/background_scripts/commands.coffee
index 2d3312ea..f5a3840b 100644
--- a/background_scripts/commands.coffee
+++ b/background_scripts/commands.coffee
@@ -9,6 +9,7 @@ Commands =
Settings.postUpdateHooks["keyMappings"] = @loadKeyMappings.bind this
@loadKeyMappings Settings.get "keyMappings"
+ @prepareHelpPageData()
loadKeyMappings: (customKeyMappings) ->
@keyToCommandRegistry = {}
@@ -113,6 +114,24 @@ Commands =
delete currentMapping[key][prop] for prop in ["keySequence", "description"]
chrome.storage.local.set normalModeKeyStateMapping: keyStateMapping
+ # Build the "helpPageData" data structure which the help page needs and place it in Chrome storage. We do
+ # this on the "nextTick" because there's not need for it to be done synchronously.
+ prepareHelpPageData: ->
+ Utils.nextTick =>
+ commandToKey = {}
+ for own key, registryEntry of @keyToCommandRegistry
+ (commandToKey[registryEntry.command] ?= []).push key
+ commandGroups = {}
+ for own group, commands of @commandGroups
+ commandGroups[group] = []
+ for command in commands
+ commandGroups[group].push
+ command: command
+ description: @availableCommands[command].description
+ keys: commandToKey[command] ? []
+ advanced: command in @advancedCommands
+ chrome.storage.local.set helpPageData: commandGroups
+
# An ordered listing of all available commands, grouped by type. This is the order they will
# be shown in the help page.
commandGroups:
diff --git a/background_scripts/main.coffee b/background_scripts/main.coffee
index e57e061d..8f99cf3e 100644
--- a/background_scripts/main.coffee
+++ b/background_scripts/main.coffee
@@ -80,56 +80,6 @@ onURLChange = (details) ->
chrome.webNavigation.onHistoryStateUpdated.addListener onURLChange # history.pushState.
chrome.webNavigation.onReferenceFragmentUpdated.addListener onURLChange # Hash changed.
-# Retrieves the help dialog HTML template from a file, and populates it with the latest keybindings.
-getHelpDialogHtml = ({showUnboundCommands, showCommandNames, customTitle}) ->
- commandsToKey = {}
- for own key of Commands.keyToCommandRegistry
- command = Commands.keyToCommandRegistry[key].command
- commandsToKey[command] = (commandsToKey[command] || []).concat(key)
-
- replacementStrings =
- version: Utils.getCurrentVersion()
- title: customTitle || "Help"
- tip: if showCommandNames then "Tip: click command names to yank them to the clipboard." else " "
-
- for own group of Commands.commandGroups
- replacementStrings[group] =
- helpDialogHtmlForCommandGroup(group, commandsToKey, Commands.availableCommands,
- showUnboundCommands, showCommandNames)
-
- replacementStrings
-
-#
-# Generates HTML for a given set of commands. commandGroups are defined in commands.js
-#
-helpDialogHtmlForCommandGroup = (group, commandsToKey, availableCommands,
- showUnboundCommands, showCommandNames) ->
- html = []
- for command in Commands.commandGroups[group]
- keys = commandsToKey[command] || []
- bindings = ("<span class='vimiumHelpDialogKey'>#{Utils.escapeHtml key}</span>" for key in keys).join ", "
- if (showUnboundCommands || commandsToKey[command])
- isAdvanced = Commands.advancedCommands.indexOf(command) >= 0
- description = availableCommands[command].description
- if keys.join(", ").length < 12
- helpDialogHtmlForCommand html, isAdvanced, bindings, description, showCommandNames, command
- else
- # If the length of the bindings is too long, then we display the bindings on a separate row from the
- # description. This prevents the column alignment from becoming out of whack.
- helpDialogHtmlForCommand html, isAdvanced, bindings, "", false, ""
- helpDialogHtmlForCommand html, isAdvanced, "", description, showCommandNames, command
- html.join("\n")
-
-helpDialogHtmlForCommand = (html, isAdvanced, bindings, description, showCommandNames, command) ->
- html.push "<tr class='vimiumReset #{"advanced" if isAdvanced}'>"
- if description
- html.push "<td class='vimiumReset'>#{bindings}</td>"
- html.push "<td class='vimiumReset'></td><td class='vimiumReset vimiumHelpDescription'>", description
- html.push("(<span class='vimiumReset commandName'>#{command}</span>)") if showCommandNames
- else
- html.push "<td class='vimiumReset' colspan='3' style='text-align: left;'>", bindings
- html.push("</td></tr>")
-
# Cache "content_scripts/vimium.css" in chrome.storage.local for UI components.
do ->
req = new XMLHttpRequest()
@@ -429,7 +379,6 @@ portHandlers =
sendRequestHandlers =
runBackgroundCommand: (request) -> BackgroundCommands[request.registryEntry.command] request
- getHelpDialogHtml: getHelpDialogHtml
# getCurrentTabUrl is used by the content scripts to get their full URL, because window.location cannot help
# with Chrome-specific URLs like "view-source:http:..".
getCurrentTabUrl: ({tab}) -> tab.url
diff --git a/content_scripts/vimium.css b/content_scripts/vimium.css
index edb1ab85..3e8f65d6 100644
--- a/content_scripts/vimium.css
+++ b/content_scripts/vimium.css
@@ -243,7 +243,7 @@ div#vimiumHelpDialog td.vimiumHelpDescription {
font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;
font-size:14px;
}
-div#vimiumHelpDialog span.commandName {
+div#vimiumHelpDialog span.vimiumCopyCommandNameName {
font-style: italic;
cursor: pointer;
font-size: 12px;
@@ -275,6 +275,9 @@ div#vimiumHelpDialogFooter {
position: relative;
margin-bottom: 37px;
}
+table.helpDialogBottom {
+ width:100%;
+}
td.helpDialogBottomRight {
width:100%;
float:right;
diff --git a/content_scripts/vimium_frontend.coffee b/content_scripts/vimium_frontend.coffee
index fcca98ab..21826944 100644
--- a/content_scripts/vimium_frontend.coffee
+++ b/content_scripts/vimium_frontend.coffee
@@ -646,8 +646,7 @@ enterFindMode = ->
new FindMode()
window.showHelp = (sourceFrameId) ->
- chrome.runtime.sendMessage handler: "getHelpDialogHtml", (response) ->
- HelpDialog.toggle {sourceFrameId, html: response}
+ HelpDialog.toggle {sourceFrameId, showAllCommandDetails: false}
# If we are in the help dialog iframe, then HelpDialog is already defined with the necessary functions.
window.HelpDialog ?=
diff --git a/pages/help_dialog.coffee b/pages/help_dialog.coffee
index 28aafb4a..4ac9116b 100644
--- a/pages/help_dialog.coffee
+++ b/pages/help_dialog.coffee
@@ -1,3 +1,12 @@
+$ = (id) -> document.getElementById id
+$$ = (element, selector) -> element.querySelector selector
+
+# The ordering we show key bindings is alphanumerical, except that special keys sort to the end.
+compareKeys = (a,b) ->
+ a = a.replace "<","~"
+ b = b.replace "<", "~"
+ if a < b then -1 else if b < a then 1 else 0
+
# This overrides the HelpDialog implementation in vimium_frontend.coffee. We provide aliases for the two
# HelpDialog methods required by normalMode (isShowing() and toggle()).
HelpDialog =
@@ -20,30 +29,67 @@ HelpDialog =
chrome.runtime.sendMessage({handler: "openOptionsPageInNewTab"})
false)
document.getElementById("toggleAdvancedCommands").addEventListener("click",
- HelpDialog.toggleAdvancedCommands, false)
+ HelpDialog.toggleAdvancedCommands.bind(HelpDialog), false)
document.documentElement.addEventListener "click", (event) =>
@hide() unless @dialogElement.contains event.target
, false
- show: ({html}) ->
- for own placeholder, htmlString of html
- @dialogElement.querySelector("#help-dialog-#{placeholder}").innerHTML = htmlString
+ instantiateHtmlTemplate: (parentNode, templateId, callback) ->
+ templateContent = document.querySelector(templateId).content
+ node = document.importNode templateContent, true
+ parentNode.appendChild node
+ callback parentNode.lastElementChild
+
+ show: ({showAllCommandDetails}) ->
+ $("help-dialog-title").textContent = if showAllCommandDetails then "Command Listing" else "Help"
+ $("help-dialog-version").textContent = Utils.getCurrentVersion()
+
+ chrome.storage.local.get "helpPageData", ({helpPageData}) =>
+ for own group, commands of helpPageData
+ container = @dialogElement.querySelector("#help-dialog-#{group}")
+ container.innerHTML = ""
+ for command in commands when showAllCommandDetails or 0 < command.keys.length
+ keysElement = null
+ descriptionElement = null
+
+ useTwoRows = 12 <= command.keys.join(", ").length
+ unless useTwoRows
+ @instantiateHtmlTemplate container, "#helpDialogEntry", (element) ->
+ element.classList.add "advanced" if command.advanced
+ keysElement = descriptionElement = element
+ else
+ @instantiateHtmlTemplate container, "#helpDialogEntryBindingsOnly", (element) ->
+ element.classList.add "advanced" if command.advanced
+ keysElement = element
+ @instantiateHtmlTemplate container, "#helpDialogEntry", (element) ->
+ element.classList.add "advanced" if command.advanced
+ descriptionElement = element
+
+ $$(descriptionElement, ".vimiumHelpDescription").textContent = command.description
+
+ keysElement = $$(keysElement, ".vimiumKeyBindings")
+ lastElement = null
+ for key in command.keys.sort compareKeys
+ @instantiateHtmlTemplate keysElement, "#keysTemplate", (element) ->
+ lastElement = element
+ $$(element, ".vimiumHelpDialogKey").innerHTML = Utils.escapeHtml key
+ # And strip off the trailing ", ", if necessary.
+ lastElement.removeChild $$ lastElement, ".commaSeparator" if lastElement
- @showAdvancedCommands(@getShowAdvancedCommands())
+ if showAllCommandDetails
+ @instantiateHtmlTemplate $$(descriptionElement, ".vimiumHelpDescription"), "#commandNameTemplate", (element) ->
+ commandNameElement = $$ element, ".vimiumCopyCommandNameName"
+ commandNameElement.textContent = command.command
+ commandNameElement.title = "Click to copy \"#{command.command}\" to clipboard."
+ commandNameElement.addEventListener "click", ->
+ chrome.runtime.sendMessage handler: "copyToClipboard", data: commandNameElement.textContent
+ HUD.showForDuration("Yanked #{commandNameElement.textContent}.", 2000)
- # When command names are shown, clicking on them copies their text to the clipboard (and they can be
- # clicked with link hints).
- for element in @dialogElement.getElementsByClassName "commandName"
- do (element) ->
- element.setAttribute "role", "link"
- element.addEventListener "click", ->
- commandName = element.textContent
- chrome.runtime.sendMessage handler: "copyToClipboard", data: commandName
- HUD.showForDuration("Yanked #{commandName}.", 2000)
+ @showAdvancedCommands(@getShowAdvancedCommands())
- # "Click" the dialog element (so that it becomes scrollable).
- DomUtils.simulateClick @dialogElement
+ # "Click" the dialog element (so that it becomes scrollable).
+ DomUtils.simulateClick @dialogElement
hide: -> UIComponentServer.hide()
toggle: -> @hide()
@@ -52,10 +98,15 @@ HelpDialog =
# Advanced commands are hidden by default so they don't overwhelm new and casual users.
#
toggleAdvancedCommands: (event) ->
+ vimiumHelpDialogContainer = $ "vimiumHelpDialogContainer"
+ scrollHeightBefore = vimiumHelpDialogContainer.scrollHeight
event.preventDefault()
showAdvanced = HelpDialog.getShowAdvancedCommands()
HelpDialog.showAdvancedCommands(!showAdvanced)
Settings.set("helpDialog_showAdvancedCommands", !showAdvanced)
+ # Try to keep the "show advanced commands" button in the same scroll position.
+ scrollHeightDelta = vimiumHelpDialogContainer.scrollHeight - scrollHeightBefore
+ vimiumHelpDialogContainer.scrollTop += scrollHeightDelta if 0 < scrollHeightDelta
showAdvancedCommands: (visible) ->
document.getElementById("toggleAdvancedCommands").innerHTML =
diff --git a/pages/help_dialog.html b/pages/help_dialog.html
index c23b2ac1..7bc0d86c 100644
--- a/pages/help_dialog.html
+++ b/pages/help_dialog.html
@@ -66,7 +66,7 @@
</div>
<div>
- <table>
+ <table class="helpDialogBottom">
<tr>
<td class="helpDialogBottomLeft">
<span id="help-dialog-tip"></span>
@@ -96,5 +96,26 @@
</div>
</div>
</div>
+
+
+ <template id="helpDialogEntry">
+ <tr class="vimiumReset">
+ <td class="vimiumReset vimiumKeyBindings"></td>
+ <td class="vimiumReset"></td>
+ <td class="vimiumReset vimiumHelpDescription"></td>
+ </tr>
+ </template>
+
+ <template id="helpDialogEntryBindingsOnly">
+ <tr>
+ <td class="vimiumReset vimiumKeyBindings" colspan="3" style="text-align: left"></td>
+ </tr>
+ </template>
+
+ <template id="keysTemplate"><span><span class="vimiumHelpDialogKey"></span><span class="commaSeparator">, </span></span></template>
+
+ <template id="commandNameTemplate">
+ <span class="vimiumReset vimiumCopyCommandName">(<span class="vimiumCopyCommandNameName" role="link"></span>)</span>
+ </template>
</body>
</html>
diff --git a/pages/options.coffee b/pages/options.coffee
index 883405e6..7021322a 100644
--- a/pages/options.coffee
+++ b/pages/options.coffee
@@ -234,9 +234,7 @@ initOptionsPage = ->
event.preventDefault()
activateHelpDialog = ->
- request = showUnboundCommands: true, showCommandNames: true, customTitle: "Command Listing"
- chrome.runtime.sendMessage extend(request, handler: "getHelpDialogHtml"), (response) ->
- HelpDialog.toggle {html: response}
+ HelpDialog.toggle showAllCommandDetails: true
saveOptions = ->
Option.saveOptions()