diff options
| -rw-r--r-- | background_scripts/exclusions.coffee | 2 | ||||
| -rw-r--r-- | pages/options.coffee | 63 | ||||
| -rw-r--r-- | pages/options.css | 230 | ||||
| -rw-r--r-- | pages/options.html | 237 | ||||
| -rw-r--r-- | pages/popup.html | 115 | 
5 files changed, 340 insertions, 307 deletions
| diff --git a/background_scripts/exclusions.coffee b/background_scripts/exclusions.coffee index 2b34238b..ac0e5f20 100644 --- a/background_scripts/exclusions.coffee +++ b/background_scripts/exclusions.coffee @@ -18,6 +18,8 @@ RegexpCache =  # The exclusions are an array of such objects (because the order matters).  root.Exclusions = Exclusions = +  # Make RegexpCache, which is required on the page popup, accessible via Exclusions. +  RegexpCache: RegexpCache    rules: Settings.get("exclusionRules") diff --git a/pages/options.coffee b/pages/options.coffee index cd19fa37..776432d2 100644 --- a/pages/options.coffee +++ b/pages/options.coffee @@ -1,6 +1,6 @@ -  $ = (id) -> document.getElementById id  bgSettings = chrome.extension.getBackgroundPage().Settings +Exclusions = chrome.extension.getBackgroundPage().Exclusions  #  # Class hierarchy for various types of option. @@ -13,6 +13,7 @@ class Option    constructor: (field,enableSaveButton) ->      @field = field +    @onUpdated = enableSaveButton      @element = $(@field)      @element.addEventListener "change", enableSaveButton      @fetch() @@ -41,8 +42,10 @@ class Option    # Static method.    @saveOptions: ->      Option.all.map (option) -> option.save() -    $("saveOptions").disabled = true -    $("saveOptions").innerHTML = "No Changes" +    # These are only relevant on the options page; catch the exception on the popup page. +    try +      $("saveOptions").disabled = true +      $("saveOptions").innerHTML = "No Changes"    # Abstract method; only implemented in sub-classes.    # Populate the option's DOM element (@element) with the setting's current value. @@ -77,8 +80,8 @@ class CheckBoxOption extends Option    readValueFromElement: -> @element.checked  class ExclusionRulesOption extends Option -  constructor: (args...) -> -    super(args...) +  constructor: (field, onUpdated, @url=null) -> +    super(field, onUpdated)      $("exclusionAddButton").addEventListener "click", (event) =>        @appendRule { pattern: "", passKeys: "" }        # Focus the pattern element in the new rule. @@ -91,6 +94,16 @@ class ExclusionRulesOption extends Option      for rule in rules        @appendRule rule +    # If this is the popup page (@url is defined), then hide rules which do not match @url.  If no rules +    # match, then add a default rule. +    if @url +      haveMatch = false +      for element in @element.getElementsByClassName "exclusionRuleTemplateInstance" +        pattern = element.children[0].firstChild.value.trim() +        unless @url.match Exclusions.RegexpCache.get pattern +          element.style.display = 'none' +          haveMatch = true +    # Append a row for a new rule.    appendRule: (rule) ->      content = document.querySelector('#exclusionRuleTemplate').content @@ -100,13 +113,13 @@ class ExclusionRulesOption extends Option        element = row.querySelector ".#{field}"        element.value = rule[field]        for event in [ "input", "change" ] -        element.addEventListener event, enableSaveButton +        element.addEventListener event, @onUpdated      remove = row.querySelector ".exclusionRemoveButton"      remove.addEventListener "click", (event) =>        row = event.target.parentNode.parentNode        row.parentNode.removeChild row -      enableSaveButton() +      @onUpdated()      @element.appendChild row @@ -160,12 +173,8 @@ activateHelpDialog = ->    # Prevent the "show help" link from retaining the focus.    document.activeElement.blur() -# -# Initialization. -document.addEventListener "DOMContentLoaded", -> - -  # Populate options.  The constructor adds each new object to "Option.all". -  new type(name,enableSaveButton) for name, type of { +initOptions = -> +  options =      exclusionRules: ExclusionRulesOption      filterLinkHints: CheckBoxOption      hideHud: CheckBoxOption @@ -181,7 +190,10 @@ document.addEventListener "DOMContentLoaded", ->      searchEngines: TextOption      searchUrl: NonEmptyTextOption      userDefinedLinkHintCss: TextOption -  } + +  # Populate options.  The constructor adds each new object to "Option.all". +  for name, type of options +    new type(name,enableSaveButton)    $("saveOptions").addEventListener "click", Option.saveOptions    $("advancedOptionsLink").addEventListener "click", toggleAdvancedOptions @@ -200,3 +212,26 @@ document.addEventListener "DOMContentLoaded", ->        document.activeElement.blur() if document?.activeElement?.blur        Option.saveOptions() +initPopup = -> +  chrome.tabs.getSelected null, (tab) -> +    document.getElementById("optionsLink").setAttribute "href", chrome.runtime.getURL("pages/options.html") +    updated = false + +    onUpdated = -> +      $("helpText").innerHTML = "Type <strong>Ctrl-Enter</strong> to save and close; <strong>Esc</strong> to cancel." +      updated = true + +    document.addEventListener "keyup", (event) -> +      if event.ctrlKey and event.keyCode == 13 +        Option.saveOptions() +        window.close() + +    new ExclusionRulesOption("exclusionRules", onUpdated, tab.url) + +# +# Initialization. +document.addEventListener "DOMContentLoaded", -> +  switch location.pathname +    when "/pages/options.html" then initOptions() +    when "/pages/popup.html" then initPopup() + diff --git a/pages/options.css b/pages/options.css new file mode 100644 index 00000000..148d1330 --- /dev/null +++ b/pages/options.css @@ -0,0 +1,230 @@ +body { +  font: 14px "DejaVu Sans", "Arial", sans-serif; +  color: #303942; +  margin: 0 auto; +} +a, a:visited { color: #15c; } +a:active { color: #052577; } +div#wrapper, #footerWrapper { +  width: 540px; +  margin-left: 35px; +} +header { +  font-size: 18px; +  font-weight: normal; +  border-bottom: 1px solid #eee; +  padding: 20px 0 15px 0; +  width: 100%; +} +button { +  -webkit-user-select: none; +  -webkit-appearance: none; +  background-image: -webkit-linear-gradient(#ededed, #ededed 38%, #dedede); +  border: 1px solid rgba(0, 0, 0, 0.25); +  border-radius: 2px; +  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.75); +  color: #444; +  font: inherit; +  text-shadow: 0 1px 0 #f0f0f0; +  height: 24px; +  font-size: 12px; +  padding: 0 10px; +} +button:hover { +  background-image: -webkit-linear-gradient(#f0f0f0, #f0f0f0 38%, #e0e0e0); +  border-color: rgba(0, 0, 0, 0.3); +  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.12), inset 0 1px 2px rgba(255, 255, 255, 0.95); +  color: black; +} +button:active { +  background-image: -webkit-linear-gradient(#e7e7e7, #e7e7e7 38%, #d7d7d7); +  box-shadow: none; +  text-shadow: none; +} +button[disabled], button[disabled]:hover, button[disabled]:active { +  background-image: -webkit-linear-gradient(#ededed, #ededed 38%, #dedede); +  border: 1px solid rgba(0, 0, 0, 0.25); +  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.75); +  text-shadow: 0 1px 0 #f0f0f0; +  color: #888; +} +input[type="checkbox"] { +  -webkit-user-select: none; +} +label:hover { +  color: black; +} +pre, code, .code { +  font-family: Consolas, "Liberation Mono", Courier, monospace; +} +pre { +  margin: 5px; +  border-left: 1px solid #eee; +  padding-left: 5px; + +} +input, textarea { +  box-sizing: border-box; +} +textarea { +  /* Horizontal resizing is pretty screwy-looking. */ +  resize: vertical; +} +table#options{ +  width: 100%; +  font-size: 14px; +  position: relative; +  border-spacing: 0 23px; +} +.example { +  font-size: 12px; +  line-height: 16px; +  color: #979ca0; +  margin-left: 20px; +} +.info { +  margin-left: 0px; +} +.caption { +  margin-right: 10px; +  min-width: 130px; +  padding-top: 3px; +  vertical-align: top; +} +td { padding: 0; } +div#exampleKeyMapping { +  margin-left: 10px; +  margin-top: 5px; +} +input#linkHintCharacters { +  width: 100%; +} +input#linkHintNumbers { +  width: 100%; +} +input#linkHintCharacters { +  width: 100%; +} +input#scrollStepSize { +  width: 40px; +  margin-right: 3px; +} +textarea#userDefinedLinkHintCss, textarea#keyMappings, textarea#searchEngines { +  width: 100%;; +  min-height: 130px; +  white-space: nowrap; +} +input#previousPatterns, input#nextPatterns { +  width: 100%; +} +input#newTabUrl { +  width: 100%; +} +input#searchUrl { +  width: 100%; +} +#status { +  margin-left: 10px; +  font-size: 80%; +} +/* Make the caption in the settings table as small as possible, to pull the other fields to the right. */ +.caption { +  width: 1px; +  white-space: nowrap; +} +#buttonsPanel { width: 100%; } +#advancedOptions { display: none; } +#advancedOptionsLink { line-height: 24px; } +.help { +  position: absolute; +  right: -320px; +  width: 320px; +} +input:read-only { +  background-color: #eee; +  color: #666; +  pointer-events: none; +  -webkit-user-select: none; +} +input[type="text"], textarea { +  border: 1px solid #bfbfbf; +  border-radius: 2px; +  color: #444; +  font: inherit; +  padding: 3px; +} +button:focus, input[type="text"]:focus, textarea:focus { +  -webkit-transition: border-color 200ms; +  border-color: #4d90fe; +  outline: none; +} +/* Boolean options have a tighter form representation than text options. */ +td.booleanOption { font-size: 12px; } +/* Ids and classes for rendering exclusionRules */ +#exclusionScrollBox { +  overflow: scroll; +  overflow-x: hidden; +  overflow-y: auto; +  /* Each exclusion rule is about 30px, so this allows 7 before scrolling */ +  max-height: 215px; +  min-height: 75px; +  border-radius: 2px; +  color: #444; +  width: 100% +} +#exclusionRules { +  width: 100%; +} +.exclusionRulePassKeys { +  width: 33%; +} +.exclusionRemoveButton { +  width: 1px; /* 1px; smaller than the button itself. */ +} +.exclusionRemoveButtonButton { +  border: none; +  background-color: #fff; +  color: #979ca0; +} +.exclusionRemoveButtonButton:hover { +  color: #444; +} +input.pattern, input.passKeys, .exclusionHeaderText { +  width: 100%; +  font-family: Consolas, "Liberation Mono", Courier, monospace; +  font-size: 14px; +} +.exclusionHeaderText { +  padding-left: 3px; +  color: #979ca0; +} +#exclusionAddButton { +  float: right; +  margin-right: 0px; +  margin-top: 5px; +} +#footer { +  background: #f5f5f5; +  border-top: 1px solid #979ca0; +  position: fixed; +  bottom: 0px; +  z-index: 10; +} +#footer, #footerTable, #footerTableData { +  width: 100%; +} +#endSpace { +  /* Leave space for the fixed footer. */ +  min-height: 30px; +  max-height: 30px; +} +#helpText { +  font-size: 12px; +} +#saveOptionsTableData { +  float: right; +} +#saveOptions { +  white-space: nowrap; +  width: 110px; +} diff --git a/pages/options.html b/pages/options.html index 8e685304..03016d3f 100644 --- a/pages/options.html +++ b/pages/options.html @@ -1,242 +1,9 @@  <html>    <head>      <title>Vimium Options</title> +    <link rel="stylesheet" type="text/css" href="options.css">      <script src="content_script_loader.js"></script> -    <style type="text/css" media="screen"> -      body { -        font: 14px "DejaVu Sans", "Arial", sans-serif; -        color: #303942; -        margin: 0 auto; -      } -      a, a:visited { color: #15c; } -      a:active { color: #052577; } -      div#wrapper, #footerWrapper { -        width: 540px; -        margin-left: 35px; -      } -      header { -        font-size: 18px; -        font-weight: normal; -        border-bottom: 1px solid #eee; -        padding: 20px 0 15px 0; -        width: 100%; -      } -      button { -        -webkit-user-select: none; -        -webkit-appearance: none; -        background-image: -webkit-linear-gradient(#ededed, #ededed 38%, #dedede); -        border: 1px solid rgba(0, 0, 0, 0.25); -        border-radius: 2px; -        box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.75); -        color: #444; -        font: inherit; -        text-shadow: 0 1px 0 #f0f0f0; -        height: 24px; -        font-size: 12px; -        padding: 0 10px; -      } -      button:hover { -        background-image: -webkit-linear-gradient(#f0f0f0, #f0f0f0 38%, #e0e0e0); -        border-color: rgba(0, 0, 0, 0.3); -        box-shadow: 0 1px 0 rgba(0, 0, 0, 0.12), inset 0 1px 2px rgba(255, 255, 255, 0.95); -        color: black; -      } -      button:active { -        background-image: -webkit-linear-gradient(#e7e7e7, #e7e7e7 38%, #d7d7d7); -        box-shadow: none; -        text-shadow: none; -      } -      button[disabled], button[disabled]:hover, button[disabled]:active { -        background-image: -webkit-linear-gradient(#ededed, #ededed 38%, #dedede); -        border: 1px solid rgba(0, 0, 0, 0.25); -        box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08), inset 0 1px 2px rgba(255, 255, 255, 0.75); -        text-shadow: 0 1px 0 #f0f0f0; -        color: #888; -      } -      input[type="checkbox"] { -        -webkit-user-select: none; -      } -      label:hover { -        color: black; -      } -      pre, code, .code { -        font-family: Consolas, "Liberation Mono", Courier, monospace; -      } -      pre { -        margin: 5px; -        border-left: 1px solid #eee; -        padding-left: 5px; - -      } -      input, textarea { -        box-sizing: border-box; -      } -      textarea { -        /* Horizontal resizing is pretty screwy-looking. */ -        resize: vertical; -      } -      table#options{ -        width: 100%; -        font-size: 14px; -        position: relative; -        border-spacing: 0 23px; -      } -      .example { -        font-size: 12px; -        line-height: 16px; -        color: #979ca0; -        margin-left: 20px; -      } -      .info { -        margin-left: 0px; -      } -      .caption { -        margin-right: 10px; -        min-width: 130px; -        padding-top: 3px; -        vertical-align: top; -      } -      td { padding: 0; } -      div#exampleKeyMapping { -        margin-left: 10px; -        margin-top: 5px; -      } -      input#linkHintCharacters { -        width: 100%; -      } -      input#linkHintNumbers { -        width: 100%; -      } -      input#linkHintCharacters { -        width: 100%; -      } -      input#scrollStepSize { -        width: 40px; -        margin-right: 3px; -      } -      textarea#userDefinedLinkHintCss, textarea#keyMappings, textarea#searchEngines { -        width: 100%;; -        min-height: 130px; -        white-space: nowrap; -      } -      input#previousPatterns, input#nextPatterns { -        width: 100%; -      } -      input#newTabUrl { -        width: 100%; -      } -      input#searchUrl { -        width: 100%; -      } -      #status { -        margin-left: 10px; -        font-size: 80%; -      } -      /* Make the caption in the settings table as small as possible, to pull the other fields to the right. */ -      .caption { -        width: 1px; -        white-space: nowrap; -      } -      #buttonsPanel { width: 100%; } -      #advancedOptions { display: none; } -      #advancedOptionsLink { line-height: 24px; } -      .help { -        position: absolute; -        right: -320px; -        width: 320px; -      } -      input:read-only { -        background-color: #eee; -        color: #666; -        pointer-events: none; -        -webkit-user-select: none; -      } -      input[type="text"], textarea { -        border: 1px solid #bfbfbf; -        border-radius: 2px; -        color: #444; -        font: inherit; -        padding: 3px; -      } -      button:focus, input[type="text"]:focus, textarea:focus { -        -webkit-transition: border-color 200ms; -        border-color: #4d90fe; -        outline: none; -      } -      /* Boolean options have a tighter form representation than text options. */ -      td.booleanOption { font-size: 12px; } -      /* Ids and classes for rendering exclusionRules */ -      #exclusionScrollBox { -        overflow: scroll; -        overflow-x: hidden; -        overflow-y: auto; -        /* Each exclusion rule is about 30px, so this allows 7 before scrolling */ -        max-height: 215px; -        min-height: 75px; -        border-radius: 2px; -        color: #444; -        width: 100% -      } -      #exclusionRules { -        width: 100%; -      } -      .exclusionRulePassKeys { -        width: 33%; -      } -      .exclusionRemoveButton { -        width: 1px; /* 1px; smaller than the button itself. */ -      } -      .exclusionRemoveButtonButton { -        border: none; -        background-color: #fff; -        color: #979ca0; -      } -      .exclusionRemoveButtonButton:hover { -        color: #444; -      } -      input.pattern, input.passKeys, .exclusionHeaderText { -        width: 100%; -        font-family: Consolas, "Liberation Mono", Courier, monospace; -        font-size: 14px; -      } -      .exclusionHeaderText { -        padding-left: 3px; -        color: #979ca0; -      } -      #exclusionAddButton { -        float: right; -        margin-right: 0px; -        margin-top: 5px; -      } -      #footer { -        background: #f5f5f5; -        border-top: 1px solid #979ca0; -        position: fixed; -        bottom: 0px; -        z-index: 10; -      } -      #footer, #footerTable, #footerTableData { -        width: 100%; -      } -      #endSpace { -        /* Leave space for the fixed footer. */ -        min-height: 30px; -        max-height: 30px; -      } -      #helpText { -        font-size: 12px; -      } -      #saveOptionsTableData { -        float: right; -      } -      #saveOptions { -        white-space: nowrap; -        width: 110px; -      } -    </style> - -  <script type="text/javascript" src="options.js"></script> - +    <script type="text/javascript" src="options.js"></script>    </head>    <body> diff --git a/pages/popup.html b/pages/popup.html index 775d6c07..726ecc3f 100644 --- a/pages/popup.html +++ b/pages/popup.html @@ -1,85 +1,84 @@  <html>    <head> +    <link rel="stylesheet" type="text/css" href="options.css">      <style>        * {          margin: 0px;          padding: 0px;        } -      #vimiumPopup { width: 400px; } - -      #excludeControls { -        padding: 10px; +      #endSpace { +        width: 450px;        } -      #popupPattern, #popupPassKeys { -        margin: 5px; -        width: 330px; -        /* Match the corresponding font and font size used on the options page. */ -        /* TODO (smblott): Match other styles from the options page. */ -        font-family: Consolas, "Liberation Mono", Courier, monospace; -        font-size: 14px; +      #helpText, #optionsLink { +        font-family : "Helvetica Neue", "Helvetica", "Arial", sans-serif; +        font-size: 12px;        } -      #confirmationMessage { -        display: inline-block; -        width: 18px; -        height: 13px; -        background: url(icons/check.png) 3px 2px no-repeat; -        display: none; +      #helpText { +        color: #979ca0;        } -      #popupRemove { margin: 5px; } -      #popupExclude { margin: 5px; } - -      #popupMenu ul { -        list-style: none; +      #exclusionAddButton { +        width: 80px;        } -      #popupMenu li, #popupMenu a:active, #popupMenu a:visited { -        color: #3F6EC2; -        display: block; -        border-top: 1px solid #DDDDDD; -        padding: 3px; -        padding-left: 10px; -      } +      /* Styles overwridden or changed from options.css. */ -      #popupMenu a:hover { -        background: #EEEEEE; +      #footerWrapper { +        width: 450px; /* As for #endSpace */ +        margin-left: 0px;        } -      #optionsLink { -        font-family : "Helvetica Neue", "Helvetica", "Arial", sans-serif; -        font-size: 12px; -        float: right; -      } -      #helpText { -        color: #979ca0; -        font-family : "Helvetica Neue", "Helvetica", "Arial", sans-serif; -        font-size: 12px; -        float: left; -        display: none; +      #endSpace { +        /* Leave space for the fixed footer. */ +        min-height: 36px; +        max-height: 36px;        } +      </style> -    <script src="popup.js"></script> +    <script src="options.js"></script>    </head>    <body> -    <div id="vimiumPopup"> -      <div id="excludeControls"> -        <input id="popupPattern" placeholder="Pattern against which to match URLs..." type="text" /><br/> -        <input id="popupPassKeys" placeholder="Only exclude these keys..." type="text" /><br/> -        <input id="popupRemove" type="button" value="Remove Rule" /> -        <input id="popupExclude" type="button" value="Add or Update Rule" /> -        <span id="confirmationMessage">Text is added in popup.coffee.</span> -      </div> +    <!-- Copied (almost) directly from options.html - start --> +    <div id="exclusionScrollBox"> +       <table id="exclusionRules"> +          <tr> +             <td><span class="exclusionHeaderText">URL Patterns</span></td> +             <td><span class="exclusionHeaderText">Excluded Keys</span></td> +          </tr> +       </table> +       <template id="exclusionRuleTemplate"> +          <tr class="exclusionRuleTemplateInstance"> +             <td><input/ type="text" class="pattern" placeholder="URL pattern"></td> +             <td class="exclusionRulePassKeys"><input/ type="text" class="passKeys" placeholder="Excluded keys"></td> +             <td class="exclusionRemoveButton"> +               <input/ type="button" tabindex = "-1" class="exclusionRemoveButtonButton" value="✖"></td> +          </tr> +       </template> +    </div> +    <!-- Copied (almost) directly from options.html - end --> + +    <!-- Some extra space which is hidden underneath the footer. --> +    <div id="endSpace"/> -      <div id="popupMenu"> -        <ul> -          <li> -             <span id="helpText">Type <strong>Ctrl-Enter</strong> to save and close.</span> -             <a id="optionsLink" target="_blank">Options</a> -          </li> -        </ul> +    <div id="footer"> +      <div id="footerWrapper"> +        <table id="footerTable"> +          <tr> +            <td id="footerTableData"> +              <span> +                <span id="helpText">These are the matching exclusion rules for this page.</span> +                <br/> +                <span> <a id="optionsLink" target="_blank">Vimium Options</a>.</span> +              </span> +            </td> +            <td> +              <button id="exclusionAddButton">Add Rule</button> +            </td> +          </tr> +        </table>        </div>      </div>    </body> | 
