├── screenshots
├── options.png
├── context-menu.jpg
└── toolbar-button.jpg
├── icons
├── archive-icon-dark-128.png
├── archive-icon-dark-16.png
├── archive-icon-dark-32.png
├── archive-icon-dark-64.png
├── archive-icon-light-16.png
├── archive-icon-light-32.png
├── archive-icon-light-64.png
└── archive-icon-light.128.png
├── popup
├── popup.html
└── popup.js
├── README.md
├── options
├── options.html
└── options.js
├── manifest.json
└── archive.js
/screenshots/options.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanmccann/archive-url-firefox-addon/HEAD/screenshots/options.png
--------------------------------------------------------------------------------
/screenshots/context-menu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanmccann/archive-url-firefox-addon/HEAD/screenshots/context-menu.jpg
--------------------------------------------------------------------------------
/icons/archive-icon-dark-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanmccann/archive-url-firefox-addon/HEAD/icons/archive-icon-dark-128.png
--------------------------------------------------------------------------------
/icons/archive-icon-dark-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanmccann/archive-url-firefox-addon/HEAD/icons/archive-icon-dark-16.png
--------------------------------------------------------------------------------
/icons/archive-icon-dark-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanmccann/archive-url-firefox-addon/HEAD/icons/archive-icon-dark-32.png
--------------------------------------------------------------------------------
/icons/archive-icon-dark-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanmccann/archive-url-firefox-addon/HEAD/icons/archive-icon-dark-64.png
--------------------------------------------------------------------------------
/icons/archive-icon-light-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanmccann/archive-url-firefox-addon/HEAD/icons/archive-icon-light-16.png
--------------------------------------------------------------------------------
/icons/archive-icon-light-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanmccann/archive-url-firefox-addon/HEAD/icons/archive-icon-light-32.png
--------------------------------------------------------------------------------
/icons/archive-icon-light-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanmccann/archive-url-firefox-addon/HEAD/icons/archive-icon-light-64.png
--------------------------------------------------------------------------------
/screenshots/toolbar-button.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanmccann/archive-url-firefox-addon/HEAD/screenshots/toolbar-button.jpg
--------------------------------------------------------------------------------
/icons/archive-icon-light.128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jonathanmccann/archive-url-firefox-addon/HEAD/icons/archive-icon-light.128.png
--------------------------------------------------------------------------------
/popup/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
18 |
19 |
20 |
21 |
22 | Archive to Wayback Machine
23 |
24 | Archive to Ghost Archive
25 |
26 |
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Wayback Machine Firefox Addon
2 | ========
3 |
4 | This Firefox addon will add a new item to the context menu and the toolbar menu, allowing you to save the current webpage to the [Wayback Machine](http://archive.org/web/). The toolbar button also allows you to save the webpage to [archive.today](archive.today).
5 |
6 | Installation
7 | ========
8 |
9 | This extension is available for installation via [Mozzila's Add-Ons](https://addons.mozilla.org/en-US/firefox/addon/save-url-to-wayback-machine).
10 |
11 | To install this extension from source, please utilize the following guide - [Temporary Installation in Firefox](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Temporary_Installation_in_Firefox).
--------------------------------------------------------------------------------
/options/options.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 2,
3 | "name": "Archive URL",
4 | "version": "1.9",
5 |
6 | "author": "Jonathan McCann",
7 | "homepage_url": "https://github.com/jonathanmccann/archive-url-firefox-addon",
8 |
9 | "description": "This Firefox addon will add a new item to the context menu and a button the toolbar menu, allowing you to archive the current webpage to the Wayback Machine, archive.today, and Ghost Archive. When right clicking on a link or an image, you can choose to archive that URL instead of the current URL.",
10 |
11 | "icons": {
12 | "16": "icons/archive-icon-dark-16.png",
13 | "32": "icons/archive-icon-dark-32.png",
14 | "64": "icons/archive-icon-dark-64.png",
15 | "128": "icons/archive-icon-dark-128.png"
16 | },
17 |
18 | "options_ui": {
19 | "page": "options/options.html"
20 | },
21 |
22 | "permissions": [
23 | "contextMenus",
24 | "storage",
25 | "tabs"
26 | ],
27 |
28 | "browser_action": {
29 | "browser_style": false,
30 | "default_icon": {
31 | "16": "icons/archive-icon-dark-16.png",
32 | "32": "icons/archive-icon-dark-32.png"
33 | },
34 | "default_title": "Archive to Wayback Machine",
35 | "theme_icons": [{
36 | "light": "icons/archive-icon-light-16.png",
37 | "dark": "icons/archive-icon-dark-16.png",
38 | "size": 16
39 | },
40 | {
41 | "light": "icons/archive-icon-light-32.png",
42 | "dark": "icons/archive-icon-dark-32.png",
43 | "size": 32
44 | }]
45 | },
46 |
47 | "background": {
48 | "scripts": ["archive.js"]
49 | }
50 | }
--------------------------------------------------------------------------------
/popup/popup.js:
--------------------------------------------------------------------------------
1 | document.addEventListener("click", function(e) {
2 | if (!e.target.classList.contains("archiver")) {
3 | return;
4 | }
5 |
6 | browser.tabs.query({active: true, currentWindow: true}).then(tabs => {
7 | if (tabs[0]) {
8 | if (e.target.id == "multiple") {
9 | browser.extension.getBackgroundPage().archiveUrlToMultiple(tabs[0].url);
10 | }
11 | else if (e.target.id == "archive") {
12 | browser.extension.getBackgroundPage().archiveUrlArchive(tabs[0].url);
13 | }
14 | else if (e.target.id == "ghostArchive") {
15 | browser.extension.getBackgroundPage().archiveUrlGhostArchive(tabs[0].url);
16 | }
17 | else if (e.target.id == "wayback") {
18 | browser.extension.getBackgroundPage().archiveUrlWayback(tabs[0].url);
19 | }
20 | }
21 |
22 | window.close();
23 | });
24 | });
25 |
26 | function resetArchiveURL() {
27 | browser.storage.local.get("archiveDomain").then(name => {
28 | var archiveDomain = name.archiveDomain;
29 |
30 | if (archiveDomain == undefined) {
31 | archiveDomain = "today";
32 | }
33 |
34 | document.getElementById("archive").innerHTML = "Archive to archive." + archiveDomain;
35 | });
36 |
37 | browser.storage.local.get("enabledArchivers", function(name) {
38 | if ((name.enabledArchivers == undefined) || (name.enabledArchivers == "")) {
39 | document.getElementById("wayback").style.display = "block";
40 | }
41 | else {
42 | var count = 0;
43 |
44 | for (var enabledArchiver of JSON.parse(name.enabledArchivers)) {
45 | document.getElementById(enabledArchiver).style.display = "block";
46 |
47 | count++;
48 | }
49 |
50 | document.getElementById("multiple").style.display = "block";
51 |
52 | if (count == 2) {
53 | document.getElementById("multiple").innerHTML = "Archive to both";
54 | }
55 | else {
56 | document.getElementById("multiple").innerHTML = "Archive to all";
57 | }
58 | }
59 | });
60 | }
61 |
62 | document.addEventListener("DOMContentLoaded", resetArchiveURL);
--------------------------------------------------------------------------------
/options/options.js:
--------------------------------------------------------------------------------
1 | function saveOptions(e) {
2 | var archiver;
3 |
4 | var archiveDomain = document.options.archiveDomain.value;
5 |
6 | if ((archiveDomain == undefined) || (archiveDomain == "")) {
7 | archiveDomain = "today";
8 |
9 | document.getElementById("archiveDomain").value = "today";
10 | }
11 |
12 | document.getElementById("archiveLabel").innerHTML = "archive." + archiveDomain;
13 |
14 | var enabledArchiverCheckboxes = document.querySelectorAll('input[type=checkbox]:checked');
15 |
16 | var enabledArchivers = [];
17 |
18 | if (enabledArchiverCheckboxes.length == 0) {
19 | enabledArchivers.push("wayback");
20 | }
21 | else {
22 | for (i = 0; i < enabledArchiverCheckboxes.length; i++) {
23 | enabledArchivers.push(enabledArchiverCheckboxes[i].id)
24 | }
25 | }
26 |
27 | setArchiver(enabledArchivers);
28 |
29 | browser.storage.local.set({
30 | archiveDomain: archiveDomain,
31 | enabledArchivers: JSON.stringify(enabledArchivers)
32 | });
33 |
34 | e.preventDefault();
35 | }
36 |
37 | function setArchiveDomain(archiveDomain) {
38 | if ((archiveDomain == undefined) || (archiveDomain == "")) {
39 | document.getElementById("archiveDomain").value = "today";
40 | document.getElementById("archiveLabel").innerHTML = "archive.today";
41 | }
42 | else {
43 | document.getElementById("archiveDomain").value = archiveDomain;
44 | document.getElementById("archiveLabel").innerHTML = "archive." + archiveDomain;
45 | }
46 | }
47 |
48 | function setArchiver(enabledArchivers) {
49 | for (i = 0; i < enabledArchivers.length; i++) {
50 | document.getElementById(enabledArchivers[i]).checked = true;
51 | }
52 | }
53 |
54 | function restoreOptions() {
55 | browser.storage.local.get("archiveDomain", function(archiveDomain) {
56 | setArchiveDomain(archiveDomain.archiveDomain);
57 | });
58 |
59 | browser.storage.local.get("enabledArchivers", function(enabledArchivers) {
60 | if ((enabledArchivers.enabledArchivers == undefined) || (enabledArchivers.enabledArchivers == "")) {
61 | setArchiver(["wayback"]);
62 | }
63 | else {
64 | setArchiver(JSON.parse(enabledArchivers.enabledArchivers));
65 | }
66 | });
67 | }
68 |
69 | document.addEventListener("DOMContentLoaded", restoreOptions);
70 | document.querySelector("form").addEventListener("submit", saveOptions);
--------------------------------------------------------------------------------
/archive.js:
--------------------------------------------------------------------------------
1 | var archiveDomain;
2 | var archiver;
3 |
4 | var enabledArchivers = [];
5 |
6 | var archiveCurrentUrlTitleToArchive = "Archive Current URL to archive.";
7 | var archiveCurrentUrlTitleToGhostArchive = "Archive Current URL to Ghost Archive";
8 | var archiveCurrentUrlTitleToWayback = "Archive Current URL to Wayback Machine";
9 | var archiveCurrentUrlTitleToMultiple = "Archive Current URL to ";
10 |
11 | var archiveImageUrlTitleToArchive = "Archive Image URL to archive.";
12 | var archiveImageUrlTitleToGhostArchive = "Archive Image URL to Ghost Archive";
13 | var archiveImageUrlTitleToWayback = "Archive Image URL to Wayback Machine";
14 | var archiveImageUrlTitleToMultiple = "Archive Image URL to ";
15 |
16 | var archiveLinkUrlTitleToArchive = "Archive Link URL to archive.";
17 | var archiveLinkUrlTitleToGhostArchive = "Archive Link URL to Ghost Archive";
18 | var archiveLinkUrlTitleToWayback = "Archive Link URL to Wayback Machine";
19 | var archiveLinkUrlTitleToMultiple = "Archive Link URL to ";
20 |
21 | function saveCurrentUrl() {
22 | browser.tabs.query({active: true, currentWindow: true}, function(tabs) {
23 | if (tabs[0]) {
24 | if (enabledArchivers[0] == "archive") {
25 | archiveUrlArchive(tabs[0].url);
26 | }
27 | else if (enabledArchivers[0] == "ghostArchive") {
28 | archiveUrlGhostArchive(tabs[0].url);
29 | }
30 | else {
31 | archiveUrlWayback(tabs[0].url);
32 | }
33 | }
34 | });
35 | }
36 |
37 | function archiveUrlArchive(url) {
38 | browser.tabs.create({
39 | url: "https://archive." + archiveDomain + "/?run=1&url=" + encodeURIComponent(url),
40 | active: false
41 | })
42 | }
43 |
44 | function archiveUrlGhostArchive(url) {
45 | browser.tabs.create({
46 | url: "https://ghostarchive.org/save/" + url,
47 | active: false
48 | })
49 | }
50 |
51 | function archiveUrlWayback(url) {
52 | browser.tabs.create({
53 | url: "https://web.archive.org/save/" + url,
54 | active: false
55 | })
56 | }
57 |
58 | function archiveUrlToMultiple(url) {
59 | for (enabledArchiver of enabledArchivers) {
60 | if (enabledArchiver == "archive") {
61 | archiveUrlArchive(url);
62 | }
63 | else if (enabledArchiver == "ghostArchive") {
64 | archiveUrlGhostArchive(url);
65 | }
66 | else if (enabledArchiver == "wayback") {
67 | archiveUrlWayback(url);
68 | }
69 | }
70 | }
71 |
72 | // Check for changes to 'archiver' and update the local value accordingly as well as the toolbar title
73 | function checkForArchiverChanges(changes, area) {
74 | if (area == "local") {
75 | var preferenceChange = false;
76 |
77 | var changedItems = Object.keys(changes);
78 |
79 | for (item of changedItems) {
80 | if (item == "archiveDomain") {
81 | archiveDomain = changes[item].newValue;
82 |
83 | preferenceChange = true;
84 | }
85 | else if (item == "enabledArchivers") {
86 | enabledArchivers = JSON.parse(changes[item].newValue);
87 |
88 | preferenceChange = true;
89 | }
90 | }
91 |
92 | if (preferenceChange) {
93 | updateArchiver();
94 | }
95 | }
96 | }
97 |
98 | function addArchiveContextMenus() {
99 | browser.contextMenus.create({
100 | id: "archive-url-archive",
101 | title: archiveCurrentUrlTitleToArchive + archiveDomain,
102 | contexts: ["page"]
103 | })
104 |
105 | browser.contextMenus.create({
106 | id: "archive-image-url-archive",
107 | title: archiveImageUrlTitleToArchive + archiveDomain,
108 | contexts: ["image"]
109 | })
110 |
111 | browser.contextMenus.create({
112 | id: "archive-link-url-archive",
113 | title: archiveLinkUrlTitleToArchive + archiveDomain,
114 | contexts: ["link"]
115 | })
116 | }
117 |
118 | function addBothArchiveContextMenus() {
119 | browser.contextMenus.create({
120 | id: "archive-url-both",
121 | title: archiveCurrentUrlTitleToMultiple + (enabledArchivers.length == 2 ? "both" : "all"),
122 | contexts: ["page"]
123 | })
124 |
125 | browser.contextMenus.create({
126 | id: "archive-image-url-both",
127 | title: archiveImageUrlTitleToMultiple + (enabledArchivers.length == 2 ? "both" : "all"),
128 | contexts: ["image"]
129 | })
130 |
131 | browser.contextMenus.create({
132 | id: "archive-link-url-both",
133 | title: archiveLinkUrlTitleToMultiple + (enabledArchivers.length == 2 ? "both" : "all"),
134 | contexts: ["link"]
135 | })
136 | }
137 |
138 | function addGhostArchiveContextMenus() {
139 | browser.contextMenus.create({
140 | id: "archive-url-ghost-archive",
141 | title: archiveCurrentUrlTitleToGhostArchive,
142 | contexts: ["page"]
143 | })
144 |
145 | browser.contextMenus.create({
146 | id: "archive-image-url-ghost-archive",
147 | title: archiveImageUrlTitleToGhostArchive,
148 | contexts: ["image"]
149 | })
150 |
151 | browser.contextMenus.create({
152 | id: "archive-link-url-ghost-archive",
153 | title: archiveLinkUrlTitleToGhostArchive,
154 | contexts: ["link"]
155 | })
156 | }
157 |
158 | function addWaybackContextMenus() {
159 | browser.contextMenus.create({
160 | id: "archive-url-wayback",
161 | title: archiveCurrentUrlTitleToWayback,
162 | contexts: ["page"]
163 | })
164 |
165 | browser.contextMenus.create({
166 | id: "archive-image-url-wayback",
167 | title: archiveImageUrlTitleToWayback,
168 | contexts: ["image"]
169 | })
170 |
171 | browser.contextMenus.create({
172 | id: "archive-link-url-wayback",
173 | title: archiveLinkUrlTitleToWayback,
174 | contexts: ["link"]
175 | })
176 | }
177 |
178 | function updateArchiver() {
179 | browser.contextMenus.removeAll();
180 |
181 | if (enabledArchivers.length == 1) {
182 | browser.browserAction.setPopup({popup: ""});
183 |
184 | browser.browserAction.onClicked.addListener(saveCurrentUrl);
185 |
186 | if (enabledArchivers[0] == "archive") {
187 | browser.browserAction.setTitle({title: "Archive to archive." + archiveDomain});
188 |
189 | addArchiveContextMenus();
190 | }
191 | else if (enabledArchivers[0] == "ghostArchive") {
192 | browser.browserAction.setTitle({title: "Archive to Ghost Archive"});
193 |
194 | addGhostArchiveContextMenus();
195 | }
196 | else {
197 | browser.browserAction.setTitle({title: "Archive to Wayback Machine"});
198 |
199 | addWaybackContextMenus();
200 | }
201 | }
202 | else {
203 | browser.browserAction.setPopup({popup: "popup/popup.html"});
204 |
205 | browser.browserAction.onClicked.removeListener(saveCurrentUrl);
206 |
207 | browser.browserAction.setTitle({title: "Archive current URL"});
208 |
209 | for (enabledArchiver of enabledArchivers) {
210 | if (enabledArchiver == "archive") {
211 | addArchiveContextMenus();
212 | }
213 | else if (enabledArchiver == "ghostArchive") {
214 | addGhostArchiveContextMenus();
215 | }
216 | else if (enabledArchiver == "wayback") {
217 | addWaybackContextMenus();
218 | }
219 | }
220 |
221 | addBothArchiveContextMenus();
222 | }
223 | }
224 |
225 | browser.contextMenus.onClicked.addListener(function(info, tab) {
226 | switch (info.menuItemId) {
227 | case "archive-url-archive":
228 | archiveUrlArchive(tab.url);
229 | break;
230 | case "archive-image-url-archive":
231 | archiveUrlArchive(info.srcUrl);
232 | break;
233 | case "archive-link-url-archive":
234 | archiveUrlArchive(info.linkUrl);
235 | break;
236 | case "archive-url-ghost-archive":
237 | archiveUrlGhostArchive(tab.url);
238 | break;
239 | case "archive-image-url-ghost-archive":
240 | archiveUrlGhostArchive(info.srcUrl);
241 | break;
242 | case "archive-link-url-ghost-archive":
243 | archiveUrlGhostArchive(info.linkUrl);
244 | break;
245 | case "archive-url-wayback":
246 | archiveUrlWayback(tab.url);
247 | break;
248 | case "archive-image-url-wayback":
249 | archiveUrlWayback(info.srcUrl);
250 | break;
251 | case "archive-link-url-wayback":
252 | archiveUrlWayback(info.linkUrl);
253 | break;
254 | case "archive-url-both":
255 | archiveUrlToMultiple(tab.url);
256 | break;
257 | case "archive-image-url-both":
258 | archiveUrlToMultiple(info.srcUrl);
259 | break;
260 | case "archive-link-url-both":
261 | archiveUrlToMultiple(info.linkUrl);
262 | break;
263 | }
264 | });
265 |
266 | // Add listener for changes to local storage to update the archiver
267 | browser.storage.onChanged.addListener(checkForArchiverChanges);
268 |
269 | // Read the preferences from local storage
270 | browser.storage.local.get("archiverDomain", function(name) {
271 | archiveDomain = name.archiveDomain;
272 |
273 | if (archiveDomain == undefined) {
274 | archiveDomain = "today";
275 | }
276 |
277 | browser.storage.local.get("enabledArchivers", function(name) {
278 | if ((name.enabledArchivers == undefined) || (name.enabledArchivers == "")) {
279 | enabledArchivers.push("wayback");
280 | }
281 | else {
282 | enabledArchivers = JSON.parse(name.enabledArchivers);
283 | }
284 |
285 | updateArchiver();
286 | });
287 | });
--------------------------------------------------------------------------------