diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index 122702f..0000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,76 +0,0 @@
-{
- "env": {
- "browser": true
- },
-
-
- // see http://eslint.org/docs/rules/ for explanations
- "rules": {
- "no-extra-parens": 1,
- "no-regex-spaces": 1,
- "no-else-return": 1,
- "no-empty": 1,
- "no-empty-function": 1,
- "no-implicit-coercion": 1,
- "no-magic-numbers": 1,
- "no-undef": 1,
- "no-unused-vars": 1,
- "no-undef-init": 1,
- "no-shadow": [1, { "builtinGlobals": true }],
- "vars-on-top": 1,
-
- "no-constant-condition": 2,
- "no-dupe-keys": 2,
- "no-duplicate-case": 2,
- "no-ex-assign": 2,
- "no-extra-boolean-cast": 2,
- "no-func-assign": 2,
- "no-invalid-regexp": 2,
- "no-irregular-whitespace": 2,
- "no-sparse-arrays": 2,
- "no-unreachable": 2,
- "use-isnan": 2,
- "valid-typeof": 2,
- "consistent-return": 2,
- "curly": [2, "multi-line"],
- "dot-location": [2, "property"],
- "dot-notation": 2,
- "eqeqeq": 2,
- "no-eval": 2,
- "no-implied-eval": 2,
- "no-loop-func": 2,
- "no-multi-spaces": [2, { "exceptions": { "VariableDeclarator": true } }],
- "no-new-func": 2,
- "no-new-wrappers": 2,
- "no-new": 2,
- "no-octal-escape": 2,
- "no-octal": 2,
- "no-param-reassign": 2,
- "no-redeclare": [2, { "builtinGlobals": true }],
- "no-script-url": 2,
- "no-self-assign": 2,
- "no-self-compare": 2,
- "no-void": 2,
- "strict": [2, "global"],
- "radix": 2,
- "yoda": 2,
- "no-delete-var": 2,
- "no-use-before-define": 2,
- "array-bracket-spacing": [2, "never"],
- "block-spacing": [2, "never"],
- "brace-style": 2,
- "comma-spacing": [2, {"before": false, "after": true}],
- "comma-style": 2,
- "computed-property-spacing": [2, "never"],
- "func-style": [2, "declaration"],
- "no-lonely-if": 2,
- "no-mixed-spaces-and-tabs": [2, "smart-tabs"],
- "no-spaced-func": 2,
- "no-trailing-spaces": 2,
- "object-curly-spacing": [2, "never"],
- "quotes": [2, "single"],
-
- "semi": [2, "never"],
- "no-extra-semi": 2
- }
-}
diff --git a/.eslintrc.yml b/.eslintrc.yml
new file mode 100644
index 0000000..17bc8e5
--- /dev/null
+++ b/.eslintrc.yml
@@ -0,0 +1,88 @@
+extends: eslint:recommended
+
+env:
+ es6: true,
+ browser: true,
+ webextensions: true
+
+rules:
+ # warnings
+ no-control-regex: warn
+ no-ternary: warn
+ prefer-const: warn
+ prefer-template: warn
+ no-magic-numbers:
+ - warn
+ - ignoreArrayIndexes: true
+ # errors
+ yoda: error
+ radix: error
+ no-useless-return: error
+ no-useless-concat: error
+ no-unused-expressions: error
+ no-self-compare: error
+ no-script-url: error
+ no-return-assign: error
+ no-octal-escape: error
+ no-loop-func: error
+ no-lone-blocks: error
+ no-invalid-this: error
+ no-implied-eval: error
+ no-floating-decimal: error
+ no-eval: error
+ no-eq-null: error
+ no-empty-function: error
+ no-else-return: error
+ no-alert: error
+ eqeqeq: error
+ dot-notation: error
+ no-shadow: error
+ no-undef-init: error
+ no-use-before-define: error
+ brace-style: error
+ comma-dangle: error
+ comma-spacing: error
+ eol-last: error
+ func-call-spacing: error
+ keyword-spacing: error
+ linebreak-style: error
+ no-bitwise: error
+ no-lonely-if: error
+ no-multi-assign: error
+ no-multiple-empty-lines: error
+ no-nested-ternary: error
+ no-trailing-spaces: error
+ semi-spacing: error
+ space-before-blocks: error
+ space-in-parens: error
+ space-infix-ops: error
+ switch-colon-spacing: error
+ wrap-regex: error
+ no-confusing-arrow: error
+ no-useless-computed-key: error
+ no-var: error
+ template-curly-spacing: error
+ semi:
+ - error
+ - never
+ no-extra-parens:
+ - error
+ - all
+ valid-typeof:
+ - error
+ - requireStringLiterals: true
+ strict:
+ - error
+ - global
+ curly:
+ - error
+ - multi-line
+ indent:
+ - error
+ - tab
+ quotes:
+ - error
+ - single
+ space-before-function-paren:
+ - error
+ - never
diff --git a/Chrome/_locales/de/messages.json b/Chrome/_locales/de/messages.json
index a0ffdc6..6bf6d48 100644
--- a/Chrome/_locales/de/messages.json
+++ b/Chrome/_locales/de/messages.json
@@ -51,6 +51,14 @@
"message": "Eine URL pro Zeile!",
"description": "Zweiter fett formatierter Satz auf der Einstellungsseite"
},
+ "optionsAudible": {
+ "message": "Tabs die Audio spielen wach halten",
+ "description": "Checkbox für die Audio-Einstellung"
+ },
+ "optionsThumbnails": {
+ "message": "Screenshot von manuell schlafen gelegten Tabs anzeigen (experimentell!)",
+ "description": "Checkbox für die Thumbnail-Einstellung"
+ },
"optionsSaveButton": {
"message": "Speichern",
"description": "Text des Speichern-Buttons"
@@ -63,4 +71,4 @@
"message": "Aufwecken",
"description": "Text des Aufweck-Buttons einer inaktiven Seite"
}
-}
\ No newline at end of file
+}
diff --git a/Chrome/_locales/en/messages.json b/Chrome/_locales/en/messages.json
index eb2e26b..4f62dff 100644
--- a/Chrome/_locales/en/messages.json
+++ b/Chrome/_locales/en/messages.json
@@ -51,6 +51,14 @@
"message": "One URL per line!",
"description": "options page second bold sentence"
},
+ "optionsAudible": {
+ "message": "keep audio-playing tabs awake",
+ "description": "checkbox for the audio-option"
+ },
+ "optionsThumbnails": {
+ "message": "show screenshot of manually hibernated tabs (experimental!)",
+ "description": "checkbox for the thumbnail-option"
+ },
"optionsSaveButton": {
"message": "Save",
"description": "save button text"
@@ -63,4 +71,4 @@
"message": "Wake up!",
"description": "text of the button to wake up a hibernating page"
}
-}
\ No newline at end of file
+}
diff --git a/Chrome/eventPage.js b/Chrome/eventPage.js
index 657c0f5..7270ace 100644
--- a/Chrome/eventPage.js
+++ b/Chrome/eventPage.js
@@ -1,91 +1,112 @@
'use strict'
-var whitelist
-var whitelistArray = new Array()
+let whitelistArray = new Array()
+let caffeinatedAudio = false
+let thumbnails = false
chrome.storage.sync.get(function(items) {
- if (items.whitelist) {
- whitelist = items.whitelist
- whitelistArray = whitelist.split('\n')
+ if (items.whitelist) whitelistArray = items.whitelist.split('\n')
+ if (items.audible !== undefined) caffeinatedAudio = items.audible
+ if (items.thumbnails !== undefined) thumbnails = items.thumbnails
+})
+
+chrome.storage.onChanged.addListener(function(changes, area) {
+ if (area === 'sync') {
+ chrome.storage.sync.get(function(items) {
+ if (items.whitelist) whitelistArray = items.whitelist.split('\n')
+ if (items.audible !== undefined) caffeinatedAudio = items.audible
+ if (items.thumbnails !== undefined) thumbnails = items.thumbnails
+ })
}
})
+chrome.runtime.onInstalled.addListener(function() {
+ chrome.contextMenus.create({
+ id : 'SleepTab',
+ title : chrome.i18n.getMessage('contextMenuTitle'),
+ contexts : ['page']
+ })
+})
+
function inWhitelist(url) {
- var listed = false
whitelistArray.forEach(function(item) {
if (url.startsWith(item)) {
- listed = true
+ return true
}
})
- return listed
+ return false
}
-function sleepTab(html, tab) {
- var pageInfo = {
+function sleepTab(html, tab, img) {
+ const pageInfo = {
url: tab.url,
title: tab.title,
hibernationInfo: chrome.i18n.getMessage('hibernationPageInfo'),
buttonText: chrome.i18n.getMessage('hibernationPageButton'),
favIconUrl: tab.favIconUrl
}
- var pageHtml = html.replace(/\{\/\*pageInfoObject\*\/\}/, JSON.stringify(pageInfo))
- var dataURL = 'data:text/html;charset=utf-8,' + encodeURIComponent(pageHtml)
- chrome.tabs.update(tab.id, {url: dataURL})
-}
-chrome.browserAction.onClicked.addListener(function(tab) {
- var c = 0
+ const pageHtml = html.replace(/\{\/\*pageInfoObject\*\/\}/, JSON.stringify(pageInfo))
- var xmlHttp = new XMLHttpRequest()
- xmlHttp.open('GET', chrome.runtime.getURL('hibernationPage/index.html'), true)
- xmlHttp.onload = function () {
- var html = xmlHttp.responseText
+ if (img && thumbnails) {
+ const canvas = document.createElement('canvas')
+ const ctx = canvas.getContext('2d')
- chrome.windows.getAll({populate: true}, function(windows) {
- windows.forEach(function(win) {
- win.tabs.forEach(function(tab) {
- if (tab.active || tab.highlighted || tab.pinned) return
- if (tab.status !== 'complete') return
- if (!tab.url.match(/^https?:\/\//)) return
- if (inWhitelist(tab.url)) return
+ const i = new Image()
+ i.src = img
+ i.onload = function() {
+ canvas.width = 300
+ canvas.height = canvas.width * (i.height / i.width)
+ ctx.drawImage(i, 0, 0, canvas.width, canvas.height)
+ img = ``
- sleepTab(html, tab)
- c++
- })
- })
+ const dataURL = `data:text/html;charset=UTF-8,${encodeURIComponent(pageHtml.replace(//, img))}`
+ chrome.tabs.update(tab.id, {url: dataURL, autoDiscardable: true})
+ }
+ return
+ }
+ const dataURL = `data:text/html;charset=UTF-8,${encodeURIComponent(pageHtml)}`
+ chrome.tabs.update(tab.id, {url: dataURL, autoDiscardable: true})
+}
+
+function sleepSingle(tab) {
+ const xmlHttp = new XMLHttpRequest()
+ xmlHttp.open('GET', chrome.runtime.getURL('hibernationPage/index.html'), true)
+ xmlHttp.onload = function() {
+ chrome.tabs.captureVisibleTab({format: 'png'}, function(img) {
+ sleepTab(xmlHttp.responseText, tab, img)
})
}
xmlHttp.send(null)
-})
-
-const onInstalledDetails = {details: {'OnInstalledReason': 'installed'}}
-
-chrome.runtime.onInstalled.addListener(function(onInstalledDetails) {
- chrome.contextMenus.create({
- id : 'SleepTab',
- title : chrome.i18n.getMessage('contextMenuTitle'),
- contexts : ['page']
- })
-})
+}
-chrome.contextMenus.onClicked.addListener(function(info, tab) {
- var xmlHttp = new XMLHttpRequest()
+chrome.browserAction.onClicked.addListener(function() {
+ const xmlHttp = new XMLHttpRequest()
xmlHttp.open('GET', chrome.runtime.getURL('hibernationPage/index.html'), true)
- xmlHttp.onload = function () {
- var html = xmlHttp.responseText
- sleepTab(html, tab)
+ xmlHttp.onload = function() {
+ chrome.tabs.query({
+ active: false,
+ pinned: false,
+ highlighted: false,
+ status: 'complete',
+ url: ['http://*/*', 'https://*/*', 'ftp://*/*', 'file://*/*']
+ }, function(tabs) {
+ tabs.forEach(function(tab) {
+ if (inWhitelist(tab.url)) return
+ if (tab.audible && caffeinatedAudio) return
+ sleepTab(xmlHttp.responseText, tab)
+ })
+ })
}
xmlHttp.send(null)
})
-chrome.commands.onCommand.addListener(function(command) {
- chrome.tabs.query({active: true, lastFocusedWindow: true}, function(tab) {
- var xmlHttp = new XMLHttpRequest()
- xmlHttp.open('GET', chrome.runtime.getURL('hibernationPage/index.html'), true)
- xmlHttp.onload = function () {
- var html = xmlHttp.responseText
- sleepTab(html, tab[0])
- }
- xmlHttp.send(null)
+chrome.contextMenus.onClicked.addListener(function(info, tab) {
+ sleepSingle(tab)
+})
+
+chrome.commands.onCommand.addListener(function() {
+ chrome.tabs.query({active: true, lastFocusedWindow: true}, function(tabs) {
+ sleepSingle(tabs[0])
})
})
diff --git a/Chrome/hibernationPage/index.html b/Chrome/hibernationPage/index.html
index f502884..ad760a8 100644
--- a/Chrome/hibernationPage/index.html
+++ b/Chrome/hibernationPage/index.html
@@ -2,60 +2,49 @@
+ + +
+ ++ + +
+ diff --git a/Chrome/options.js b/Chrome/options.js index fa70ba1..c5f0156 100644 --- a/Chrome/options.js +++ b/Chrome/options.js @@ -1,9 +1,12 @@ 'use strict' function save_options() { - var whitelist = document.getElementById('whitelist').value - chrome.storage.sync.set({whitelist: whitelist}, function() { - var status = document.getElementById('status') + const whitelist = document.getElementById('whitelist').value + const audible = document.getElementById('audible').checked + const thumbnails = document.getElementById('thumbnails').checked + + chrome.storage.sync.set({whitelist: whitelist, audible: audible, thumbnails: thumbnails}, function() { + const status = document.getElementById('status') status.textContent = chrome.i18n.getMessage('saveOptions') setTimeout(function() { status.textContent = '' @@ -12,8 +15,10 @@ function save_options() { } function restore_options() { - chrome.storage.sync.get({whitelist: ''}, function(items) { + chrome.storage.sync.get(function(items) { document.getElementById('whitelist').value = items.whitelist + document.getElementById('audible').checked = items.audible + document.getElementById('thumbnails').checked = items.thumbnails }) } @@ -25,5 +30,7 @@ document.getElementById('secondParagraph').innerText = chrome.i18n.getMessage('o document.getElementById('thirdParagraph').innerText = chrome.i18n.getMessage('optionsThirdParagraph') document.getElementById('firstStrong').innerText = chrome.i18n.getMessage('optionsFirstStrong') document.getElementById('secondStrong').innerText = chrome.i18n.getMessage('optionsSecondStrong') +document.getElementById('audibleSpan').innerText = chrome.i18n.getMessage('optionsAudible') +document.getElementById('thumbnailsSpan').innerText = chrome.i18n.getMessage('optionsThumbnails') document.getElementById('save').innerText = chrome.i18n.getMessage('optionsSaveButton') document.getElementById('save').addEventListener('click', save_options)