diff options
| author | Stephen Blott | 2014-12-20 16:46:32 +0000 |
|---|---|---|
| committer | Stephen Blott | 2014-12-20 18:01:38 +0000 |
| commit | 015f5bad3f6e4058d6bfeb8f6bf213de37464da7 (patch) | |
| tree | bc3aad28bd4cdecfaa33293ad450ab12dbb71db6 | |
| parent | b38f0111d98c80fc3a03851a045feba447cc04ea (diff) | |
| download | vimium-015f5bad3f6e4058d6bfeb8f6bf213de37464da7.tar.bz2 | |
Exclusion; allow multiple matching rules.
| -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> |
