I'm trying to setup a file upload through rest for large files. The function below is taking care of chunking but I need to be able to recognize the last chunk because my rest call changes to /finishUpload() in order to commit the save.
Right now I'm only able to figure out when the blob is empty but I can't figure out how to determine the last iteration before the blob is empty.
This is the script I'm using below to parse my files.
export default function parseFile(file, options) {
var opts = typeof options === 'undefined' ? {} : options;
var fileSize = file.size;
var chunkSize = typeof opts['chunk_size'] === 'undefined' ? 64 * 1024 : parseInt(opts['chunk_size']);
var binary = typeof opts['binary'] === 'undefined' ? false : opts['binary'] == true;
var offset = 0;
var self = this; // we need a reference to the current object
var readBlock = null;
var chunkReadCallback = typeof opts['chunk_read_callback'] === 'function' ? opts['chunk_read_callback'] : function() {};
var chunkErrorCallback = typeof opts['error_callback'] === 'function' ? opts['error_callback'] : function() {};
var success = typeof opts['success'] === 'function' ? opts['success'] : function() {};
var onLoadHandler = function(evt) {
if (evt.target.result == "") {
console.log('Chunk empty, call finish');
success(file);
return;
}
if (evt.target.error == null) {
chunkReadCallback(evt.target.result, offset).then(function() {
offset += evt.target.result.length;
readBlock(offset, chunkSize, file);
});
} else {
chunkErrorCallback(evt.target.error);
return;
}
if (offset >= fileSize) {
success(file);
return;
}
}
readBlock = function(_offset, _chunkSize, _file) {
var r = new FileReader();
var blob = _file.slice(_offset, _chunkSize + _offset);
console.log("blob size:", blob.size, "offset:", _offset, "C+S:",_chunkSize + _offset)
r.onload = onLoadHandler;
if (binary) {
r.readAsArrayBuffer(blob);
} else {
r.readAsText(blob);
}
}
readBlock(offset, chunkSize, file);
}
Codepen
Why not rely on the filesize, i.e. check the condition _chunkSize + _offset >= fileSize?
You can use progress, loadend events to process File object one byte at a time; define a variable where processing should be paused or stopped at nth byte, every nth byte, or any byte during processing of file.
var str = "abcdefghijklmnopqrstuvwxyz";
var type = "application/octet-stream";
var data = new Blob([], {
type: type
});
var filename = "file.txt";
var reader = new FileReader();
var complete = false;
var beforeEnd = false;
var stopAt = str.length - 1;
function handleFile(e) {
data = new File([data.slice()
, str.slice(data.size, data.size + 1)]
, filename, {
type: type,
lastModifiedDate: new Date()
});
}
function handleRead(e) {
if (data.size <= str.length && !complete) {
if (data.size === stopAt && !beforeEnd) {
beforeEnd = true;
var r = new FileReader();
r.onloadend = function() {
alert(`stopAt: ${stopAt}\n`
+`data.size: ${data.size}\n`
+`result at stopAt: ${r.result[stopAt -1]}`);
reader.readAsArrayBuffer(data);
}
r.readAsText(data);
} else {
reader.readAsArrayBuffer(data)
}
} else {
console.log("complete")
}
}
function handleProgress(e) {
if (data.size <= str.length && !complete) {
var read = new FileReader();
read.onload = function() {
if (!complete) {
console.log(read.result);
if (read.result.length === str.length) {
complete = true;
console.log(data);
}
}
}
read.readAsText(data);
}
}
reader.addEventListener("load", handleFile);
reader.addEventListener("loadend", handleRead);
reader.addEventListener("progress", handleProgress);
reader.readAsArrayBuffer(data);
Related
I need to send data from a custom form to Zoho. I'm looking at the native javascript request in their documentation here.
https://www.zoho.com/crm/developer/docs/api/v2/insert-records.html
var listener = 0;
class InsertRecordsAPI {
async insertRecords() {
var url = "https://www.zohoapis.com/crm/v2/Leads"
var parameters = new Map()
var headers = new Map()
var token = {
clientId:"1000.NPY9M1V0XXXXXXXXXXXXXXXXXXXF7H",
redirectUrl:"http://127.0.0.1:5500/redirect.html",
scope:"ZohoCRM.users.ALL,ZohoCRM.bulk.read,ZohoCRM.modules.ALL,ZohoCRM.settings.ALL,Aaaserver.profile.Read,ZohoCRM.org.ALL,profile.userphoto.READ,ZohoFiles.files.ALL,ZohoCRM.bulk.ALL,ZohoCRM.settings.variable_groups.ALL"
}
var accesstoken = await new InsertRecordsAPI().getToken(token)
headers.set("Authorization", "Zoho-oauthtoken " + accesstoken)
var requestMethod = "POST"
var reqBody = {"data":[{"Last_Name":"Lead_changed","Email":"newcrmapi#zoho.com","Company":"abc","Lead_Status":"Contacted"},{"Last_Name":"New Lead","Email":"newlead#zoho.com","Company":"abc","Lead_Status":"Contacted"}],"trigger":["approval","workflow","blueprint"]}
var params = "";
parameters.forEach(function(value, key) {
if (parameters.has(key)) {
if (params) {
params = params + key + '=' + value + '&';
}
else {
params = key + '=' + value + '&';
}
}
});
var apiHeaders = {};
if(headers) {
headers.forEach(function(value, key) {
apiHeaders[key] = value;
});
}
if (params.length > 0){
url = url + '?' + params.substring(0, params.length - 1);
}
var requestObj = {
uri : url,
method : requestMethod,
headers : apiHeaders,
body : JSON.stringify(reqBody),
encoding: "utf8",
allowGetBody : true,
throwHttpErrors : false
};
var result = await new InsertRecordsAPI().makeAPICall(requestObj);
console.log(result.status)
console.log(result.response)
}
async getToken(token) {
if(listener == 0) {
window.addEventListener("storage", function(reponse) {
if(reponse.key === "access_token" && (reponse.oldValue != reponse.newValue || reponse.oldValue == null)){
location.reload();
}
if(reponse.key === "access_token"){
sessionStorage.removeItem("__auth_process");
}
}, false);
listener = 1;
if(sessionStorage.getItem("__auth_process")) {
sessionStorage.removeItem("__auth_process");
}
}
["granted_for_session", "access_token","expires_in","expires_in_sec","location","api_domain","state","__token_init","__auth_process"].forEach(function (k) {
var isKeyExists = localStorage.hasOwnProperty(k);
if(isKeyExists) {
sessionStorage.setItem(k, localStorage[k]);
}
localStorage.removeItem(k);
});
var valueInStore = sessionStorage.getItem("access_token");
var tokenInit = sessionStorage.getItem("__token_init");
if(tokenInit != null && valueInStore != null && Date.now() >= parseInt(tokenInit) + 59 * 60 * 1000){ // check after 59th minute
valueInStore = null;
sessionStorage.removeItem("access_token");
}
var auth_process = sessionStorage.getItem("__auth_process");
if ((valueInStore == null && auth_process == null) || (valueInStore == 'undefined' && (auth_process == null || auth_process == "true"))) {
var accountsUrl = "https://accounts.zoho.com/oauth/v2/auth"
var clientId;
var scope;
var redirectUrl;
if(token != null) {
clientId = token.clientId;
scope = token.scope;
redirectUrl = token.redirectUrl;
}
var fullGrant = sessionStorage.getItem("full_grant");
var grantedForSession = sessionStorage.getItem("granted_for_session");
if(sessionStorage.getItem("__token_init") != null && ((fullGrant != null && "true" == full_grant) || (grantedForSession != null && "true" == grantedForSession))) {
accountsUrl += '/refresh';
}
if (clientId && scope) {
sessionStorage.setItem("__token_init", Date.now());
sessionStorage.removeItem("access_token");
sessionStorage.setItem("__auth_process", "true");
window.open(accountsUrl + "?" + "scope" + "=" + scope + "&"+ "client_id" +"=" + clientId + "&response_type=token&state=zohocrmclient&redirect_uri=" + redirectUrl);
["granted_for_session", "access_token","expires_in","expires_in_sec","location","api_domain","state","__token_init","__auth_process"].forEach(function (k) {
var isKeyExists = localStorage.hasOwnProperty(k);
if(isKeyExists){
sessionStorage.setItem(k, localStorage[k]);
}
localStorage.removeItem(k);
});
valueInStore = sessionStorage.getItem("access_token");
}
}
if(token != null && valueInStore != 'undefined'){
token.accessToken = valueInStore;
}
return token.accessToken;
}
async makeAPICall(requestDetails) {
return new Promise(function (resolve, reject) {
var body, xhr, i;
body = requestDetails.body || null;
xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.open(requestDetails.method, requestDetails.uri, true);
for (i in requestDetails.headers) {
xhr.setRequestHeader(i, requestDetails.headers[i]);
}
xhr.send(body);
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
resolve(xhr);
}
}
})
}
}
I need to send dynamic data and I'm a little fuzzy on how to use the async functions and populate the reqBody variable.
I have tried things like
makeAPICall(myjson);
.then((data) => { console.log(data)})
But I'm not getting anything returned. Any response is welcome. My thanks in advance.
I need to store a large json into a cell of a spreadsheet. Since there's a 50k character limit I thought of compressing the json string. I've managed to store the compressed blob as a base64 encoded string, but I'm failing to restore it to the original json. When the readLargeJson function is called I get the following error: "Blob object must have non-null content type for this operation".
The insertLargeJson function below seems to be working correctly.
I tried also storing without the base64 encoding, but didn't help.
function insertLargeJson()
{
var obj = {};
obj["dummy"] = [];
// Just to make the json huge
for (var i = 0; i < 10000; i++)
{
obj["dummy"].push("value");
}
var activeSheet = SpreadsheetApp.getActiveSheet();
var str = JSON.stringify(obj);
var blob = Utilities.newBlob(str, 'application/octet-stream');
var compressedBlob = Utilities.zip([blob]);
var encoded = Utilities.base64Encode(compressedBlob.getDataAsString());
activeSheet.getRange(1, 1).setValue(encoded);
}
function readLargeJson()
{
var activeSheet = SpreadsheetApp.getActiveSheet();
var values = activeSheet.getSheetValues(1, 1, 1, 1);
var value = values[0, 0];
var decoded = Utilities.base64Decode(value);
var blob = Utilities.newBlob(decoded);
var unzipped = Utilities.unzip(blob);
var obj = JSON.parse(unzipped.getDataAsString());
Browser.msgBox('Test Json array size', "" + obj["dummy"].length, Browser.Buttons.OK);
}
I don't necessarily need to use the blob interface to compress the json, any solution that would compress the json string and that would be storable in a cell for later retrieving the original json would work.
It is an interesting concept so I search a bit and get something working.
In your code you have to use compressedBlob.getBytes() to encode data and not compressedBlob.getDataAsString(). To create a blob in your read function you must use bytes in input.
Then in your read function the unzip return an array and before to get the data you have to use the getAs() function. So you must have unzipped[0].getAs('application/octet-stream').getDataAsString() and not unzipped.getDataAsString()
I made a single function to ease testing, so you just have to split it depending your need.
function insertReadLargeJson(){
var obj = {};
obj["dummy"] = [];
// Just to make the json huge
for (var i = 0; i < 10000; i++)
{
obj["dummy"].push("value");
}
// Logger.log(obj)
var activeSheet = SpreadsheetApp.getActiveSheet();
var str = JSON.stringify(obj);
var blob = Utilities.newBlob(str, 'application/octet-stream');
var compressedBlob = Utilities.zip([blob]);
var encoded = Utilities.base64Encode(compressedBlob.getBytes());
activeSheet.getRange(1, 1).setValue(encoded);
var decoded = Utilities.base64Decode(encoded);
var blob = Utilities.newBlob(decoded,'application/zip');
var unzipped = Utilities.unzip(blob);
var obj = JSON.parse(unzipped[0].getAs('application/octet-stream').getDataAsString());
// Logger.log(JSON.stringify(obj))
Logger.log(obj.dummy.length)
// Logger.log('Test Json array size', "" + obj["dummy"].length)
}
I was able to do it with the help of an external library.
I converted the code to be readable by Apps Script:
JSONPACK.gs
var TOKEN_TRUE = -1;
var TOKEN_FALSE = -2;
var TOKEN_NULL = -3;
var TOKEN_EMPTY_STRING = -4;
var TOKEN_UNDEFINED = -5;
function pack(json, options) {
// Canonizes the options
options = options || {};
// A shorthand for debugging
var verbose = options.verbose || false;
verbose && console.log('Normalize the JSON Object');
// JSON as Javascript Object (Not string representation)
json = typeof json === 'string' ? this.JSON.parse(json) : json;
verbose && console.log('Creating a empty dictionary');
// The dictionary
var dictionary = {
strings : [],
integers : [],
floats : []
};
verbose && console.log('Creating the AST');
// The AST
var ast = (function recursiveAstBuilder(item) {
verbose && console.log('Calling recursiveAstBuilder with ' + this.JSON.stringify(item));
// The type of the item
var type = typeof item;
// Case 7: The item is null
if (item === null) {
return {
type : 'null',
index : TOKEN_NULL
};
}
//add undefined
if (typeof item === 'undefined') {
return {
type : 'undefined',
index : TOKEN_UNDEFINED
};
}
// Case 1: The item is Array Object
if ( item instanceof Array) {
// Create a new sub-AST of type Array (#)
var ast = ['#'];
// Add each items
for (var i in item) {
if (!item.hasOwnProperty(i)) continue;
ast.push(recursiveAstBuilder(item[i]));
}
// And return
return ast;
}
// Case 2: The item is Object
if (type === 'object') {
// Create a new sub-AST of type Object ($)
var ast = ['$'];
// Add each items
for (var key in item) {
if (!item.hasOwnProperty(key))
continue;
ast.push(recursiveAstBuilder(key));
ast.push(recursiveAstBuilder(item[key]));
}
// And return
return ast;
}
// Case 3: The item empty string
if (item === '') {
return {
type : 'empty',
index : TOKEN_EMPTY_STRING
};
}
// Case 4: The item is String
if (type === 'string') {
// The index of that word in the dictionary
var index = indexOf.call(dictionary.strings, item);
// If not, add to the dictionary and actualize the index
if (index == -1) {
dictionary.strings.push(encode(item));
index = dictionary.strings.length - 1;
}
// Return the token
return {
type : 'strings',
index : index
};
}
// Case 5: The item is integer
if (type === 'number' && item % 1 === 0) {
// The index of that number in the dictionary
var index = indexOf.call(dictionary.integers, item);
// If not, add to the dictionary and actualize the index
if (index == -1) {
dictionary.integers.push(base10To36(item));
index = dictionary.integers.length - 1;
}
// Return the token
return {
type : 'integers',
index : index
};
}
// Case 6: The item is float
if (type === 'number') {
// The index of that number in the dictionary
var index = indexOf.call(dictionary.floats, item);
// If not, add to the dictionary and actualize the index
if (index == -1) {
// Float not use base 36
dictionary.floats.push(item);
index = dictionary.floats.length - 1;
}
// Return the token
return {
type : 'floats',
index : index
};
}
// Case 7: The item is boolean
if (type === 'boolean') {
return {
type : 'boolean',
index : item ? TOKEN_TRUE : TOKEN_FALSE
};
}
// Default
throw new Error('Unexpected argument of type ' + typeof (item));
})(json);
// A set of shorthands proxies for the length of the dictionaries
var stringLength = dictionary.strings.length;
var integerLength = dictionary.integers.length;
var floatLength = dictionary.floats.length;
verbose && console.log('Parsing the dictionary');
// Create a raw dictionary
var packed = dictionary.strings.join('|');
packed += '^' + dictionary.integers.join('|');
packed += '^' + dictionary.floats.join('|');
verbose && console.log('Parsing the structure');
// And add the structure
packed += '^' + (function recursiveParser(item) {
verbose && console.log('Calling a recursiveParser with ' + this.JSON.stringify(item));
// If the item is Array, then is a object of
// type [object Object] or [object Array]
if ( item instanceof Array) {
// The packed resulting
var packed = item.shift();
for (var i in item) {
if (!item.hasOwnProperty(i))
continue;
packed += recursiveParser(item[i]) + '|';
}
return (packed[packed.length - 1] === '|' ? packed.slice(0, -1) : packed) + ']';
}
// A shorthand proxies
var type = item.type, index = item.index;
if (type === 'strings') {
// Just return the base 36 of index
return base10To36(index);
}
if (type === 'integers') {
// Return a base 36 of index plus stringLength offset
return base10To36(stringLength + index);
}
if (type === 'floats') {
// Return a base 36 of index plus stringLength and integerLength offset
return base10To36(stringLength + integerLength + index);
}
if (type === 'boolean') {
return item.index;
}
if (type === 'null') {
return TOKEN_NULL;
}
if (type === 'undefined') {
return TOKEN_UNDEFINED;
}
if (type === 'empty') {
return TOKEN_EMPTY_STRING;
}
throw new TypeError('The item is alien!');
})(ast);
verbose && console.log('Ending parser');
// If debug, return a internal representation of dictionary and stuff
if (options.debug)
return {
dictionary : dictionary,
ast : ast,
packed : packed
};
return packed;
};
function unpack(packed, options) {
// Canonizes the options
options = options || {};
// A raw buffer
var rawBuffers = packed.split('^');
// Create a dictionary
options.verbose && console.log('Building dictionary');
var dictionary = [];
// Add the strings values
var buffer = rawBuffers[0];
if (buffer !== '') {
buffer = buffer.split('|');
options.verbose && console.log('Parse the strings dictionary');
for (var i=0, n=buffer.length; i<n; i++){
dictionary.push((buffer[i]));
}
}
// Add the integers values
buffer = rawBuffers[1];
if (buffer !== '') {
buffer = buffer.split('|');
options.verbose && console.log('Parse the integers dictionary');
for (var i=0, n=buffer.length; i<n; i++){
dictionary.push(base36To10(buffer[i]));
}
}
// Add the floats values
buffer = rawBuffers[2];
if (buffer !== '') {
buffer = buffer.split('|')
options.verbose && console.log('Parse the floats dictionary');
for (var i=0, n=buffer.length; i<n; i++){
dictionary.push(parseFloat(buffer[i]));
}
}
// Free memory
buffer = null;
options.verbose && console.log('Tokenizing the structure');
// Tokenizer the structure
var number36 = '';
var tokens = [];
var len=rawBuffers[3].length;
for (var i = 0; i < len; i++) {
var symbol = rawBuffers[3].charAt(i);
if (symbol === '|' || symbol === '$' || symbol === '#' || symbol === ']') {
if (number36) {
tokens.push(base36To10(number36));
number36 = '';
}
symbol !== '|' && tokens.push(symbol);
} else {
number36 += symbol;
}
}
// A shorthand proxy for tokens.length
var tokensLength = tokens.length;
// The index of the next token to read
var tokensIndex = 0;
options.verbose && console.log('Starting recursive parser');
return (function recursiveUnpackerParser() {
// Maybe '$' (object) or '#' (array)
var type = tokens[tokensIndex++];
options.verbose && console.log('Reading collection type ' + (type === '$' ? 'object' : 'Array'));
// Parse an array
if (type === '#') {
var node = [];
for (; tokensIndex < tokensLength; tokensIndex++) {
var value = tokens[tokensIndex];
options.verbose && console.log('Read ' + value + ' symbol');
if (value === ']')
return node;
if (value === '#' || value === '$') {
node.push(recursiveUnpackerParser());
} else {
switch(value) {
case TOKEN_TRUE:
node.push(true);
break;
case TOKEN_FALSE:
node.push(false);
break;
case TOKEN_NULL:
node.push(null);
break;
case TOKEN_UNDEFINED:
node.push(undefined);
break;
case TOKEN_EMPTY_STRING:
node.push('');
break;
default:
node.push(dictionary[value]);
}
}
}
options.verbose && console.log('Parsed ' + this.JSON.stringify(node));
return node;
}
// Parse a object
if (type === '$') {
var node = {};
for (; tokensIndex < tokensLength; tokensIndex++) {
var key = tokens[tokensIndex];
if (key === ']')
return node;
if (key === TOKEN_EMPTY_STRING)
key = '';
else
key = dictionary[key];
var value = tokens[++tokensIndex];
if (value === '#' || value === '$') {
node[key] = recursiveUnpackerParser();
} else {
switch(value) {
case TOKEN_TRUE:
node[key] = true;
break;
case TOKEN_FALSE:
node[key] = false;
break;
case TOKEN_NULL:
node[key] = null;
break;
case TOKEN_UNDEFINED:
node[key] = undefined;
break;
case TOKEN_EMPTY_STRING:
node[key] = '';
break;
default:
node[key] = dictionary[value];
}
}
}
options.verbose && console.log('Parsed ' + this.JSON.stringify(node));
return node;
}
throw new TypeError('Bad token ' + type + ' isn\'t a type');
})();
}
function indexOfDictionary (dictionary, value) {
// The type of the value
var type = typeof value;
// If is boolean, return a boolean token
if (type === 'boolean')
return value ? TOKEN_TRUE : TOKEN_FALSE;
// If is null, return a... yes! the null token
if (value === null)
return TOKEN_NULL;
//add undefined
if (typeof value === 'undefined')
return TOKEN_UNDEFINED;
if (value === '') {
return TOKEN_EMPTY_STRING;
}
if (type === 'string') {
value = encode(value);
var index = indexOf.call(dictionary.strings, value);
if (index === -1) {
dictionary.strings.push(value);
index = dictionary.strings.length - 1;
}
}
// If has an invalid JSON type (example a function)
if (type !== 'string' && type !== 'number') {
throw new Error('The type is not a JSON type');
};
if (type === 'string') {// string
value = encode(value);
} else if (value % 1 === 0) {// integer
value = base10To36(value);
} else {// float
}
// If is number, "serialize" the value
value = type === 'number' ? base10To36(value) : encode(value);
// Retrieve the index of that value in the dictionary
var index = indexOf.call(dictionary[type], value);
// If that value is not in the dictionary
if (index === -1) {
// Push the value
dictionary[type].push(value);
// And return their index
index = dictionary[type].length - 1;
}
// If the type is a number, then add the '+' prefix character
// to differentiate that they is a number index. If not, then
// just return a 36-based representation of the index
return type === 'number' ? '+' + index : index;
};
function encode(str) {
if ( typeof str !== 'string')
return str;
return str.replace(/[\+ \|\^\%]/g, function(a) {
return ({
' ' : '+',
'+' : '%2B',
'|' : '%7C',
'^' : '%5E',
'%' : '%25'
})[a]
});
};
function decode(str) {
if ( typeof str !== 'string')
return str;
return str.replace(/\+|%2B|%7C|%5E|%25/g, function(a) {
return ({
'+' : ' ',
'%2B' : '+',
'%7C' : '|',
'%5E' : '^',
'%25' : '%'
})[a]
})
};
function base10To36(number) {
return Number.prototype.toString.call(number, 36).toUpperCase();
};
function base36To10(number) {
return parseInt(number, 36);
};
function indexOf(obj, start) {
for (var i = (start || 0), j = this.length; i < j; i++) {
if (this[i] === obj) {
return i;
}
}
return -1;
};
With that, your script can now be:
Code.gs
function insertLargeJson()
{
var obj = {};
obj["dummy"] = [];
// Just to make the json huge
for (var i = 0; i < 10000; i++)
{
obj["dummy"].push("value");
}
var activeSheet = SpreadsheetApp.getActiveSheet();
var packed = pack(obj);
var value = JSON.stringify(packed);
activeSheet.getRange(1, 1).setValue(value);
}
function readLargeJson()
{
var activeSheet = SpreadsheetApp.getActiveSheet();
var value = activeSheet.getRange(1,1).getValue();
var packed = JSON.parse(value);
var obj = unpack(packed);
Browser.msgBox('Test Json array size', "" + obj["dummy"].length, Browser.Buttons.OK);
}
Hope this helps!
My goal is from an xlsx file that loads the client, represent the variables using Leaflet.
When I give the absolute path of the example that I have on my server everything is fine, the problem comes when I try to give the file from <input type = "file">.
From what I have been able to read in other questions, a "fakepath" is created for security reasons, but this means that I can not access the file that the client leaves in the input.
I'm new to programming and I'm pretty lost in terms of security and this stuff. If someone had a solution, I would be very grateful.
HTML
<input type="file" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />
JS
/* DATA --- Read xlsx file (foreign code - PLUGIN xlsx.full.min.js ) */
function readXlsxFile(url, sheet, cb) {
var oReq = new XMLHttpRequest();
oReq.open("GET", url, true);
oReq.responseType = "arraybuffer";
oReq.onerror = function() {
cb(new Error("Could not load file " + url));
}
oReq.onload = function() {
var arraybuffer = oReq.response;
// Convertir datos a binario
var data = new Uint8Array(arraybuffer);
var arr = new Array();
for (var i = 0; i != data.length; ++i) arr[i] = String.fromCharCode(data[i]);
var bstr = arr.join("");
var workbook = XLSX.read(bstr, { type: "binary" });
var sheetName = workbook.SheetNames[sheet];
var worksheet = workbook.Sheets[sheetName];
var result = XLSX.utils.sheet_to_json(worksheet, { raw: true });
cb(null, result);
}
oReq.send();
};
function readXlsxFileSheet(url, cb) {
const rateFile = serializeMapFormValues().rate
if (rateFile === "travelers" || rateFile === "travelersPoblation" || rateFile === "travelersForeignPercent" || rateFile === "travelersNatPercent") {
readXlsxFile(url, 0, cb);
} else if (rateFile === "ruralTravelers" || rateFile === "ruralForeignPercent" || rateFile === "ruralPercent" || rateFile === "ruralNatPercent") {
readXlsxFile(url, 1, cb);
} else if (rateFile === "apartTravelers" || rateFile === "apartPoblation" || rateFile === "apartForeignPercent" || rateFile === "apartNatPercent") {
readXlsxFile(url, 2, cb);
} else if (rateFile === "hotelTravelers" || rateFile === "hotelForeignPercent" || rateFile === "hotelNatPercent") {
readXlsxFile(url, 3, cb);
} else {
console.log("Lost variable for sheet");
}
};
const submitButton = document.querySelector("input[type=submit]");
submitButton.addEventListener("click", function(ev) {
ev.preventDefault();
//Catch path and variable from the HTML form
let fileUrl = serializeMapFormValues().url;
let fileRow = serializeMapFormValues().rate;
// Update map data
readXlsxFileSheet(fileUrl, function(error, data) {
// code
});
});
If I change fileUrl ("C:\fakepath\turismo_ejemplo_resuelto.xlsx") for "files/turismo_ejemplo_resuelto.xlsx" everything is fine.
Basically I've made a program where words are inputted and their definitions are found using Wordnik API. Each word is then displayed dynamically and the definition is shown on click. Here's that code:
function define(arr) {
return new Promise(function(resolve, reject) {
var client = [];
var definitions = {};
for (var i = 0, len = arr.length; i < len; i++) {
(function(i) {
client[i] = new XMLHttpRequest();
client[i].onreadystatechange = function() {
if (client[i].readyState === 4 && client[i].status === 200) {
if (client[i].responseText.length === 0) {
console.log(client[i].responseText);
client.responseText[0] = {
word: arr[i],
text: 'Definition not found'
};
}
definitions[arr[i]] = JSON.parse(client[i].responseText);
if (Object.keys(definitions).length === arr.length) {
resolve(definitions);
}
}
};
client[i].open('GET', 'http://api.wordnik.com:80/v4/word.json/' + arr[i] +
'/definitions?limit=1&includeRelated=false&sourceDictionaries=all&useCanonical=false&includeTags=false&api_key=',
true);
client[i].send();
})(i);
}
});
}
function makeFlashCards() {
var data = document.getElementById('inputText').value;
var wordsToDefine = ignore(makeArr(findUniq(data)));
define(wordsToDefine).then(function(result) {
success(result);
}).catch(function(reason) {
console.log('this shouldnt run');
});
}
function success(obj) {
document.getElementById('form').innerHTML = '';
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
addElement('div', obj[prop][0].word);
}
}
attachDefinition(obj);
}
function addElement(type, word) {
var newElement = document.createElement(type);
var content = document.createTextNode(word);
newElement.appendChild(content);
var referenceNode = document.getElementById('form');
document.body.insertBefore(newElement, referenceNode);
newElement.id = word;
newElement.className = "flashcards";
}
function attachDefinition(obj) {
var classArr = document.getElementsByClassName('flashcards');
for (let i = 0, len = classArr.length; i < len; i++) {
classArr[i].addEventListener('click', function() {
cardClicked.call(this, obj);
});
}
}
function cardClicked(obj) {
var el = document.getElementById(this.id);
if (obj[this.id].length !== 0) {
if (this.innerHTML.split(' ').length === 1) {
var img = document.createElement('img');
img.src = 'https://www.wordnik.com/img/wordnik_badge_a2.png';
el.innerHTML = obj[this.id][0].text
+ ' ' + obj[this.id][0].attributionText + '<br>';
el.style['font-weight'] = 'normal';
el.style['font-size'] = '16px';
el.style['text-align'] = 'left';
el.style['overflow'] = 'auto';
el.appendChild(img);
} else {
el.innerHTML = obj[this.id][0].word;
el.style['font-weight'] = 'bold';
el.style['font-size'] = '36px';
el.style['text-align'] = 'center';
el.style['overflow'] = 'visible';
}
}
}
When the define function is given an array with all valid words, the program works as expected however if any word in the array argument is not valid the program doesn't add click event handlers to each element. I think this might have to do with the catch being triggered.
When an invalid word is requested Wordnik API sends back an empty array which might be the root of this problem. I tried to account for this by adding
if (client[i].responseText.length === 0) {
console.log(client[i].responseText);
client.responseText[0] = {
word: arr[i],
text: 'Definition not found'
};
but this conditional never ends up running.
I need some way of filtering out the empty array responses so the catch is not triggered and the program can run smoothly.
When you get to if (client[i].responseText.length === 0) make sure that client[i].responseText is returning empty string. It is probably undefined in which case client[i].responseText.length will throw an error and this will cause the catch block to execute.
function makePromise() {
return new Promise(function(resolve, reject) {
var test = undefined;
if (test.length === 0) {
resolve("resolved");
}
});
}
makePromise().then(console.log).catch(function(res) {
console.log('Error was thrown')
});
Try changing that condition to:
if (client[i].responseText && client[i].responseText.length === 0)
I am developping an hybrid app (JQM 1.4 + Phonegap 3.6.3).
I have a function populateImagesUrlsLocalAndServer that checks if an image file exists on my server, but I can't use this function because it makes my app crash on Phonegap...
I can't find why.
Can you help me fix this issue so I can use this feature in my app again ?
Thank
function populateImagesUrlsLocalAndServer(str, baseUrl, type) {
if (connectionStatus == "online") {
if (UrlExists('./'+baseUrl+str)) { //local file
imagesUrls[str] = './'+baseUrl+str;
} else if (isPhoneGap && UrlExists('http://boardlineapp.com/app/'+baseUrl+str)) { //server file....we exclude this for desktop browser because of cross domain error
console.log('retrieving '+'http://boardlineapp.com/app/'+baseUrl+str+' on server')
imagesUrls[str] = 'http://boardlineapp.com/app/'+baseUrl+str;
} else {
imagesUrls[str] = './'+baseUrl+'default.png';
}
} else { //offline
if (UrlExists('./'+baseUrl+str)) { //local file
imagesUrls[str] = './'+baseUrl+str;
} else {
imagesUrls[str] = './'+baseUrl+'default.png';
}
}
imagesUrls[str+'type'] = type;
}
instead, for now I am using :
function populateImagesUrls(str, baseUrl, type) {
if ( str == 'byrne-ow-fender.png'
|| str == 'ci-tacogrinder.png'
|| str == 'noamizuno.png'
|| str == 'brendanmargieson.png'
|| str == 'kaihing.png'
|| str == 'dustinhollick.png'
|| str == 'dhd-thetwin.png'
) {
//console.log(str);
//console.log(baseUrl);
imagesUrls[str] = './'+baseUrl+'default.png';
} else {
imagesUrls[str] = './'+baseUrl+str;
}
imagesUrls[str+'type'] = type;
}
the function that calls it is the following:
function checkIfImagesExistAllAtOnce() {
var prodataTemp = [];
prodataTemp = prodata.slice();
prodataTemp.shift();
prodataTemp.sort(sort_by('brand', 'name', 'model'));
var strBrandDone;
var strNameDone;
var strModelDone;
for (i = 1; i < prodataTemp.length; ++i) {
//check brand
var str = prodataTemp[i]['brand'].replace(/\s+/g, '').toLowerCase();
str = str+'.png';
if (str != strBrandDone) {
var baseUrl = "images/brands/";
strBrandDone = str;
var type = "brand";
populateImagesUrls(str, baseUrl, type);
//populateImagesUrlsLocalAndServer(str, baseUrl, type);
}
//check pro image
var str = prodataTemp[i]['name'].replace(/\s+/g, '').toLowerCase();
str = str+'.png';
if (str != strNameDone) {
var baseUrl = "images/pros/";
strNameDone = str;
var type = "pro";
populateImagesUrls(str, baseUrl, type);
//populateImagesUrlsLocalAndServer(str, baseUrl, type);
}
//check board image
var str = prodataTemp[i]['imageName'];
if (str != strModelDone) {
var baseUrl = "images/boards/";
strModelDone = str;
var type = "board";
populateImagesUrls(str, baseUrl, type);
//populateImagesUrlsLocalAndServer(str, baseUrl, type);
}
}
prodataTemp = null;
}