save restore local storage to a local file - javascript

Is there a way to easily save and restore the local storage to a file in jquery or JavaScript?
There are 3 scenarios for this:
testing with a specific local storage
making a backup of the local storage in some specific situations where this data is critical (we want to save in case local cache is deleted)
Setting up another browser from an existing local storage.

I probably would have just tacked this on as a comment to Nathaniel Johnson's answer, but I don't have the reputation yet! With regard with those methods, here are some more simple versions of his functions:
function getLocalStorage() {
return JSON.stringify(localStorage)
}
function writeLocalStorage(data) {
Object.keys(data).forEach(function(key) { localStorage.setItem(key, data[key])})
}

The process for saving and retrieving local storage has two parts.
First you must be able to retrieve the contents of local storage in a form that is manageable in javascript. Since local storage is a map of key-value pairs the easiest way to this is to turn local storage into a javascript object. Then take this object and turn it into a JSON string. What you do with this string is up to you but I find it easiest to just have the user copy the string into an email.
function getLocalStorage() {
var a = {};
for (var i = 0; i < localStorage.length; i++) {
var k = localStorage.key(i);
var v = localStorage.getItem(k);
a[k] = v;
}
var s = JSON.stringify(a);
return s;
}
When I get the string, I use the following function to turn my local storage into a copy of their local storage. Remember to wipe your local storage clean before duplicating their data with a call to localStorage.clear()
function writeLocalStorage(data) {
var o = JSON.parse(data);
for (var property in o) {
if (o.hasOwnProperty(property)) {
localStorage.setItem(property, o[property]);
}
}
}
The last part of your question is how to protect the data from overwriting. You can't write to a local file, however, you can have copy the data into <textarea> and tell the user how to copy and paste the data into a email or a more direct approach.

This javascript below works for me:
function getLocalstorageToFile(fileName) {
/* dump local storage to string */
var a = {};
for (var i = 0; i < localStorage.length; i++) {
var k = localStorage.key(i);
var v = localStorage.getItem(k);
a[k] = v;
}
/* save as blob */
var textToSave = JSON.stringify(a)
var textToSaveAsBlob = new Blob([textToSave], {
type: "text/plain"
});
var textToSaveAsURL = window.URL.createObjectURL(textToSaveAsBlob);
/* download without button hack */
var downloadLink = document.createElement("a");
downloadLink.download = fileName;
downloadLink.innerHTML = "Download File";
downloadLink.href = textToSaveAsURL;
downloadLink.onclick = function () {
document.body.removeChild(event.target);
};
downloadLink.style.display = "none";
document.body.appendChild(downloadLink);
downloadLink.click();
}

Create two bookmarks in Chrome with names e.g. LS BACKUP and LS RESTORE
Put those two snippets in URLs accordingly
javascript:!function(e){var o=document.createElement("textarea"),t=document.getSelection();o.textContent=e,document.body.appendChild(o),t.removeAllRanges(),o.select(),document.execCommand("copy"),t.removeAllRanges(),document.body.removeChild(o)}(JSON.stringify(localStorage)),alert("Local storage is copied to clipboard");
javascript:!function(){let t=prompt("Input local storage backup string");try{t=JSON.parse(t),Object.keys(t).forEach(r=>{try{localStorage.setItem(r,t[r])}catch(a){alert(`Error occurred with the key "${r}" and value "${t[r]}"`)}})}catch(t){alert("Input is not a valid JSON string")}}();
The first one will copy a JSON string to clipboard.
The second one will prompt you to insert a JSON string, which will be parsed and put to local storage.

Related

Automating Photoshop with JS

I had to place videos(mp4-files) in one photoshop document. I thought it would be easier to find a solution with png/jpg, and then project it on mp4. but the fact is that photoshop saving png/jpg and mp4 in different ways. Therefore, despite the fact that there is an import solution, I have difficulties with exporting mp4 by code.
I have 2 arrays of mp4 files and each mp4 from the first array needs to be overlaid on each of the second and saved by mp4. I solved the problem by uploading a video to an open photoshop file with a simple code:
function replaceContents(newFile) {
var docRef = app.open(newFile);
return docRef;
}
function importVideos(order_number) {
var doc = app.activeDocument;
var file = new File('E:/path/' + order_number + '.mp4');
// open a new document with needed video
var docTemp = replaceContents(file);
// copy opend layer with video from new doc to my main doc
var layer = docTemp.activeLayer.duplicate(doc.layerSets.getByName(color), ElementPlacement.PLACEATEND);
// close new unnecessary doc
docTemp.close(SaveOptions.DONOTSAVECHANGES);
layer.name = order_number;
return layer;
}
Here is the code for saving videos and in doExport() doc should be saved as a video.
function Saving(color) {
var array1 = app.activeDocument.layerSets.getByName('s');
var array2 = app.activeDocument.layerSets.getByName(color);
for (i = 0; i < 5; i++) {
array1.artLayers[i].visible = true;
for (j = 0; j < 5; j++) {
array2.artLayers[i].visible = true;
doExport();
array2.artLayers[i].visible = false;
}
array1.artLayers[i].visible = false;
}
}
So a new question: how to export a video from photoshop with a code with the ability to specify the file name and the save path?
P.S. if you do this through Actions, you can't enter input parameters like the name of the saved file, it seals the Action as you did it.
If you know how to create arguments for Actions, you are welcome!

How to execute / access local file from Thunderbird WebExtension?

I like to write a Thunderbird AddOn that encrypts stuff. For this, I already extracted all data from the compose window. Now I have to save this into files and run a local executable for encryption. But I found no way to save the files and execute an executable on the local machine. How can I do that?
I found the File and Directory Entries API documentation, but it seems to not work. I always get undefined while trying to get the object with this code:
var filesystem = FileSystemEntry.filesystem;
console.log(filesystem); // --> undefined
At least, is there a working AddOn that I can examine to find out how this is working and maybe what permissions I have to request in the manifest.json?
NOTE: Must work cross-platform (Windows and Linux).
The answer is, that WebExtensions are currently not able to execute local files. Also, saving to some local folder on the disk is also not possible.
Instead, you need to add some WebExtension Experiment to your project and there use the legacy APIs. There you can use the IOUtils and FileUtils extensions to reach your goal:
Execute a file:
In your background JS file:
var ret = await browser.experiment.execute("/usr/bin/executable", [ "-v" ]);
In the experiment you can execute like this:
var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");
var { FileUtils } = ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
var { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyGlobalGetters(this, ["IOUtils");
async execute(executable, arrParams) {
var fileExists = await IOUtils.exists(executable);
if (!fileExists) {
Services.wm.getMostRecentWindow("mail:3pane")
.alert("Executable [" + executable + "] not found!");
return false;
}
var progPath = new FileUtils.File(executable);
let process = Cc["#mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
process.init(progPath);
process.startHidden = false;
process.noShell = true;
process.run(true, arrParams, arrParams.length);
return true;
},
Save an attachment to disk:
In your backround JS file you can do like this:
var f = messenger.compose.getAttachmentFile(attachment.id)
var blob = await f.arrayBuffer();
var t = await browser.experiment.writeFileBinary(tempFile, blob);
In the experiment you can then write the file like this:
async writeFileBinary(filename, data) {
// first we need to convert the arrayBuffer to some Uint8Array
var uint8 = new Uint8Array(data);
uint8.reduce((binary, uint8) => binary + uint8.toString(2), "");
// then we can save it
var ret = await IOUtils.write(filename, uint8);
return ret;
},
IOUtils documentation:
https://searchfox.org/mozilla-central/source/dom/chrome-webidl/IOUtils.webidl
FileUtils documentation:
https://searchfox.org/mozilla-central/source/toolkit/modules/FileUtils.jsm

Generate logs for web application in Javascript

I have a use case in which I would like to generate logs for my JS web application, which could be stored as a file on the client-side (stored on the user's machine).
Therefore, I want to know that what approach can I follow for generating logs in JS?
If you mean you want to do this from browser-hosted JavaScript code, I'm afraid you can't. Browser-based JavaScript code can't write to arbitrary files on the user's computer. It would be a massive security problem.
You could keep a "log" in web storage, but note that web storage has size limits so you wouldn't want to let it grow too huge.
Here's a barebones logging function that adds to a log in local storage:
function log(...msgs) {
// Get the current log's text, or "" if there isn't any yet
let text = localStorage.getItem("log") || "";
// Add this "line" of log data
text += msgs.join(" ") + "\r\n";
// Write it back to local storage
localStorage.setItem("log", text);
}
Obviously you can then build on that in a bunch of different ways (log levels, date/time logging, etc.).
You can use local storage to simulate file :
Create id for each line of your "file" and store the number of the last line
function logIntoStorage (pMsg) {
if (!pMsg) pMsg = "pMsg is not here !";
if ((typeof pMsg) != "string") pMsg = "pMsg is Not a string:"+(typeof pMsg);
let logNb = "logNb";
let padLong = 7;
let strLg = "0";
let lg = 0;
let maxSize = 50; // max nb of lines in the log
// Reading log num line
strLg = localStorage.getItem(logNb);
if(!strLg) { //logNb not stored yet
lg = 0;
strLg = "0";
localStorage.setItem(logNb, lg.toString(10)); // store the number of cur line
} else { // Read logNb from storage
strLg = localStorage.getItem(logNb);
lg = parseInt(strLg,10);
}
if (lg >= maxSize) {
lg = maxSize; // size limit nb lines.
pMsg = "LIMIT SIZE REACHED";
}
// log msg into localStorage at logLine:0000####
let s = ("0000000000000000"+strLg).substr(-padLong); // padding zeros
localStorage.setItem("logLine:"+s, pMsg);
if (lg >= maxSize) return;
lg++; // point to the next line
localStorage.setItem(logNb, lg.toString(10));
}
In modern Chrome you can actually "stream" data to the user's disk, after they give permission, thanks to the File System Access API.
To do so, you have to request for a file to save to, calling showSaveFilePicker().
Once you get the user's approval you'll receive a handle from where you'll be able to get a WriteableStream.
Once you are done writing, you just have to .close() the writer.
onclick = async () => {
if( !("showSaveFilePicker" in self) ) {
throw new Error( "unsupported browser" );
}
const handle = await showSaveFilePicker();
const filestream = await handle.createWritable();
const writer = await filestream.getWriter();
// here we have a WritableStream, with direct access to the user's disk
// we can write to it as we wish
writer.write( "hello" );
writer.write( " world" );
// when we're done writing
await writer.ready;
writer.close();
};
Live example.

Convert local path URI to File or Blob

I am working on a copy and paste feature for my website, so here is my problem. When i copy an image directly from a webpage it works as it should (the first if statement on the code), but if i am trying to copy a image from my own computer a i get a local path (like the one in the else statement)
$scope.pasteImage = function(eventPaste)
{
$scope.uploading = true;
var promises = [];
var items = (eventPaste.clipboardData || eventPaste.originalEvent.clipboardData).items;
for (var i = 0; i < items.length; i++)
{
var blob = null;
if (eventPaste.originalEvent.clipboardData.items[i].type.indexOf("image") == 0 || eventPaste.originalEvent.clipboardData.items[i] == 0)
{
blob = eventPaste.originalEvent.clipboardData.items[i].getAsFile();
}
else
{
var file = new File("file:///home/oem/testabc/vembly/source/server/images/pregnant.png")
console.log(file)
}
}
console.log(eventPaste)
console.log(blob)
var files = [blob];
uploadService.uploadMultiple(files)
}
so, my question is if its possible to transform that file (else statment) into a blob so i can use it in the uploadMultiple(files) funtction that i have.
No.
It would be a huge security problem if any website could use JavaScript to read data from any file path on your system it happened to guess existed.

Get object URL from FileEntry (or equivalent)

I am currently loading dropped files by doing:
var files = e.dataTransfer.items;
for (var i = 0; i < files.length; i++) {
var file = files[i]; //typeof is 'DataTransferItem'
var url = URL.createObjectURL(file);
}
This gets me the object url, which I can then put into a music player. However, when iterating over an inputted folder:
var reader = entry.createReader();
reader.readEntries(function (res) {
res.forEach(function (entry) {
console.log('The entry:', entry);
console.log('The url:', JSON.stringify(entry.toURL()));
});
});
I get files of type FileEntry. According to this I shall be able to do file.toURL() and use that instead of an object url. This does return me an empty string. this seems to be there for a reason, but I have no idea how to fix this. I see something about a blob URL but I have no idea how that would work.
Example
Try to drag files and folders to the output screen and see it yourself
How I fixed it:
from an entry with typeof FileEntry, we can just do .file(callback), where the first parameter in the callback is of type File, which we can then just create an objectURL from:
var reader = entry.createReader();
reader.readEntries(function (res) {
res.forEach(function (entry) {
entry.file(function(file){ //this does the trick
var obj = URL.createObjectURL(file);
}
});
});
Many thanks to dandavis who provided me his javascript code and the approximate line so I could go look for it myself ;)

Categories