diff options
| author | Stephen Blott | 2016-12-11 14:18:59 +0000 | 
|---|---|---|
| committer | Stephen Blott | 2016-12-11 14:52:21 +0000 | 
| commit | cc09af6921228033b822ef4ad4713abd26c375e7 (patch) | |
| tree | f75eb8c6a6108897571b2c1884b4f39e5382a55a | |
| parent | 1664a02c02be27a824b19633740a23ec01573c77 (diff) | |
| download | vimium-cc09af6921228033b822ef4ad4713abd26c375e7.tar.bz2 | |
Rework help-dialog HTML.
Previously, the dynamic HTML for the help dialog was generated on the
background page.  The HTML itself was tangled in with program logic.
Here, we move all of the HTML to HTML5 templates; also, we build the
help-dialog contents in the help dialog itself, not on the background
page.
Note: #2368 is included here too.
(Background: I'm trying to clean up some of the command and help-dialog
logic in preparation for addressing the issue of how to document command
options, see #2319.)
| -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() | 
