diff options
| -rw-r--r-- | background_scripts/commands.coffee | 19 | ||||
| -rw-r--r-- | background_scripts/main.coffee | 51 | ||||
| -rw-r--r-- | content_scripts/vimium.css | 5 | ||||
| -rw-r--r-- | content_scripts/vimium_frontend.coffee | 3 | ||||
| -rw-r--r-- | pages/help_dialog.coffee | 83 | ||||
| -rw-r--r-- | pages/help_dialog.html | 23 | ||||
| -rw-r--r-- | pages/options.coffee | 4 | 
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() | 
