Added proper alert messages and improved security of import file.
BIN
src/images/icons/delete.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
src/images/icons/download.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
src/images/icons/edit.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
src/images/icons/import.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
src/images/icons/save.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
src/images/icons/sessionManager.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
src/images/icons/sessionManager48x48.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/images/icons/sessionManager96x96.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
34
src/manifest.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": " Easy Session Manager",
|
||||
"version": "0.0.5",
|
||||
"description": " Easy Session Manager allows you to manage your Firefox session by backing up or loading your saved sessions.",
|
||||
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "sessionManager@itdominator.com",
|
||||
"strict_min_version": "57.0"
|
||||
}
|
||||
},
|
||||
|
||||
"icons": {
|
||||
"48": "images/icons/sessionManager48x48.png",
|
||||
"96": "images/icons/sessionManager96x96.png",
|
||||
"512": "images/icons/sessionManager.png"
|
||||
},
|
||||
|
||||
"permissions": [
|
||||
"tabs",
|
||||
"storage",
|
||||
"unlimitedStorage"
|
||||
],
|
||||
|
||||
"background": { "page": "pages/import.html" },
|
||||
|
||||
"browser_action": {
|
||||
"default_icon": "images/icons/sessionManager.png",
|
||||
"default_title": " Easy Session Manager",
|
||||
"default_popup": "pages/sessionManager.html"
|
||||
}
|
||||
|
||||
}
|
34
src/pages/import.html
Normal file
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Easy Session Manager Import</title>
|
||||
<link rel="shortcut icon" href="../images/icons/import.png">
|
||||
<link rel="stylesheet" href="../styles/styles.css"/>
|
||||
|
||||
<style media="screen">
|
||||
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0em;
|
||||
margin: 0em;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container" name="import">
|
||||
<h1 id="lableTag">Select File</h1>
|
||||
<input id="inputId" type="file" enctype='multipart/form-data' multiple accept="application/json"/>
|
||||
</div>
|
||||
|
||||
<span id="allertMessage">
|
||||
|
||||
</span>
|
||||
|
||||
<script src="../scripts/background.js"></script>
|
||||
</body>
|
||||
</html>
|
45
src/pages/sessionManager.html
Executable file
@@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../styles/styles.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center>
|
||||
<button type="button" name="import">
|
||||
Import <img class="icon" src="../images/icons/import.png" alt="Import JSON"/>
|
||||
<input id="inputId" type="file" />
|
||||
</button>
|
||||
|
||||
<button type="button" name="save">
|
||||
Save <img class="icon" src="../images/icons/save.png" alt="Save Image"/>
|
||||
</button>
|
||||
<button type="button" name="download">
|
||||
Download <img class="icon" src="../images/icons/download.png" alt="Download Image"/>
|
||||
</button>
|
||||
|
||||
<div id="savedSessions">
|
||||
|
||||
</div>
|
||||
|
||||
<span id="allertMessage">
|
||||
|
||||
</span>
|
||||
|
||||
<button type="button" name="edit">
|
||||
Edit <img class="icon" src="../images/icons/edit.png" alt="Edit Image"/>
|
||||
</button>
|
||||
|
||||
<button type="button" name="delete">
|
||||
Delete <img class="icon" src="../images/icons/delete.png" alt="Delete Image"/>
|
||||
</button>
|
||||
</center>
|
||||
|
||||
|
||||
<a id="downloadAnchorElem" href="#"></a>
|
||||
<script src="../scripts/events.js"></script>
|
||||
<script src="../scripts/sessionManager.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
76
src/scripts/background.js
Normal file
@@ -0,0 +1,76 @@
|
||||
const regexp = /^[a-zA-Z0-9-_]+$/; // Alphanumeric, dash, underscore
|
||||
|
||||
|
||||
const alertMessage = (type, message) => {
|
||||
let msgTag = document.getElementById("allertMessage");
|
||||
let text = document.createTextNode(message);
|
||||
let fontColor = "rgba(255, 255, 255, 1)";
|
||||
let bgColor = "";
|
||||
|
||||
if (type === "success") {
|
||||
bgColor = "rgba(72, 125, 25, 1)";
|
||||
} else if (type === "warning") {
|
||||
bgColor = "rgba(195, 123, 0, 1)";
|
||||
} else if (type === "error") {
|
||||
bgColor = "rgba(125, 45, 25, 1)";
|
||||
}
|
||||
|
||||
msgTag.style.backgroundColor = bgColor;
|
||||
msgTag.style.color = fontColor;
|
||||
msgTag.style.display = "block";
|
||||
msgTag.append(text);
|
||||
|
||||
setTimeout(function () {
|
||||
let msgTag = document.getElementById("allertMessage");
|
||||
msgTag.innerHTML = "";
|
||||
msgTag.style.display = "none";
|
||||
}, 4000);
|
||||
}
|
||||
|
||||
const processor = (obj, enteryName = '') => {
|
||||
let data = obj.target.result;
|
||||
|
||||
do {
|
||||
enteryName = prompt("What is this session's name? Allowed: a-z, A-Z, -, _", '' + enteryName);
|
||||
if (enteryName == null) break
|
||||
} while (enteryName.search(regexp) == -1);
|
||||
|
||||
if (enteryName) {
|
||||
try {
|
||||
console.log("Importing session...");
|
||||
JSON.parse(data);
|
||||
browser.storage.local.set({[enteryName]: data});
|
||||
alertMessage("success", "Imported file successfully.")
|
||||
} catch (e) {
|
||||
alertMessage("error", "Failed to import data. Not a JSON parsable file.");
|
||||
return ;
|
||||
}
|
||||
} else {
|
||||
alertMessage("warning", "Canceled import.");
|
||||
}
|
||||
};
|
||||
|
||||
document.getElementById("inputId").onchange = (e) => {
|
||||
let size = e.target.files.length;
|
||||
let fileArry = e.target.files;
|
||||
|
||||
for (var i = 0; i < size; i++) {
|
||||
let reader = new FileReader();
|
||||
let name = fileArry[i].name;
|
||||
name = name.split(".")[0];
|
||||
|
||||
reader.onloadend = (obj) => { processor(obj, name); };
|
||||
|
||||
if (fileArry[i].type == "application/json")
|
||||
reader.readAsText(fileArry[i], {encoding: "string"});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
document.addEventListener("click", (e) => {
|
||||
if (e.button == 0) { // Left click
|
||||
if (e.target.className == "container") {
|
||||
document.getElementById("inputId").click();
|
||||
}
|
||||
}
|
||||
});
|
41
src/scripts/events.js
Normal file
@@ -0,0 +1,41 @@
|
||||
let selectedItem = null;
|
||||
|
||||
document.addEventListener("click", (e) => {
|
||||
if (e.button == 0) { // Left click
|
||||
if (e.target.tagName == "LI") {
|
||||
if (selectedItem) {
|
||||
if (selectedItem == e.target && selectedItem.className == "selected") {
|
||||
selectedItem.setAttribute("class", "");
|
||||
} else {
|
||||
selectedItem.setAttribute("class", "");
|
||||
selectedItem = e.target;
|
||||
selectedItem.setAttribute("class", "selected");
|
||||
}
|
||||
} else {
|
||||
selectedItem = e.target;
|
||||
selectedItem.setAttribute("class", "selected");
|
||||
}
|
||||
} else if (e.target.name == "save") {
|
||||
saveSession();
|
||||
} else if (e.target.name == "import") {
|
||||
importSession();
|
||||
} else if (selectedItem) {
|
||||
if (e.target.name == "download")
|
||||
downloadSession();
|
||||
else if (e.target.name == "delete")
|
||||
deleteFromStorage();
|
||||
else if (e.target.name == "edit")
|
||||
editSession();
|
||||
} else {
|
||||
alertMessage("warning", "Select a session first...");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("dblclick", (e) => {
|
||||
if (e.button == 0) { // Left click
|
||||
if (e.target.tagName == "LI") {
|
||||
loadSession(e.target.innerHTML.trim());
|
||||
}
|
||||
}
|
||||
});
|
187
src/scripts/sessionManager.js
Normal file
@@ -0,0 +1,187 @@
|
||||
const regexp = /^[a-zA-Z0-9-_]+$/; // Alphanumeric, dash, underscore
|
||||
const storage = browser.storage.local;
|
||||
const windowSys = browser.windows;
|
||||
|
||||
|
||||
const alertMessage = (type, message) => {
|
||||
let msgTag = document.getElementById("allertMessage");
|
||||
let text = document.createTextNode(message);
|
||||
let fontColor = "rgba(255, 255, 255, 1)";
|
||||
let bgColor = "";
|
||||
|
||||
if (type === "success") {
|
||||
bgColor = "rgba(72, 125, 25, 1)";
|
||||
} else if (type === "warning") {
|
||||
bgColor = "rgba(195, 123, 0, 1)";
|
||||
} else if (type === "error") {
|
||||
bgColor = "rgba(125, 45, 25, 1)";
|
||||
}
|
||||
|
||||
msgTag.style.backgroundColor = bgColor;
|
||||
msgTag.style.color = fontColor;
|
||||
msgTag.style.display = "block";
|
||||
msgTag.append(text);
|
||||
|
||||
setTimeout(function () {
|
||||
let msgTag = document.getElementById("allertMessage");
|
||||
msgTag.innerHTML = "";
|
||||
msgTag.style.display = "none";
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
const saveSession = () => {
|
||||
let enteryName = '';
|
||||
|
||||
do {
|
||||
enteryName = prompt("What is this session's name? Allowed: a-z, A-Z, -, _",
|
||||
new Date().toLocaleString().split(',')[0].replace(/\//g, '-'));
|
||||
if (enteryName == null) break
|
||||
} while (enteryName.search(regexp) == -1);
|
||||
|
||||
if (enteryName) {
|
||||
console.log("Saving session...");
|
||||
windowSys.getAll({ populate: true, windowTypes: ["normal"] }).then((windows) => {
|
||||
let sessionData = {};
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
let links = [];
|
||||
for (var ii = 0; ii < windows[i].tabs.length; ii++) {
|
||||
if (!windows[i].tabs[ii].url.includes("about:")) {
|
||||
links.push(
|
||||
{"link" : windows[i].tabs[ii].url.trim()}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
sessionData["WindowID:" + windows[i].id] = links;
|
||||
}
|
||||
saveToStorage(enteryName, JSON.stringify(sessionData));
|
||||
}).then(() => {
|
||||
if (document.getElementsByName(enteryName).length == 0) {
|
||||
appendToSavedSessionsList(enteryName);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
alertMessage("warning", "Canceled save...");
|
||||
}
|
||||
}
|
||||
|
||||
const saveToStorage = (name, data) => {
|
||||
storage.set({[name]: data});
|
||||
alertMessage("success", "Saved session...");
|
||||
}
|
||||
|
||||
const importSession = () => {
|
||||
browser.tabs.create({
|
||||
url: browser.extension.getURL("../pages/import.html"),
|
||||
active: true
|
||||
});
|
||||
}
|
||||
|
||||
const downloadSession = () => {
|
||||
var dlAnchorElem = document.getElementById('downloadAnchorElem');
|
||||
let id = selectedItem.innerHTML;
|
||||
fileName = "session:" + id + ":" +
|
||||
new Date().toLocaleString().split(',')[0]
|
||||
.replace(/\//g, "-") + ".json";
|
||||
|
||||
storage.get(id).then((storageResults) => {
|
||||
let json = JSON.parse(storageResults[id]);
|
||||
let dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(json));
|
||||
dlAnchorElem.setAttribute("href", dataStr);
|
||||
dlAnchorElem.setAttribute("download", fileName);
|
||||
dlAnchorElem.click();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
const deleteFromStorage = () => {
|
||||
let action = confirm("Do you wish to delete session: " + selectedItem.innerHTML + "?");
|
||||
|
||||
if (action) {
|
||||
storage.remove(selectedItem.innerHTML).then(() => {
|
||||
selectedItem.parentElement.removeChild(selectedItem);
|
||||
});
|
||||
alertMessage("success", "Deleted session successfully...");
|
||||
} else {
|
||||
alertMessage("warning", "Canceled deletion...");
|
||||
}
|
||||
}
|
||||
|
||||
const editSession = () => {
|
||||
let id = selectedItem.innerHTML;
|
||||
let newName = '';
|
||||
|
||||
do {
|
||||
newName = prompt("Editing selected session... Allowed: a-z, A-Z, -, _", id);
|
||||
if (newName == null) break
|
||||
} while (newName.search(regexp) == -1);
|
||||
|
||||
if (newName) {
|
||||
storage.get(id).then((storageResults) => {
|
||||
storage.remove(id);
|
||||
json = JSON.parse(storageResults[id]);
|
||||
saveToStorage(newName, JSON.stringify(json));
|
||||
});
|
||||
selectedItem.textContent = newName;
|
||||
} else {
|
||||
alertMessage("warning", "Canceled edit...");
|
||||
}
|
||||
}
|
||||
|
||||
const loadSession = (id = null) => {
|
||||
console.log("Loading session...");
|
||||
try {
|
||||
storage.get(id).then((storageResults) => {
|
||||
let json = JSON.parse(storageResults[id]);
|
||||
let keys = Object.keys(json);
|
||||
|
||||
browser.windows.getAll().then((windows) => {
|
||||
windowSys.getCurrent({populate: true}).then((currentWindow) => {
|
||||
// Clear out windows
|
||||
for (var i = 0; i < windows.length; i++) {
|
||||
if (currentWindow.id != windows[i].id) {
|
||||
windowSys.remove(windows[i].id);
|
||||
}
|
||||
}
|
||||
}, windows);
|
||||
});
|
||||
|
||||
// Open windows and populate with proper tabs
|
||||
keys.forEach((key) => {
|
||||
let store = json[key];
|
||||
let urls = [];
|
||||
|
||||
for (var i = 0; i < store.length; i++) {
|
||||
urls.push(store[i].link);
|
||||
}
|
||||
|
||||
windowSys.create({ url: urls });
|
||||
});
|
||||
|
||||
// Finalize clear out windows
|
||||
windowSys.getCurrent({populate: true}).then((currentWindow) => {
|
||||
windowSys.remove(currentWindow.id);
|
||||
});
|
||||
});
|
||||
} catch (e) { console.log(e); }
|
||||
}
|
||||
|
||||
const getSavedSessionIDs = () => {
|
||||
console.log("Getting saved sessions...");
|
||||
storage.get(null).then((storageResults) => {
|
||||
let keys = Object.keys(storageResults);
|
||||
for (let key of keys) {
|
||||
appendToSavedSessionsList(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const appendToSavedSessionsList = (enteryName) => {
|
||||
let liTag = document.createElement("LI");
|
||||
let text = document.createTextNode(enteryName);
|
||||
liTag.setAttribute("name", enteryName);
|
||||
liTag.append(text);
|
||||
document.getElementById("savedSessions").append(liTag);
|
||||
}
|
||||
|
||||
getSavedSessionIDs();
|
74
src/styles/styles.css
Normal file
@@ -0,0 +1,74 @@
|
||||
body { width: 450px; }
|
||||
ul, li { list-style: none; }
|
||||
|
||||
li {
|
||||
background-color: #0a1827;
|
||||
color: #ffffff;
|
||||
margin: 1em 0em;
|
||||
padding: 1.5em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
li:hover {
|
||||
background-color: #1e4573;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
#allertMessage {
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
z-index: 999;
|
||||
width: 50%;
|
||||
left: 25%;
|
||||
padding: 0.5em;
|
||||
text-align: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#savedSessions {
|
||||
max-height: 15em;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#inputId {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#lableTag {
|
||||
top: 48%;
|
||||
margin: 0 auto;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url('../images/icons/import.png');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
text-align: center;
|
||||
background-color: rgba(41, 95, 115, 0.85);
|
||||
transition: 0.6s;
|
||||
}
|
||||
|
||||
.container:hover {
|
||||
transition: 0.6s;
|
||||
background-color: rgba(41, 95, 115, 0.65);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: #a3b83b;
|
||||
box-shadow: 0px 5px 5px 5px #444444;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|