├── .eslintrc.yml ├── .gitignore ├── Chrome ├── _locales │ ├── de │ │ └── messages.json │ └── en │ │ └── messages.json ├── eventPage.js ├── hibernationPage │ └── index.html ├── icon128.png ├── icon19.png ├── icon38.png ├── manifest.json ├── options.html └── options.js ├── LICENSE ├── Makefile ├── README.md ├── TabHibernation.safariextension ├── Icon-32.png ├── Info.plist ├── global-page.html ├── global-script.js └── hibernationPage │ └── index.html ├── lib ├── icon16.png └── icon48.png └── material ├── icon128.pxm ├── icon16.pxm ├── icon19.pxm ├── icon38.pxm ├── icon48.pxm ├── screenshot1280.pxm ├── screenshot1_chrome.png ├── screenshot2_chrome.png ├── screenshot3_chrome.png ├── small_tile_chrome.png └── small_tile_chrome.psd /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | extends: eslint:recommended 2 | 3 | env: 4 | es6: true, 5 | browser: true, 6 | webextensions: true 7 | 8 | rules: 9 | # warnings 10 | no-control-regex: warn 11 | no-ternary: warn 12 | prefer-const: warn 13 | prefer-template: warn 14 | no-magic-numbers: 15 | - warn 16 | - ignoreArrayIndexes: true 17 | # errors 18 | yoda: error 19 | radix: error 20 | no-useless-return: error 21 | no-useless-concat: error 22 | no-unused-expressions: error 23 | no-self-compare: error 24 | no-script-url: error 25 | no-return-assign: error 26 | no-octal-escape: error 27 | no-loop-func: error 28 | no-lone-blocks: error 29 | no-invalid-this: error 30 | no-implied-eval: error 31 | no-floating-decimal: error 32 | no-eval: error 33 | no-eq-null: error 34 | no-empty-function: error 35 | no-else-return: error 36 | no-alert: error 37 | eqeqeq: error 38 | dot-notation: error 39 | no-shadow: error 40 | no-undef-init: error 41 | no-use-before-define: error 42 | brace-style: error 43 | comma-dangle: error 44 | comma-spacing: error 45 | eol-last: error 46 | func-call-spacing: error 47 | keyword-spacing: error 48 | linebreak-style: error 49 | no-bitwise: error 50 | no-lonely-if: error 51 | no-multi-assign: error 52 | no-multiple-empty-lines: error 53 | no-nested-ternary: error 54 | no-trailing-spaces: error 55 | semi-spacing: error 56 | space-before-blocks: error 57 | space-in-parens: error 58 | space-infix-ops: error 59 | switch-colon-spacing: error 60 | wrap-regex: error 61 | no-confusing-arrow: error 62 | no-useless-computed-key: error 63 | no-var: error 64 | template-curly-spacing: error 65 | semi: 66 | - error 67 | - never 68 | no-extra-parens: 69 | - error 70 | - all 71 | valid-typeof: 72 | - error 73 | - requireStringLiterals: true 74 | strict: 75 | - error 76 | - global 77 | curly: 78 | - error 79 | - multi-line 80 | indent: 81 | - error 82 | - tab 83 | quotes: 84 | - error 85 | - single 86 | space-before-function-paren: 87 | - error 88 | - never 89 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/TabHibernation.iml 2 | .idea/scopes/scope_settings.xml 3 | .idea/codeStyleSettings.xml 4 | 5 | Chrome/icon16.png 6 | Chrome/icon48.png 7 | TabHibernation.safariextension/icon16.png 8 | TabHibernation.safariextension/Icon-48.png 9 | 10 | node_modules/ 11 | -------------------------------------------------------------------------------- /Chrome/_locales/de/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionName": { 3 | "message": "Tab Hibernation", 4 | "description": "Name der Extension" 5 | }, 6 | "extensionDescription": { 7 | "message": "schickt inaktive Tabs schlafen", 8 | "description": "Beschreibung der Extension" 9 | }, 10 | "defaultTitle": { 11 | "message": "inaktive Tabs schlafen legen", 12 | "description": "Tooltip, der in der Google Chrome Toolbar erscheint" 13 | }, 14 | "commandsDescription": { 15 | "message": "Aktiven Tab schlafen legen", 16 | "description": "Beschreibung für den Keyboard-Shortcut" 17 | }, 18 | "contextMenuTitle": { 19 | "message": "Diese Seite schlafen legen", 20 | "description": "Titel des Kontextmenüeintrags" 21 | }, 22 | "saveOptions": { 23 | "message": "Optionen gespeichert.", 24 | "description": "Statustext, wenn Optionen gespeichert werden" 25 | }, 26 | "optionsTitle": { 27 | "message": "Tab Hibernation - Einstellungen", 28 | "description": "Titel der Einstellungsseite" 29 | }, 30 | "optionsHeading": { 31 | "message": "Whitelist", 32 | "description": "Überschrift der Einstellungsseite" 33 | }, 34 | "optionsFirstParagraph": { 35 | "message": "Hier können URLs eingetragen werden, die nicht schlafen gelegt werden sollen, wenn der \"inaktive Tabs schlafen legen\"-Button gedrückt wird.", 36 | "description": "Erster Absatz der Einstellungsseite" 37 | }, 38 | "optionsSecondParagraph": { 39 | "message": "Wenn z.B. \"sub.example.com\" und \"test.example.com\" wach gehalten werden sollen, müssen beide eingetragen werden und nicht nur \"*.example.com\"", 40 | "description": "Zweiter Absatz der Einstellungsseite" 41 | }, 42 | "optionsThirdParagraph": { 43 | "message": "Hier kann auch ein Pfad wie \"example.com/path/\" eingetragen werden, wenn nicht die gesamte Domain wach gehalten werden soll.", 44 | "description": "Dritter Absatz der Einstellungsseite" 45 | }, 46 | "optionsFirstStrong": { 47 | "message": "URLs müssen vollständig sein und http/https enthalten!", 48 | "description": "Erster fett formatierter Satz auf der Einstellungsseite" 49 | }, 50 | "optionsSecondStrong": { 51 | "message": "Eine URL pro Zeile!", 52 | "description": "Zweiter fett formatierter Satz auf der Einstellungsseite" 53 | }, 54 | "optionsAudible": { 55 | "message": "Tabs die Audio spielen wach halten", 56 | "description": "Checkbox für die Audio-Einstellung" 57 | }, 58 | "optionsThumbnails": { 59 | "message": "Screenshot von manuell schlafen gelegten Tabs anzeigen (experimentell!)", 60 | "description": "Checkbox für die Thumbnail-Einstellung" 61 | }, 62 | "optionsSaveButton": { 63 | "message": "Speichern", 64 | "description": "Text des Speichern-Buttons" 65 | }, 66 | "hibernationPageInfo": { 67 | "message": "schläft", 68 | "description": "Infotext, der auf der inaktiven Seite angezeigt wird" 69 | }, 70 | "hibernationPageButton": { 71 | "message": "Aufwecken", 72 | "description": "Text des Aufweck-Buttons einer inaktiven Seite" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Chrome/_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionName": { 3 | "message": "Tab Hibernation", 4 | "description": "extension name" 5 | }, 6 | "extensionDescription": { 7 | "message": "Sends your inactive tabs to sleep", 8 | "description": "extension description" 9 | }, 10 | "defaultTitle": { 11 | "message": "send inactive tabs to sleep", 12 | "description": "tooltip shown in the main Google Chrome toolbar" 13 | }, 14 | "commandsDescription": { 15 | "message": "Hibernate the current Tab", 16 | "description": "keyboard shortcut description" 17 | }, 18 | "contextMenuTitle": { 19 | "message": "Hibernate This Page", 20 | "description": "context menu entry title" 21 | }, 22 | "saveOptions": { 23 | "message": "Options saved.", 24 | "description": "status text when options are saved" 25 | }, 26 | "optionsTitle": { 27 | "message": "Tab Hibernation - Settings", 28 | "description": "options page title" 29 | }, 30 | "optionsHeading": { 31 | "message": "Whitelist", 32 | "description": "options page heading" 33 | }, 34 | "optionsFirstParagraph": { 35 | "message": "Here you can input a whitelist for URLs which should not be hibernated when pressing the \"send inactive tabs to sleep\"-Button.", 36 | "description": "options page first paragraph" 37 | }, 38 | "optionsSecondParagraph": { 39 | "message": "For example: if you want to whitelist \"sub.example.com\" and \"test.example.com\", you MUST put them both and can't just type \"*.example.com\"", 40 | "description": "options page second paragraph" 41 | }, 42 | "optionsThirdParagraph": { 43 | "message": "You can also put something like \"example.com/path/\" in here, if you don't want to whitelist the whole domain.", 44 | "description": "options page third paragraph" 45 | }, 46 | "optionsFirstStrong": { 47 | "message": "URLs must be complete and include http/https!", 48 | "description": "options page first bold sentence" 49 | }, 50 | "optionsSecondStrong": { 51 | "message": "One URL per line!", 52 | "description": "options page second bold sentence" 53 | }, 54 | "optionsAudible": { 55 | "message": "keep audio-playing tabs awake", 56 | "description": "checkbox for the audio-option" 57 | }, 58 | "optionsThumbnails": { 59 | "message": "show screenshot of manually hibernated tabs (experimental!)", 60 | "description": "checkbox for the thumbnail-option" 61 | }, 62 | "optionsSaveButton": { 63 | "message": "Save", 64 | "description": "save button text" 65 | }, 66 | "hibernationPageInfo": { 67 | "message": "is hibernating", 68 | "description": "info shown when page is hibernating" 69 | }, 70 | "hibernationPageButton": { 71 | "message": "Wake up!", 72 | "description": "text of the button to wake up a hibernating page" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Chrome/eventPage.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | let whitelistArray = new Array() 4 | let caffeinatedAudio = false 5 | let thumbnails = false 6 | 7 | chrome.storage.sync.get(function(items) { 8 | if (items.whitelist) whitelistArray = items.whitelist.split('\n') 9 | if (items.audible !== undefined) caffeinatedAudio = items.audible 10 | if (items.thumbnails !== undefined) thumbnails = items.thumbnails 11 | }) 12 | 13 | chrome.storage.onChanged.addListener(function(changes, area) { 14 | if (area === 'sync') { 15 | chrome.storage.sync.get(function(items) { 16 | if (items.whitelist) whitelistArray = items.whitelist.split('\n') 17 | if (items.audible !== undefined) caffeinatedAudio = items.audible 18 | if (items.thumbnails !== undefined) thumbnails = items.thumbnails 19 | }) 20 | } 21 | }) 22 | 23 | chrome.runtime.onInstalled.addListener(function() { 24 | chrome.contextMenus.create({ 25 | id : 'SleepTab', 26 | title : chrome.i18n.getMessage('contextMenuTitle'), 27 | contexts : ['page'] 28 | }) 29 | }) 30 | 31 | function inWhitelist(url) { 32 | whitelistArray.forEach(function(item) { 33 | if (url.startsWith(item)) { 34 | return true 35 | } 36 | }) 37 | return false 38 | } 39 | 40 | function sleepTab(html, tab, img) { 41 | const pageInfo = { 42 | url: tab.url, 43 | title: tab.title, 44 | hibernationInfo: chrome.i18n.getMessage('hibernationPageInfo'), 45 | buttonText: chrome.i18n.getMessage('hibernationPageButton'), 46 | favIconUrl: tab.favIconUrl 47 | } 48 | 49 | const pageHtml = html.replace(/\{\/\*pageInfoObject\*\/\}/, JSON.stringify(pageInfo)) 50 | 51 | if (img && thumbnails) { 52 | const canvas = document.createElement('canvas') 53 | const ctx = canvas.getContext('2d') 54 | 55 | const i = new Image() 56 | i.src = img 57 | i.onload = function() { 58 | canvas.width = 300 59 | canvas.height = canvas.width * (i.height / i.width) 60 | ctx.drawImage(i, 0, 0, canvas.width, canvas.height) 61 | img = `` 62 | 63 | const dataURL = `data:text/html;charset=UTF-8,${encodeURIComponent(pageHtml.replace(//, img))}` 64 | chrome.tabs.update(tab.id, {url: dataURL, autoDiscardable: true}) 65 | } 66 | return 67 | } 68 | const dataURL = `data:text/html;charset=UTF-8,${encodeURIComponent(pageHtml)}` 69 | chrome.tabs.update(tab.id, {url: dataURL, autoDiscardable: true}) 70 | } 71 | 72 | function sleepSingle(tab) { 73 | const xmlHttp = new XMLHttpRequest() 74 | xmlHttp.open('GET', chrome.runtime.getURL('hibernationPage/index.html'), true) 75 | xmlHttp.onload = function() { 76 | chrome.tabs.captureVisibleTab({format: 'png'}, function(img) { 77 | sleepTab(xmlHttp.responseText, tab, img) 78 | }) 79 | } 80 | xmlHttp.send(null) 81 | } 82 | 83 | chrome.browserAction.onClicked.addListener(function() { 84 | const xmlHttp = new XMLHttpRequest() 85 | xmlHttp.open('GET', chrome.runtime.getURL('hibernationPage/index.html'), true) 86 | xmlHttp.onload = function() { 87 | chrome.tabs.query({ 88 | active: false, 89 | pinned: false, 90 | highlighted: false, 91 | status: 'complete', 92 | url: ['http://*/*', 'https://*/*', 'ftp://*/*', 'file://*/*'] 93 | }, function(tabs) { 94 | tabs.forEach(function(tab) { 95 | if (inWhitelist(tab.url)) return 96 | if (tab.audible && caffeinatedAudio) return 97 | sleepTab(xmlHttp.responseText, tab) 98 | }) 99 | }) 100 | } 101 | xmlHttp.send(null) 102 | }) 103 | 104 | chrome.contextMenus.onClicked.addListener(function(info, tab) { 105 | sleepSingle(tab) 106 | }) 107 | 108 | chrome.commands.onCommand.addListener(function() { 109 | chrome.tabs.query({active: true, lastFocusedWindow: true}, function(tabs) { 110 | sleepSingle(tabs[0]) 111 | }) 112 | }) 113 | -------------------------------------------------------------------------------- /Chrome/hibernationPage/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 49 | 104 | ☾  105 | 106 | 107 |
108 |

""

109 |

110 | 111 |

112 |
113 | 114 | 115 | -------------------------------------------------------------------------------- /Chrome/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/Chrome/icon128.png -------------------------------------------------------------------------------- /Chrome/icon19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/Chrome/icon19.png -------------------------------------------------------------------------------- /Chrome/icon38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/Chrome/icon38.png -------------------------------------------------------------------------------- /Chrome/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "__MSG_extensionName__", 4 | "description": "__MSG_extensionDescription__", 5 | "homepage_url": "https://github.com/343max/TabHibernation", 6 | "version": "1.0", 7 | "default_locale": "en", 8 | "permissions": [ 9 | "activeTab", 10 | "tabs", 11 | "contextMenus", 12 | "storage" 13 | ], 14 | "browser_action": { 15 | "default_icon": { 16 | "19": "icon19.png", 17 | "38": "icon38.png" 18 | }, 19 | "default_title": "__MSG_defaultTitle__" 20 | }, 21 | "background": { 22 | "scripts": ["eventPage.js"], 23 | "persistent": false 24 | }, 25 | "options_ui": { 26 | "page": "options.html", 27 | "chrome_style": true 28 | }, 29 | "commands": { 30 | "hibernateCurrentTab": { 31 | "suggested_key": { 32 | "default": "Ctrl+Shift+H", 33 | "mac": "Command+Shift+H" 34 | }, 35 | "description": "__MSG_commandsDescription__" 36 | } 37 | }, 38 | "icons": { 39 | "16": "icon16.png", 40 | "48": "icon48.png", 41 | "128": "icon128.png" 42 | }, 43 | "minimum_chrome_version": "54.0" 44 | } 45 | -------------------------------------------------------------------------------- /Chrome/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

9 | 10 |

11 | 12 |

13 | 14 |

15 | 16 |

17 |
18 | 19 |

20 | 21 |
22 | 23 |

24 | 25 | 26 |

27 | 28 |

29 | 30 | 31 |

32 | 33 |
34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Chrome/options.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | function save_options() { 4 | const whitelist = document.getElementById('whitelist').value 5 | const audible = document.getElementById('audible').checked 6 | const thumbnails = document.getElementById('thumbnails').checked 7 | 8 | chrome.storage.sync.set({whitelist: whitelist, audible: audible, thumbnails: thumbnails}, function() { 9 | const status = document.getElementById('status') 10 | status.textContent = chrome.i18n.getMessage('saveOptions') 11 | setTimeout(function() { 12 | status.textContent = '' 13 | }, 750) 14 | }) 15 | } 16 | 17 | function restore_options() { 18 | chrome.storage.sync.get(function(items) { 19 | document.getElementById('whitelist').value = items.whitelist 20 | document.getElementById('audible').checked = items.audible 21 | document.getElementById('thumbnails').checked = items.thumbnails 22 | }) 23 | } 24 | 25 | document.addEventListener('DOMContentLoaded', restore_options) 26 | document.getElementById('title').innerText = chrome.i18n.getMessage('optionsTitle') 27 | document.getElementById('heading').innerText = chrome.i18n.getMessage('optionsHeading') 28 | document.getElementById('firstParagraph').innerText = chrome.i18n.getMessage('optionsFirstParagraph') 29 | document.getElementById('secondParagraph').innerText = chrome.i18n.getMessage('optionsSecondParagraph') 30 | document.getElementById('thirdParagraph').innerText = chrome.i18n.getMessage('optionsThirdParagraph') 31 | document.getElementById('firstStrong').innerText = chrome.i18n.getMessage('optionsFirstStrong') 32 | document.getElementById('secondStrong').innerText = chrome.i18n.getMessage('optionsSecondStrong') 33 | document.getElementById('audibleSpan').innerText = chrome.i18n.getMessage('optionsAudible') 34 | document.getElementById('thumbnailsSpan').innerText = chrome.i18n.getMessage('optionsThumbnails') 35 | document.getElementById('save').innerText = chrome.i18n.getMessage('optionsSaveButton') 36 | document.getElementById('save').addEventListener('click', save_options) 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Max Winde 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @ln -f lib/icon16.png Chrome/icon16.png 3 | @ln -f lib/icon16.png TabHibernation.safariextension/icon16.png 4 | @ln -f lib/icon48.png Chrome/icon48.png 5 | @ln -f lib/icon48.png TabHibernation.safariextension/Icon-48.png 6 | 7 | clean: 8 | @rm -rf Chrome/icon16.png 9 | @rm -rf TabHibernation.safariextension/icon16.png 10 | @rm -rf Chrome/icon48.png 11 | @rm -rf TabHibernation.safariextension/Icon-48.png 12 | 13 | .PHONY: all clean 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TabHibernate 2 | TabHibernate is a Browser Extension that will send inactive Tabs into some kind of "Hibernate" mode – Mostly like [OneTab](https://chrome.google.com/webstore/detail/onetab/chphlpgkkbolifaimnlloiipkdnihall) but without removing the tabs from the tabbar. 3 | 4 | You may download the extension in the [Chrome Web Store](https://chrome.google.com/webstore/detail/tab-hibernation/ddklinnhageaolpojclheieamdiphabe). 5 | 6 | **Currently only the Chrome-Version is really supported. 7 | Safari-Version needs a maintainer and a Firefox-Version would be nice to have, contact [@HorayNarea](https://github.com/HorayNarea) if you want to do something about that.** 8 | 9 | ## Building the extension 10 | Code (or other files) that can be used by both the Chrome and Safari extension are stored in `lib/`. Browser-specific code is stored in `Chrome/` for Chrome and in `TabHibernation.safariextension/` for Safari. 11 | 12 | To make the files in `lib/` accessible from both extensions hard links need to be created. Just run `make` to create these links. 13 | 14 | ## Screenshot 15 | ![Screenshot](material/screenshot1_chrome.png "Chrome screenshot") 16 | -------------------------------------------------------------------------------- /TabHibernation.safariextension/Icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/TabHibernation.safariextension/Icon-32.png -------------------------------------------------------------------------------- /TabHibernation.safariextension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Builder Version 6 | 8536.29.13 7 | CFBundleDisplayName 8 | Tab Hibernation 9 | CFBundleIdentifier 10 | com.yourcompany.tabhibernation 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleShortVersionString 14 | 1.0 15 | CFBundleVersion 16 | 1 17 | Chrome 18 | 19 | Global Page 20 | global-page.html 21 | Toolbar Items 22 | 23 | 24 | Command 25 | hibernateTabs 26 | Identifier 27 | toolbarHibernateItem 28 | Image 29 | icon16.png 30 | Label 31 | Hibernate Tabs 32 | Tool Tip 33 | Send inactive tabs to sleep 34 | 35 | 36 | 37 | Content 38 | 39 | Scripts 40 | 41 | 42 | ExtensionInfoDictionaryVersion 43 | 1.0 44 | Permissions 45 | 46 | Website Access 47 | 48 | Include Secure Pages 49 | 50 | Level 51 | All 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /TabHibernation.safariextension/global-page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TabHibernation.safariextension/global-script.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | function performCommand(event) { 4 | if(event.command === 'hibernateTabs') { 5 | var c = 0 6 | 7 | var xmlHttp = new XMLHttpRequest() 8 | xmlHttp.open('GET', safari.extension.baseURI + 'hibernationPage/index.html', true) 9 | xmlHttp.onload = function() { 10 | var html = xmlHttp.responseText 11 | 12 | safari.application.browserWindows.forEach(function(win) { 13 | win.tabs.forEach(function(tab) { 14 | // Safari returns undefined for sites like the history page or data URIs 15 | if(typeof tab.url !== 'undefined') { 16 | if(tab === win.activeTab) return 17 | if(!tab.url.match(/^https?:\/\//)) return 18 | 19 | window.setTimeout(function() { 20 | var pageInfo = { 21 | url: tab.url, 22 | title: tab.title 23 | } 24 | 25 | var pageHtml = html.replace(/\{\/\*pageInfoObject\*\/\}/, JSON.stringify(pageInfo)) 26 | var dataURL = 'data:text/html;charset=utf-8,' + encodeURIComponent(pageHtml) 27 | tab.url = dataURL 28 | }, c * 100) 29 | 30 | c++ 31 | } 32 | }) 33 | }) 34 | } 35 | xmlHttp.send(null) 36 | } 37 | } 38 | 39 | safari.application.addEventListener('command', performCommand(event), false) 40 | -------------------------------------------------------------------------------- /TabHibernation.safariextension/hibernationPage/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 51 | 103 | 104 | 105 | 106 |
107 |

"" is hibernating

108 |

109 |

Wake up!

110 |
111 | 112 | 113 | -------------------------------------------------------------------------------- /lib/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/lib/icon16.png -------------------------------------------------------------------------------- /lib/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/lib/icon48.png -------------------------------------------------------------------------------- /material/icon128.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/material/icon128.pxm -------------------------------------------------------------------------------- /material/icon16.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/material/icon16.pxm -------------------------------------------------------------------------------- /material/icon19.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/material/icon19.pxm -------------------------------------------------------------------------------- /material/icon38.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/material/icon38.pxm -------------------------------------------------------------------------------- /material/icon48.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/material/icon48.pxm -------------------------------------------------------------------------------- /material/screenshot1280.pxm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/material/screenshot1280.pxm -------------------------------------------------------------------------------- /material/screenshot1_chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/material/screenshot1_chrome.png -------------------------------------------------------------------------------- /material/screenshot2_chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/material/screenshot2_chrome.png -------------------------------------------------------------------------------- /material/screenshot3_chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/material/screenshot3_chrome.png -------------------------------------------------------------------------------- /material/small_tile_chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/material/small_tile_chrome.png -------------------------------------------------------------------------------- /material/small_tile_chrome.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/343max/TabHibernation/43f58eef47ea0cd0ca2a2ff55a61f44d2a5df377/material/small_tile_chrome.psd --------------------------------------------------------------------------------