JavaScript FileReader and Dynamic Tables - javascript

I am trying to upload a file and read its contents and then output the contents to a table. The information needs to be place on a new row whenever there is a > char in the string.
I am having a bit of an issue wrapping my head around how I can create a new 'tr' and then add data to the a cell 'td' in that row.
I am stuck on the <tr> and <td> and adding them dynamically with the contents from the file. I am sure I can use regex to look for the > char but that isn't really what I need help with. I am struggling with how I take the information after the > char and add it to a new row in the table.
UPDATE: Ok, so I am still not fully functional on what I am trying to do. I am uploading the file, reading it, and storing the information as an object. However, I can only do this for one instance. When I upload a text file there will be multiple DNA sequences in the file. Each sequence will have a sequence_id like this:
9013e1
ACAAGATGCCATTGTCCCCCGGCCTCCTGCTGCTGCTGCTCTCCGGGGCCACGGCCACCGCTGCCCTGCC
CCTGGAGGGTGGCCCCACCGGCCGAGACAGCGAGCATATGCAGGAAGCGGCAGGAATAAGGAAAAGCAGC
CTCCTGACTTTCCTCGCTTGGTGGTTTGAGTGGACCTCCCAGGCCAGTGCCGGGCCCCTCATAGGAGAGG
AAGCTCGGGAGGTGGCCAGGCGGCAGGAAGGCGCACCCCCCCAGCAATCCGCGCGCCGGGACAGAATGCC
CTGCAGGAACTTCTTCTGGAAGACCTTCTCCTCCTGCAAATAAAACCTCACCCATGAATGCTCACGCAAG
TTTAATTACAGACCTGAA
So, I am trying to read the file, find all sequence ID's and then sequences and I want an editable leading and trailing trim like so:
var objArray = [
{
'id': '>9013e1',
'sequence': 'ACAAGATGCCATTGTCCCCCGGCCT...',
'lead_trim': //get the value from a input from the user,
'trail_trim': //same as above
},
{
//another obj like above
}
]
The sequence also needs to have a line break inserted after every 60 characters. Once I have processed the data in the text file correctly I then need to output the data to a table like I stated in my original post. The problem I am having is I am getting stuck on only being able to store information for one obj in my objArray.
Here is a look at my code...
function scanForSequences(event) {
//Get the file from HTML input tag
var file = event.target.files[0];
var output = document.getElementById('table');
if(file) {
var sequenceArray = [];
var objArray = [];
var obj = {};
var str = '';
var subStr = '';
//Create a new file reader
var reader = new FileReader();
//When the file reader loads
reader.onload = function(evt) {
//Add the contents of file to variable contents
var contentsByLine = evt.target.result.split('\n');
//Alert user the file upload has succeeded
alert('File ' + file.name + ' has been uploaded!');
for(var i = 0; i < contentsByLine.length; i++){
if(contentsByLine[i].charAt(i) == '>'){
obj['id'] = contentsByLine[i];
}else{
sequenceArray.push(contentsByLine[i]);
str = sequenceArray.toString();
subStr += str.substring(0, 60) + '\n';
str = str.substring(60);
obj['sequence'] = subStr;
obj['lead_trim'] = 0;
obj['trail_trim'] = 0;
}
objArray.push(obj);
console.log(objArray);
}
}
reader.readAsText(file);
} else {
alert('Failed to upload file!');
}
console.log(obj);
}
document.getElementById('fileItem').addEventListener('change', scanForSequences, false);

Please find my proposed solution in the fiddle below:
https://jsfiddle.net/w6jbuqfy/
Here's an explanation of what's going on:
First we have a input of type file:
<input id="input" type="file">
We then attach an event listener to it to execute a function once a user has selected a file
var inputElement = document.getElementById("input");
inputElement.addEventListener("change", handleFile, false);
Inside the handleFile function, we use a FileReader to read the file.
var fileList = this.files;
var file = fileList[0];
var fr = new FileReader();
fr.readAsText(file);
Now fileReaders are asynchronous in nature, here i've got a simple interval that checks on the status of the filereader every 100ms.
var checkReadyId = setInterval(function(){
if(fr.readyState === 2){ //done
window.clearInterval(checkReadyId);
addFileDataToResults(fr.result);
} else{
console.log('not done yet');
}
}, 100);
FileReaders are done reading when their readyState is 2. So we check for that and once we are done, we can access the result from FileReader.result. As we read this as a text earlier above, we'll get a string back. We then pass this to our addFileDataToResults function.
function addFileDataToResults(fileAsString){
var resultsDiv = document.getElementById('results');
var tr = document.createElement('tr');
var td = document.createElement('td');
var linesInFile = fileAsString.split('\n');
console.log(linesInFile);
td.textContent = linesInFile[0];
tr.appendChild(td);
resultsDiv.appendChild(tr);
}
What is happening here is that we grab the resultsDiv which is a real node in our HTML. We then use createElement which creates virtual nodes and put data into them. IN this case, we are simply putting the text of the first line into our file. Once we are done creating this virtual nodes, we use appendChild to our real node which turns the virtual node into a real node and you can see it in the html.
Hope this helps
:)

Related

Take variable values and put them in another file

I'm coding the game blockly, I have a variable called lineCount which counts the number of line breaks. however this variable is in a file called lib-dialog.js. When I insert the value of this variable with innerHTML I can get the value of lines by creating a div in the soy.js file (File by which I need to treat the result) But I need this value in a variable to put an if(lines == 6) { }
// Add the user's code.
if (BlocklyGames.workspace) {
var linesText = document.getElementById('dialogLinesText');
linesText.textContent = '';
// Line produces warning when compiling Puzzle since there is no JavaScript
// generator. But this function is never called in Puzzle, so no matter.
var code = Blockly.JavaScript.workspaceToCode(BlocklyGames.workspace);
code = BlocklyInterface.stripCode(code);
var noComments = code.replace(/\/\/[^\n]*/g, ''); // Inline comments.
noComments = noComments.replace(/\/\*.*\*\//g, ''); /* Block comments. */
noComments = noComments.replace(/[ \t]+\n/g, '\n'); // Trailing spaces.
noComments = noComments.replace(/\n+/g, '\n'); // Blank lines.
noComments = noComments.trim();
var lineCount = noComments.split('\n').length;
var pre = document.getElementById('containerCode');
pre.textContent = code;
if (typeof prettyPrintOne == 'function') {
code = pre.innerHTML;
code = prettyPrintOne(code, 'js');
pre.innerHTML = code;
}
if (lineCount == 1) {
var text = BlocklyGames.getMsg('Games_linesOfCode1');
} else {
var text = BlocklyGames.getMsg('Games_linesOfCode2')
.replace('%1', String(lineCount));
}
linesText.appendChild(document.createTextNode(text));
document.getElementById("contarBloco").innerHTML = lineCount;
var contandoBloco = lineCount;
}
I need to take the variable lineCount and put its value in another js.but I'm only managing to insert it into a div with innerHTML
it is better you use localstorage . Set the value of localcount in the local storage and get wherever you want
var lineCount = noComments.split('\n').length;
localStorage.setItem("lineCount", lineCount); // in first file
var count = localStorage.getItem("lineCount") // in second file
with this logic you will get the value but it will be string then for that you either use directly string or convert into integer using parseInt method
parseInt(count);
may be it will help . Thanks
I don't know if your Javascript files are modules, if so, you can return a function in your lib-dialog.js page and return it.
Example
lib-dialog.js =
let Dialog = (function() {
function SetLineCountVariable(LocalLineCount){
LineCount = LocalLineCount;
}
return SetLineCountVariable
})();
And in your soy.js file
let Soy = (function() {
Dialog.SetLineCountVariable(6);
})();
And do not forgot to call your JS file in order in your HTML page
Another way, if you only want the variable result in your another JS file, in your lib-dialog.js, show the result of LineCount in html tag and get it in your another JS file with document.getElementById

Search a Spreadsheet for String and return partial row data

Hello stackoverflow community,
I want to create a script to search a google sheet by name, as this file will be deleted at the end of the script. A new file will be uploaded to google drive automatically every week. This will be the basis for the script that will be running weekly.
The code runs fine, but returns undefined in the 4 output cells.
Example Data from a row in the Spreadsheet "LocafoxInventoryData_Automatic":
1||5b8ff4fc3e578c005487dcd5|60.0000|38.6300|19.0000|||2.0000
I would like to retrieve the last number in the above string. (after the last " | " )
I hope someone can help me out. The strings being searched for are the ids of the products: In the above sample "5b8ff4fc3e578c005487dcd5". This id can only be found twice in the sheet. I want to always retrieve the first one. The differnce between the first and the second product IDs are the first number in the string. There are "1" and "2".
function getData() {
var files = DriveApp.getFilesByName('LocafoxInventoryData_Automatic');
while (files.hasNext()) {
var file = files.next();
var id = file.getId()
}
var sheetData = SpreadsheetApp.openById(id).getActiveSheet().getDataRange().getValues();
var sspre = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Vorlage");
var searchString1 = sspre.getRange('I7').getValue();
var searchString2 = sspre.getRange('I8').getValue();
var searchString3 = sspre.getRange('I9').getValue();
var searchString4 = sspre.getRange('I10').getValue();
for(var i=0;i<sheetData;i++)
{
//Column 1 should be searched
if(sheetData[i][0].search(searchString1)!=-1)
{
var rowData1 = sheetData[i];
return rowData1;
}
else if(sheetData[i][0].search(searchString2)!=-1)
{
var rowData2 = sheetData[i];
return rowData2;
}
else if(sheetData[i][0].search(searchString3)!=-1)
{
var rowData3 = sheetData[i];
return rowData3;
}
else if(sheetData[i][0].search(searchString4)!=-1)
{
var rowData4 = sheetData[i];
return rowData4;
}
}
sspre.getRange('D7').setValue(rowData1);
sspre.getRange('D8').setValue(rowData2);
sspre.getRange('D9').setValue(rowData3);
sspre.getRange('D10').setValue(rowData4);
file.setTrashed(true);
}
Returning Partial Row Data with Regex
Okay this is working for me. I have a file named 'LocafoxInventoryData_Automatic' which is a spreadsheet with one sheet. I look for files with that name and if more than one is found I throw error so that you can figure out which one you want.
I then open up the file as a SpreadSheet with openById. I get the product id from the Vorlage sheet column I7,8,9,10 and I wrap them with a regular expression that looks like this ^1\|\|cw8vtfxa5owglp03btv22g9d.\|\|\|(.)$ . Although in the code the backslashes \ have to be \\ double backslashed which took me a while to figure out.
So that get's the numbers at the end and I put them into Vorlage column D7,8,9,10. And then I set the file isTrashed to true. I don't know if you want to return the data so I left the object in there but commented them out. I also removed all of the else ifs.
function getData() {
var filename='LocafoxInventoryData_Automatic';
var files = DriveApp.getFilesByName(filename);
var n=0;
while (files.hasNext()) {
var file = files.next();
var id = file.getId();
n++;
}
if(n>1){throw(Utilities.formatString('Error: More than file named %s', filename));}//Will present an error if there is more than one file
if(id){
var sheetData = SpreadsheetApp.openById(id).getActiveSheet().getDataRange().getValues();//I assumed no headers in this file
var sspre = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Vorlage");
var re1 = new RegExp('^1\\|\\|' + sspre.getRange('I7').getValue() + '.*\\|\\|\\|(.*)$','i');
var re2 = new RegExp('^1\\|\\|' + sspre.getRange('I8').getValue() + '.*\\|\\|\\|(.*)$','i');
var re3 = new RegExp('^1\\|\\|' + sspre.getRange('I9').getValue() + '.*\\|\\|\\|(.*)$','i');
var re4 = new RegExp('^1\\|\\|' + sspre.getRange('I10').getValue() + '.*\\|\\|\\|(.*$)','i');
for(var i=0;i<sheetData.length;i++){
var rD1=re1.exec(sheetData[i][0]);
if(rD1) {
var rowData1 = rD1[1];
}
var rD2=re2.exec(sheetData[i][0]);
if(rD2) {
var rowData2 = rD2[1];
}
var rD3=re3.exec(sheetData[i][0]);
if(rD3) {
var rowData3 = rD3[1];
}
var rD4=re4.exec(sheetData[i][0]);
if(rD4) {
var rowData4 = rD4[1];
}
}
//var rObj={rowData1:rowData1,rowData2:rowData2,rowData3:rowData3,rowData4:rowData4};
sspre.getRange('D7').setValue(rowData1);
sspre.getRange('D8').setValue(rowData2);
sspre.getRange('D9').setValue(rowData3);
sspre.getRange('D10').setValue(rowData4);
file.setTrashed(true);
//return rObj;
}
}
Regular Expression exec method
RegExp
By the way it's quite helpful with sort of a problem to have your own regex tester written in the same language you happen to be developing in. I'm sorry it took me so long. If you run into additional problems let me know.

how to break up the content of a long text file to fit into multiple variables in google apps script?

I have a very long plain text file in my google drive which I need to parse through and select pieces of information through a script. I have successfully pulled out the text and put it into a string variable, but it is so long that the variable only contains about 1/6 of the full document.
This is the code I am using:
function f09ToSpreadsheet() {
var allFilesInFolder,cntFiles,docContent,fileNameToGet,fldr,
thisFile,whatFldrIdToUse;//Declare all variable at once
whatFldrIdToUse = '0B2O23fJ4nQLONlA4RlhuLWp0Y0k';
fileNameToGet = 'Copy of RS_Tionesta_1N.txt';//Assign the name of the file to get to a variable
//Get a reference to the folder
fldr = DriveApp.getFolderById(whatFldrIdToUse);
//Get all files by that name. Put return into a variable
//allFilesInFolder = fldr.getFilesByName(fileNameToGet);
allFilesInFolder = fldr.getFiles();
//Logger.log('allFilesInFolder: ' + allFilesInFolder);
if (allFilesInFolder.hasNext() === false) {
//If no file is found, the user gave a non-existent file name
return false;
};
cntFiles = 0;
//Even if it's only one file, must iterate a while loop in order to access the file.
//Google drive will allow multiple files of the same name.
while (allFilesInFolder.hasNext()) {
Logger.log("yup")
var thisFile = allFilesInFolder.next();
//KEY TO READING TEXT FROM .F05 & .F09 ->
docContent = thisFile.getAs("application/octet-stream");
var string = docContent.getDataAsString();
Logger.log('docContent : ' + string );
};
}
The "string" object, when printed to the log, only contains the first part of the text doc.
Is there any way to, say, split up the document into small pieces and store each part in a variable?
I'm afraid I've not tested this so apologies if it doesn't work straight away but could you get your document paragraph by paragraph and append the text like that?
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var paras = body.getParagraphs();
paras.forEach(function( para ){
var text = para.getText();
populateSheet( text );
});

Extracting img urls from webpage using Google Apps Script

This is an Apps Script that goes through a webpage and collects img urls that are inside some div of a special class.
function getIMGs(url){
var url = 'url'
var result = UrlFetchApp.fetch(url);
if (result.getResponseCode() == 200) {
var doc = Xml.parse(result, true);
var bodyHtml = doc.html.body.toXmlString();
var doc = XmlService.parse(bodyHtml);
var html = doc.getRootElement();
var thumbs = getElementsByClassName(html, 'thumb');
var sheet = SpreadsheetApp.getActiveSheet();
for (i in Thumbs) {
var output = '';
var linksInMenu = getElementsByTagName(thumbs[i], 'img');
for(i in linksInMenu) {
output += XmlService.getRawFormat().format(linksInMenu[i]);
}
var linkRegExp = /data-src="(.*?)"/;
var dataSrc = linkRegExp.exec(output);
sheet.appendRow([dataSrc[1]]);
}
}
So first the code gets the html, and uses an auxiliary function to get certain elements, which look like this:
<div class="thumb"><div class="loader"><span class="icon-uniE611"></span></div><img src="//xxx" data-src="https://xxx/8491a83b1cacc2401907997b5b93e433c03c91f.JPG" data-target="#image-slider" data-slide-to="0"></div>
Then the code gets the img elements, and finally extracts the data-src address via RegExp.
While this kinda works, I have a problem:
1) After 9 loops it crashes, on the appendRow line, as the last 4 Thumbs elements don't have data-src, hence what i'm trying to write into the spreadsheet is null.
Any solution for this? I have fixed it for the moment by just doing 9 iterations only of the For loop, but this is far from optimal, as it's not automated and required me to go through the page to count the elements with data-src.
Also, any suggestion of a more elegant solution will be appreciated! I will be really grateful for any helping hand!
Cheers

How do I focus another document with photoshop javascript scripting?

This following script almost does what I need. What I'm trying to do is go through the opened documents, 139 of them, and save them as jpeg. However what it's lacking is moving from one opened document to the other, so it saved the same image over 139 times. I assumed doc.close() would close the opened document and give a new one focus, but it doesn't.
Here's the code:
var destination = "C:/Documents and Settings/Administrator/My Documents/small images"
for(var i = 0; i < 5; i++)
{
doc = documents[i];
name_ = doc.name.substring(0, doc.name.indexOf('.'))
saveForWebPNG(destination, name_);
doc.close();
}
function saveForWebPNG(outputFolderStr, filename)
{
var opts, file;
opts = new ExportOptionsSaveForWeb();
opts.format = SaveDocumentType.JPEG;
opts.quality = 60;
if (filename.length > 27) {
file = new File(outputFolderStr + "/temp.jpg");
activeDocument.exportDocument(file, ExportType.SAVEFORWEB, opts);
file.rename(filename + ".jpg");
}
else {
file = new File(outputFolderStr + "/" + filename + ".jpg");
activeDocument.exportDocument(file, ExportType.SAVEFORWEB, opts);
}
}
According to the Adobe Photoshop CS2 JavaScript Scripting Guide it looks like you need to assign to the Application.activeDocument property to make that document the currently selected one for any actions. This makes sense since you're using that property in the saveForWebPNG function without explicitly activating the document in the iterator in the first block. It might be as simple as the following change:
for (var i = 0; i < 5; i++) {
var doc = documents[i];
app.activeDocument = doc; // Select that document.
var name = doc.name.substring(0, doc.name.indexOf('.'))
saveForWebPNG(destination, name);
doc.close();
}
However, I don't have a copy of Photoshop and haven't verified this solution.
I know this is a lot late, but I just came across this question and feel like I might have a solution that someone down the road may be able to use. So here goes.
One solution is to adjust the for loop. Let's say there are 5 documents open. app.documents.length would be 5. When you close one, the length is now 4, then 3, etc. i is counting up as app.documents.length is decreasing. When i = 3, app.documents.length = 2. I think that iterating backwards would do the trick.
for (i = app.documents.length - 1; i >= 0; i--) { ... }
The answer from #maerics is correct.
However, if you don't know the index of the given document you can reference it by name like in this example:
// Assume 'hello.psd' and 'world.psd' are in same folder at script.
// Open the first file. It is the active document.
var scriptFile = new File($.fileName)
var scriptPath = scriptFile.parent.fsName
var file1obj = File(scriptPath + '/hello.psd')
var file1 = open(file1obj)
// Open the second file. The second file is now the active document.
var file2obj = File(scriptPath + '/world.psd')
var file2 = open(file2obj)
// Make the first file the active document
app.activeDocument = file1
// Make the second file the active document
app.activeDocument = file2
+1 for jbiz's solution. I couldn't figure out why my loop wouldn't complete.
for (i=app.documents.length-1; i >= 0; i--) {
doc = app.documents[i];
app.activeDocument = doc;
...
do whatever you need, save & close
...
}
app.documents.length gets shorter with every iteration though the loop if you close the document when you're done.
You want to close the current selected (or active) document:
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);

Categories

Resources