document generation only works the first time - javascript

I'm using openxml in my HTML5 mobile app to generate word documents on the mobile device.
In general openxml works fine and straight forward, but I'm struggling with an annyoing problem.
The document generation only works the first time after I've started the app. This time I can open and view the document. Restart the app means:
- Redeploy from development machine
- Removing the app from the task pane (pushing aside; I assume the app is removed then?)
The second time I get the message the document is corrupted and I'm unable to view the file
UPDATE:
I can't reproduce this behaviour when I'm running the app connected to the remote debugger without having a breakpoint set. Doing it this way I always get a working document.
I doesn't make a difference wether I do any changes on the document or not. Simply open and saving reproduce this error.
After doing some research I've found that structure of the docx.zip file of the working and the corrupt file is the same. They also have the same file length. But in the corrupt docx there are some files I've found some files having a wrong/invalid CRC. See here an example when trying to get a corrupt file out of the zip. Other files are working as expected.
The properties for this file are->
(CRC in a working version is: 44D3906C)
Code for processing the doc-template:
/*
* Process the template
*/
function processTemplate(doc64, callback)
{
"use strict";
console.log("PROCESS TEMPLATE");
var XAttribute = Ltxml.XAttribute;
var XCData = Ltxml.XCData;
var XComment = Ltxml.XComment;
var XContainer = Ltxml.XContainer;
var XDeclaration = Ltxml.XDeclaration;
var XDocument = Ltxml.XDocument;
var XElement = Ltxml.XElement;
var XName = Ltxml.XName;
var XNamespace = Ltxml.XNamespace;
var XNode = Ltxml.XNode;
var XObject = Ltxml.XObject;
var XProcessingInstruction = Ltxml.XProcessingInstruction;
var XText = Ltxml.XText;
var XEntity = Ltxml.XEntity;
var cast = Ltxml.cast;
var castInt = Ltxml.castInt;
var W = openXml.W;
var NN = openXml.NoNamespace;
var wNs = openXml.wNs;
var doc = new openXml.OpenXmlPackage(doc64);
// add a paragraph to the beginning of the document.
var body = doc.mainDocumentPart().getXDocument().root.element(W.body);
var tpl_row = ((doc.mainDocumentPart().getXDocument().descendants(W.tbl)).elementAt(1).descendants(W.tr)).elementAt(2);
var newrow = new XElement(tpl_row);
doc.mainDocumentPart().getXDocument().descendants(W.tbl).elementAt(1).add(newrow);
// callback(doc);
var mod_file = null;
var newfile;
var path;
if (doc != null && doc != undefined ) {
mod_file = doc.saveToBlob();
// Start writing document
path = "Templates";
newfile = "Templates/Bau.docx";
console.log("WRITE TEMPLATE DOCUMENT");
fs.root.getFile("Templates/" + "MyGenerated.docx", {create: true, exclusive: false},
function(fileEntry)
{
fileEntry.createWriter(
function(fileWriter)
{
fileWriter.onwriteend = function(e) {
console.log("TEMPLATE DOCUMENT WRITTEN:"+e.target.length);
};
fileWriter.onerror = function(e) {
console.log("ERROR writing DOCUMENT:" + e.code + ";" + e.message);
};
var blobreader = new FileReader();
blobreader.onloadend = function()
{
fileWriter.write(blobreader.result); // reader.result contains the contents of blob as a typed array
};
blobreader.readAsArrayBuffer(mod_file);
},
null);
}, null);
};
Any ideas what I'm doing wrong?

Thanks for posting about the error. There were some issues with jszip.js that I encountered when I was developing the Open XML SDK for JavaScript.
At the following link, there is a sample javascript app that demonstrates generating a document.
Open XML SDK for JavaScript Demo
In that app you can save multiple DOCXs, one after another, and they are not corrupted.
In order to work on this issue, I need to be able to re-produce locally. Maybe you can take that little working web app and replace parts with your parts until it is generating invalid files?
Cheers, Eric
P.S. I am traveling and have intermittent access to internet. If you can continue the thread on OpenXmlDeveloper.org, then it will help me to answer quicker. :-)

What made it work for me, was changing the way of adding images (Parts) to the document. I was using the type "binary" for adding images to document. I changed this to "base64"
So I changed the source from:
mydoc.addPart( "/word/"+reltarget, openXml.contentTypes.png, "binary", fotodata ); // add Image Part to doc
to:
mydoc.addPart( "/word/"+reltarget, openXml.contentTypes.png, "base64", window.btoa(fotodata) ); // add Image Part to doc

Related

Google Script: How to script an automatic import from a txt in my drive into spreadsheet?

I've never used Javascript before and i've been trying for ages to do this but with no luck, and I can't find any previous people trying.
I want to copy the text data straight from this txt document in my drive, it is possible to do this fine manually but I want it to be done daily automatically instead.
The text document;
Boxes Made,3
Target Percentage,34
Hourly Rate,2
If I import this into a spreadsheet with these settings its perfect;
Import Settings
And it imports like this;
After Import
Now I need to try and automate this so that a script imports it automatically.
The script I have so far doesn't work, please help.
Current script;
function AutoImporter (Source)
{
var Source = DriveApp.getFilesByName('DailyData.txt');
var TextContents = Source.copyText();
var Target = SpreadsheetApp.getActiveSheet();
Target.appendText(TextContents[1]);
}
--edit
Some guy just sent me a script that seems closer but still didn't work;
function autoCSV() {
var ss=SpreadsheetApp.getActiveSpreadsheet();
var s=ss.getActiveSheet();
var r=s.getActiveCell();
var id="DailyData.txt";//<<<<<enter the ID of the text file
var f3=DriveApp.getFileById(id);
var lst1=f3.getBlob().getDataAsString().split('\n').map(function(x) {return x.split(',')});
var ncols=1,i,lst2=[];
for (i in lst1) {if (lst1[i].length>ncols) ncols=lst1[i].length;}
for (i=0;i<ncols;i++) lst2.push('');
for (i in lst1) lst1[i]=lst1[i].concat(lst2.slice(0,lst2.length-lst1[i].length));
s.getRange(r.getRow(), r.getColumn(), lst1.length, ncols).setValues(lst1);
}
You may read text file from Google Drive this way:
'use strict'; // <- Always use strict mode.
function foo() {
var fileName = 'DailyData.txt';
var files = DriveApp.getFilesByName(fileName);
if (!files.hasNext()) {
throw new Error('No file with name:' + fileName);
}
// We take only the first file among all files with such name.
var file = files.next();
var text = file.getBlob().getDataAsString('utf8');
Logger.log(text);
// Now you have to parse the file.
}
Documentation:
DriveApp.getFilesByName returns collection of Files.
File.getBlob returns Blob.
Blob.getDataAsString returns String.

How can I set a folder for After Effects to watch for JSON/text files?

I'm successfully using the following extend-script (with json2.js) to read a local JSON file, and change a text layer in my project. How could I modify this script so that, when ran, it continuously 'watches' for new JSON files that are added to the directory, and runs the rest of the script?
#include "json2.js" // jshint ignore:line
var script_file = File($.fileName); // get the location of the script file
var script_file_path = script_file.path; // get the path
var file_to_read = File(script_file_path + "/unique-job-id.json");
var my_JSON_object = null; // create an empty variable
var content; // this will hold the String content from the file
if(file_to_read !== false){// if it is really there
file_to_read.open('r'); // open it
content = file_to_read.read(); // read it
my_JSON_object = JSON.parse(content);// now evaluate the string from the file
//alert(my_JSON_object.arr[1]); // if it all went fine we have now a JSON Object instead of a string call length
var theComposition = app.project.item(1);
var theTextLayer = theComposition.layers[1];
theTextLayer.property("Source Text").setValue(my_JSON_object.arr[2]);
file_to_read.close(); // always close files after reading
}else{
alert("Error reading JSON"); // if something went wrong
}
Look at the Object Model:
Application scheduleTask() method
app.scheduleTask(stringToE xecute, delay, repeat)
Description:
Schedules the specified JavaScript for delayed execution.
So app.scheduleTask(string,delay,true) is exactly what you are looking for.Like this:
app.schduleTask('taskToWatchFile()',1000,true);
function taskToWatchFile(){
/*
*Add your code here
*/
}

Disable the possibility to upload files for user

I'm building a service for users where I must have private files.
Actually, with Cloud Code, I can control the download flux, through a function. But, how I can prevent a hacker to use the javascript console and upload his files ? He will get a link, which he can share with anyone without restriction and at my charges.
const file = Parse.File('hackerFile', hackerFileArray);
file.save().then(() => console.log(file.url)) // Now, he have a free file hosting.
Is there a way to completely remove this feature for everyone, except the master key ?
Example of hosting a file on http://todolist.parseapp.com/
Open the console in your browser then
var script = document.createElement('script');
script.src = '//www.parsecdn.com/js/parse-1.6.14.min.js'; // Because of their version.
document.head.appendChild(script);
Parse.initialize("0Oq3tTp9JMvd72LOrGN25PiEq9XgVHCxo57MQbpT", "vUFy2o7nFx3eeKVlZneYMPI2MBoxT5LhWNoIWPja"); // Found in their sources
var reader = new FileReader();
var input = document.createElement('input');
input.type = 'file';
document.body.appendChild(input);
// Then choose a file from the browser. I choosen a picture.
reader.onloadend = function() {
var file = new Parse.File('hackFile', {base64: reader.result});
file.save().then(function() {
console.log(file.url());
})
};
reader.readAsDataURL(input.files[0]);
Then you have a link. I got http://files.parsetfss.com/ae2ddbce-9cc0-4e1a-a16d-52ec5fdb7570/tfss-8fccfba0-ccf7-41cd-8f42-75f0a3478262-hackFile
Haven't tried this, but think it could work:
1) Add a beforeSave function on whatever class you're looking to prevent this behavior on.
2) In the beforeSave, check request.object.dirtyKeys() and iterate through each of those keys on the newly created object.
3) If the value associated with one of those dirtyKeys is a file, don't allow the file to save: response.error
Parse.Cloud.beforeSave(Parse.User, function(request, response) {
var dirtyKeys = request.object.dirtyKeys();
for (var i = 0; i < dirtyKeys.length; ++i) {
var dirtyKey = dirtyKeys[i];
if (isUnwantedFile(request.object, dirtyKey)) {
response.error("User is not allowed to store files");
return;
}
}
response.success();
});
//note this function is untested -- I'm not sure what type a user-created file would be,
//but basically if you can figure that out, substitute it in here
function isUnwantedFile(obj, key){
return typeof obj[dirtyKey] === Parse.File
}

Is Parse's Javascript file upload broken?

I've been trying to save a user-uploaded image to parse for the longest time, and nothing seems to work -- even when following their documentation.
Below is the handler I use for the onChange() on a multiple file upload. At first I was concerned about multiple file uploads, but at this point just saving one image doesn't work.
function fileHandler(event) {
var files = event.target.files;
stopPictures = [];
$("#stop-img-container").empty();
if (files[0] != null) {
$("#stop-img-container").show();
for (var i = 0; i < files.length; i++) {
var file = files[i];
var picReader = new FileReader();
picReader.addEventListener("load",function(event){
var picFile = event.target;
var image = $("<img/>",{
"title": picFile.name,
"class": "stop-image",
"src": picFile.result
}).appendTo("#stop-img-container");
var name = picFile.name;
var dataFile = picFile.result;
var base64str = dataFile.substring(dataFile.indexOf("base64,")+7,dataFile.length);
var parseFile = new Parse.File(name,{base64:base64str}); // saving logs 404 Not Found from POST to "http://api.parse.com/1/files"
var parseFile = new Parse.File(name,dataFile); // saving logs "Uncaught Creating a Parse.File from a String is not yet supported."
var parseFile = new Parse.File(name,file); // saving logs 404 Not Found from POST to "http://api.parse.com/1/files"
var parseFile = new Parse.File(name,base64str); // saving logs "Uncaught Creating a Parse.File from a String is not yet supported."
parseFile.save().then(function (savedFile) {
stopPictures.push(savedFile);
alert("worked");
});
});
picReader.readAsDataURL(file);
}
} else {
$("#stop-img-container").hide();
}
}
There's some extraneous stuff here, but basically it collects the user's selected files, displays them for them once they've finished loading, and then creates them as a Parse file. I've left it in to show that at least something is working as it properly locally stores and previews the user's selected files.
I have included three different ways of creating the same Parse file. However, all of them fail when I try to save to Parse in any way.
Parse's Javascript API docs says that any of these should work fine. But they lie, or I'm an idiot.
Anyone have any idea why this doesn't seem to work? Seems like a pretty critical aspect of their API is broken completely -- which I find hard to imagine.
EDIT: I'm also positive I'm properly parsing (lower case p) the base64 string as this site confirms the appropriate image and works.
I experienced the same problem.
Finally I found what causes the problem.
It's a "file name".
I suspect the file name in tuckerchapin's example is null.
var name = picFile.name;
I wrote the example with React.
this code works fine.
class ImageUpload extends React.Component {
onChange(e) {
var file = e.target.files[0];
var parseFile = new Parse.File(file.name, file);
Parse.User.current().set("icon",parseFile);
Parse.User.current().save();
}
handleSubmit(e) {
e.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="file" onChange={this.onChange.bind(this)} />
</form>
);
}
}

file input does not update except in Chrome

I have a local program which writes a JSON object to a file so that a JavaScript can pick up its data and process it. The file is selected using an <input> object:
<form id = "getfiles">
<input type = "file" multiple id = "files" />
</form>
with the following JS function setInterval to repeat every 300ms. However, when the file changes, only Google Chrome reloads the file and processes the new content; I have to manually reselect the file on the page in IE 10 and Firefox 20.
function speakText()
{
var thefile = document.getElementById('files').files[0];
var lastChanged = thefile.lastModifiedDate;
var reader = new FileReader();
reader.onload = function(event)
{
var lcd = document.getElementById("last_change_date");
if (!lcd)
{
var spanLastChanged = document.createElement("span");
spanLastChanged.id = "last_change_date";
spanLastChanged.innerText = lastChanged;
console.log(lastChanged);
document.body.appendChild(spanLastChanged);
}
else
{
// compare lastChanged with last_change_date
var last_known_change = Date.parse(lcd.innerText);
// var last_known_change = Date.parse(thefile.lastModifiedDate);
if (last_known_change !== Date.parse(lastChanged))
{
console.log("Something is new since " + lcd.innerText);
var fileContent = event.target.result;
var commands = JSON.parse(fileContent);
handleJSON(fileContent);
lcd.innerText = lastChanged;
}
}
}
reader.readAsText(thefile, "UTF-8");
}
Firefox and IE are doing the right thing per spec: the File objects associated with a file input are supposed to be immutable snapshots of a file at the point when the File object was created. It's a known bug in WebKit/Blink that they just store a reference to the file's data, so that mutating the data will change what the File object sees.
In fact, the WebKit/Blink behavior is a privacy bug: when a user selects a file in a file input, they are giving a web page permission to read the data of the file at that time, not for all future versions of the file! Which is why the spec is written as it is.

Categories

Resources