M _static/addon/background.js +18 -9
@@ 1,15 1,19 @@
+;(function () {
'use strict'
-// es6
/* Manual tests:
-- Open 2 windows. Toggle in one window should not affect the other.
+- Open 2 windows. Toggle in one window should affect the other only if they are on same domain.
- Open preferences, change whitelist. All windows should reflect changes (icons and prefs).
*/
+function whitelisted(tab) { return settings.whitelist.includes(domain(tab.url)) }
+
function updateIcon(tab) {
- const enabled = ! settings.whitelist.includes(domain(tab.url))
+ // I'm guessing tab.url case-folds and normalizes the same way as HTMLAnchorElement.href,
+ // but would be nice if I could find documentation to that effect.
+ const enabled = ! whitelisted(tab)
browser.browserAction.setIcon({
// tabId is an unfortunate name. Because there's only one of these buttons browser per
// window, not per tab, it only comes into play when you have multiple windows
@@ 34,14 38,17 @@ function updateIcon(tab) {
}
function updateLocation () {
browser.tabs.query({active: true})
- // I'm guessing tabs[0].url case-folds and normalizes the same way as HTMLAnchorElement.href,
- // but would be nice if I could find documentation to that effect.
- .then(
- tabs => { for (const k in tabs) { updateIcon(tabs[k]) } },
- error => { throw error })
+ // Only the focused window receives tab update and activated events, so need to enumerate
+ // active tabs in all open windows so that the icon state reflects the change
+ .then(tabs => {
+ for (let t of tabs) {
+ updateIcon(t)
+ // No need to filter this message to active tabs, but this is simplest
+ browser.tabs.sendMessage(t.id, whitelisted(t))
+ }})
}
updateLocation()
-// Copying the example https://github.com/mdn/webextensions-examples/tree/master/bookmark-it,
+// Copying the example https://github.com/mdn/webextensions-examples/tree/master/bookmark-it
browser.tabs.onUpdated.addListener(updateLocation) // url changes
browser.tabs.onActivated.addListener(updateLocation) // tab switching
onSettingsChange(updateLocation)
@@ 64,3 71,5 @@ browser.browserAction.onClicked.addListe
}
browser.storage.local.set(settings) // triggers icon state update via prefs listeners
})
+
+})()
M _static/addon/manifest.json +1 -4
@@ 22,10 22,7 @@
"content_scripts": [
{
"all_frames": true,
- "js": [
- "shared.js",
- "savior.js"
- ],
+ "js": ["savior.js"],
"matches": [
"<all_urls>"
],
M _static/addon/savior.js +12 -4
@@ 1,14 1,20 @@
+;(function () {
'use strict'
-// es6
const inputWhitelist = ["text","number","password","search","email","tel","url"]
-// todo: don't allow enter key on most textual inputs
+// Maintain a whitelisted toggle in sync from background script since checking
+// `window.top.location.hostname` fails for cross-domain iframes:
+let whitelisted = false
+browser.runtime.onMessage.addListener(w =>
+ // Though I haven't found documentation to this effect, empirically, it seems that messages
+ // don't cross to other addons, so no need to filter.
+ whitelisted = w)
+
function saveKeys(keyEvent) {
const _ = keyEvent.target
- // Domains normalized at save time, assume window.location.hostname is normalized same way:
- const allow = settings.whitelist.includes(window.location.hostname)
+ const allow = whitelisted
|| keyEvent.key === 'Escape'
|| _.isContentEditable
|| document.fullscreen || document.mozFullScreen
@@ 23,3 29,5 @@ function saveKeys(keyEvent) {
window.addEventListener('keydown', saveKeys, true)
window.addEventListener('keypress', saveKeys, true)
window.addEventListener('keyup', saveKeys, true)
+
+})()
M _static/test.html +11 -3
@@ 171,15 171,23 @@ pointerTrap.onclick = function () {
<h2>Iframe</h2>
-<p>To test cross-domain iframes, this page needs to be published somewhere, such as <a href="http://keyboard-savior-xtreme.readthedocs.io/en/latest/_static/test.html">http://keyboard-savior-xtreme.readthedocs.io/en/latest/_static/test.html</a>, then loaded while hosting this test page on <a href="http://localhost:8000/_static/test.html">http://localhost:8000/_static/test.html</a>.
+<p>To test cross-domain iframes, access this page from somewhere like 127.0.0.1 or <a href="http://keyboard-savior-xtreme.readthedocs.io/en/latest/_static/test.html">http://keyboard-savior-xtreme.readthedocs.io/en/latest/_static/test.html</a>, while hosting it on <a href="http://localhost:8000/_static/test.html">http://localhost:8000/_static/test.html</a>.
+
+If set up correctly, the "top location" displayed in the iframe should show a cross-origin security error.
+
+Whitelisting the top-level domain should also allow the embedded page to capture keyboard events.
</p>
<script>
'use strict'
document.write('<p>my location: ' + window.location + '</p>')
-document.write('<p>top location: ' + window.top.location + '</p>')
+try {
+ document.write('<p>top location: ' + window.top.location + '</p>')
+} catch (e) {
+ document.write('<p>top location: ' + e + '</p>')
+}
if (window.location.hostname !== 'localhost') {
- document.write('<iframe src="http://localhost:8000/_static/test.html"></iframe>')
+ document.write('<iframe width=800 height=1000 src="http://localhost:8000/_static/test.html"></iframe>')
}
</script>