Can someone explain why my console log is not working?
Every time I select the file for verification to see if anything shows in the console nothing happens
document.addEventListener("DOMContentLoaded", function() {
document.getElementById('file').onchange = function() {
var extPermitidas = ['txt'];
var extArquivo = this.value.split('.').pop();
if (typeof extPermitidas.find(function(ext) {
return extArquivo == ext;
}) == 'undefined') {
alert('The file cannot be used because its extension is not allowed!');
return;
} else {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function(progressEvent) {
// By lines
var lines = this.result.split('\n');
let N = /^(N1\d{14}.{78}|N9\d{14}.{14}\d{6})$/;
for (var line = 0; line < lines.length; line++) {
if (N.test(lines[line]) == N) {
console.log("valid file");
} else {
console.log("invalid file");
}
}
};
reader.readAsText(file);
}
alert('file successfully validated!');
}
});
<input type="file" id="file" />
EDIT
Could it be a problem in the conditional if (N.test(lines[line]) == N)?
This appears to be a function context issue. Try changing var file = this.files[0]; to var file = document.getElementById("file").files[0];.
this can sometimes be tricky since its value is determined by how a function is called (runtime binding). See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Edit:
The conditional if (N.test(lines[line]) == N) is strange. The test() method executes a search for a match between a regular expression and a specified string and returns true or false. So, you don't need to compare the return of test to == N. Plus, you almost always want to use triple equals (===).
Have you already check your conditions or try to place the console.log in various parts of your code? Maybe it's an issue with event firing. I've tried to run you regex with my console I guess it works smoothly.
regex result
Related
I include myscript.js in the file http://site1.com/index.html like this:
<script src=http://site2.com/myscript.js></script>
Inside "myscript.js", I want to get access to the URL "http://site2.com/myscript.js". I'd like to have something like this:
function getScriptURL() {
// something here
return s
}
alert(getScriptURL());
Which would alert "http://site2.com/myscript.js" if called from the index.html mentioned above.
From http://feather.elektrum.org/book/src.html:
var scripts = document.getElementsByTagName('script');
var index = scripts.length - 1;
var myScript = scripts[index];
The variable myScript now has the script dom element. You can get the src url by using myScript.src.
Note that this needs to execute as part of the initial evaluation of the script. If you want to not pollute the Javascript namespace you can do something like:
var getScriptURL = (function() {
var scripts = document.getElementsByTagName('script');
var index = scripts.length - 1;
var myScript = scripts[index];
return function() { return myScript.src; };
})();
You can add id attribute to your script tag (even if it is inside a head tag):
<script id="myscripttag" src="http://site2.com/myscript.js"></script>
and then access to its src as follows:
document.getElementById("myscripttag").src
of course id value should be the same for every document that includes your script, but I don't think it is a big inconvenience for you.
Everything except IE supports
document.currentScript
Simple and straightforward solution that work very well :
If it not IE you can use document.currentScript
For IE you can do document.querySelector('script[src*="myscript.js"]')
so :
function getScriptURL(){
var script = document.currentScript || document.querySelector('script[src*="myscript.js"]')
return script.src
}
update
In a module script, you can use:
import.meta.url
as describe in mdn
I wrote a class to find get the path of scripts that works with delayed loading and async script tags.
I had some template files that were relative to my scripts so instead of hard coding them I made created the class to do create the paths automatically. The full source is here on github.
A while ago I had use arguments.callee to try and do something similar but I recently read on the MDN that it is not allowed in strict mode.
function ScriptPath() {
var scriptPath = '';
try {
//Throw an error to generate a stack trace
throw new Error();
}
catch(e) {
//Split the stack trace into each line
var stackLines = e.stack.split('\n');
var callerIndex = 0;
//Now walk though each line until we find a path reference
for(var i in stackLines){
if(!stackLines[i].match(/http[s]?:\/\//)) continue;
//We skipped all the lines with out an http so we now have a script reference
//This one is the class constructor, the next is the getScriptPath() call
//The one after that is the user code requesting the path info (so offset by 2)
callerIndex = Number(i) + 2;
break;
}
//Now parse the string for each section we want to return
pathParts = stackLines[callerIndex].match(/((http[s]?:\/\/.+\/)([^\/]+\.js)):/);
}
this.fullPath = function() {
return pathParts[1];
};
this.path = function() {
return pathParts[2];
};
this.file = function() {
return pathParts[3];
};
this.fileNoExt = function() {
var parts = this.file().split('.');
parts.length = parts.length != 1 ? parts.length - 1 : 1;
return parts.join('.');
};
}
if you have a chance to use jQuery, the code would look like this:
$('script[src$="/myscript.js"]').attr('src');
Following code lets you find the script element with given name
var scripts = document.getElementsByTagName( 'script' );
var len = scripts.length
for(var i =0; i < len; i++) {
if(scripts[i].src.search("<your JS file name") > 0 && scripts[i].src.lastIndexOf("/") >= 0) {
absoluteAddr = scripts[i].src.substring(0, scripts[i].src.lastIndexOf("/") + 1);
break;
}
}
document.currentScript.src
will return the URL of the current Script URL.
Note: If you have loaded the script with type Module then use
import.meta.url
for more import.meta & currentScript.src
Some necromancy, but here's a function that tries a few methods
function getScriptPath (hint) {
if ( typeof document === "object" &&
typeof document.currentScript === 'object' &&
document.currentScript && // null detect
typeof document.currentScript.src==='string' &&
document.currentScript.src.length > 0) {
return document.currentScript.src;
}
let here = new Error();
if (!here.stack) {
try { throw here;} catch (e) {here=e;}
}
if (here.stack) {
const stacklines = here.stack.split('\n');
console.log("parsing:",stacklines);
let result,ok=false;
stacklines.some(function(line){
if (ok) {
const httpSplit=line.split(':/');
const linetext = httpSplit.length===1?line.split(':')[0]:httpSplit[0]+':/'+( httpSplit.slice(1).join(':/').split(':')[0]);
const chop = linetext.split('at ');
if (chop.length>1) {
result = chop[1];
if ( result[0]!=='<') {
console.log("selected script from stack line:",line);
return true;
}
result=undefined;
}
return false;
}
ok = line.indexOf("getScriptPath")>0;
return false;
});
return result;
}
if ( hint && typeof document === "object") {
const script = document.querySelector('script[src="'+hint+'"]');
return script && script.src && script.src.length && script.src;
}
}
console.log("this script is at:",getScriptPath ())
Can't you use location.href or location.host and then append the script name?
I have an issue that I don't understand and I have no idea how to fix it, where to look for the cause. When I'm debugin (chrome) every thing is working, but during normal use it dosen't. For me is some kind of Science-Fiction, it would be better for me if it's more Science than Fiction :)
for (var i = 0; i < filteredAddedFiles.length; i++) {
if ((/\.(png|jpeg|jpg|gif)$/i).test(filteredAddedFiles[i].name)) {
(function (file) {
var reader = new FileReader();
var blob = b64toBlob(file.base64.replace('data:image/jpeg;base64,', ''), file.type);
reader.addEventListener("load", function () {
console.log(this);
var image = new Image();
image.src = window.URL.createObjectURL(blob);
image.onload = function () {
preview.innerHTML += drawHtml(image, file)
};
//I tried:
//(function (b) {
// var image = new Image();
// image.addEventListener("load", function () {
// preview.innerHTML += drawHtml(this, file);
// //window.URL.revokeObjectURL(image.src);
// });
// image.src = window.URL.createObjectURL(b);
//})(blob);
});
reader.readAsDataURL(blob);
})(filteredAddedFiles[i]);
} else {
errors += filteredAddedFiles[i].name + " Unsupported Image extension\n";
}
}
here I attached a short movie that shows how its working
link to movie
not working - I mean - it looks like the all thing inside for dosen't executed
EDIT: 1
#Teemu - I turn on logs in chrome console and all console.log's appear
#Katie.Sun - now the above for - console.log(filteredAddedFiles.length); is 0 - but when I'm debuging code the same console.log(filteredAddedFiles.length); have values !
EDIT: 2
#Matti Price
filteredAddedFiles - is the result of custom logic of page, filtering,
validation etc.
Everything starts here:
addedFiles = added(files); // files - FileList from input this is a read only array of obj
function added(from) {
var out = [];
for (var i = 0; i < from.length; i++) {
(function (obj) {
var readerBase64 = new FileReader();
readerBase64.addEventListener("load", function () {
var fileBase64 = readerBase64.result;
var row = { name: obj.name, size: obj.size, type: obj.type, base64: fileBase64 }
out.push(row);
});
readerBase64.readAsDataURL(obj);
})(from[i]);
}
return out;
}
then addedFiles - do something farther and transform into filteredAddedFiles later. what I found in added function? during debug there is an length value witch is correct, but when I opened the __proto__: Array(0) I found length property = 0.
Should this length value be equal to the value from above length?
The second thing:
I have to admit that I don't have enough knowledge aboute addEventListener. Are there any queues here or some thread etc?
EDIT: 3
After last #Teemu comment I made some changes (I had to read a lot aboute promisses etc:)), but output is the same console.log("out resolve", out); shows a array of object, but console.log("out.length then", out.length); shows 0 and the small blue i-icon show msg - Value below evaluated just now
var out = [];
for (var i = 0; i < files.length; i++) {
fillArray(files[i], out);
}
console.log("out resolve", out);
console.log("out.length then", out.length);
function fillArray(obj, out) {
return new Promise(function (resolve, reject) {
var readerBase64 = new FileReader();
readerBase64.addEventListener("load", function () {
var fileBase64 = readerBase64.result;
var row = { name: obj.name, size: obj.size, type: obj.type, out.push(row);
resolve(out);
});
readerBase64.readAsDataURL(obj);
});
}
After I posted the edit above I relized that I just create promise, I forgot to call `promise
, but this is not important, because 90% of my code has been changed because of this topic and the answer of the Golden Person #Kaiido
URL.createObjectURL() - is synchronous. You don't need your Promise wrapping event handlers hell, all can be done in a single loop.
In my case, this is a better solution than a filereader, I have to upload only images, and with some restrictions thanks to which I don't have to worry about freeze the Internet browser, because of the synchronous nature of createObjectURL()
Thank you for your help and commitment
I have a C program that takes one argument (a char array / string) via command line and also reads from stdin. I've compiled it to JavaScript using emscripten. This was successful and I can run it just like the normal C program using node.js:
emcc -O2 translate.c
node translate.js "foo" < bar.txt
As you can see, I'm providing the string "foo" as an argument and the contents of bar.txt as stdin. Now I want this to be a self-contained HTML file.
By changing the output to HTML:
emcc -O2 translate.c -o trans.html
I provide the argument by adding arguments: ['foo'], to the definitions in var Module. This works as expected, the program receives the argument correctly.
Now, how do I provide the stdin input to this program? I don't need to do this dynamically. It would be fine to just declare a string somewhere in the HTML with the required stdin content.
A way would be to use the Emscripten Filesystem API, for example by calling FS.init in the Module preRun function, passing custom functions to be used for standard input, output and error.
var Module = {
preRun: function() {
function stdin() {
// Return ASCII code of character, or null if no input
}
function stdout(asciiCode) {
// Do something with the asciiCode
}
function stderr(asciiCode) {
// Do something with the asciiCode
}
FS.init(stdin, stdout, stderr);
}
};
The functions are quite low-level: they each deal with one character at a time as an ASCII code. If you have strings you want to pass in, you would have to iterate over the characters of the string yourself. I suspect charCodeAt would be helpful. To output strings from stdout or stderr, then I suspect fromCharCode would be helpful.
Example (not very well tested!) implementations using each are below.
var input = "This is from the standard input\n";
var i = 0;
var Module = {
preRun: function() {
function stdin() {
if (i < res.length) {
var code = input.charCodeAt(i);
++i;
return code;
} else {
return null;
}
}
var stdoutBuffer = "";
function stdout(code) {
if (code === "\n".charCodeAt(0) && stdoutBuffer !== "") {
console.log(stdoutBuffer);
stdoutBuffer = "";
} else {
stdoutBuffer += String.fromCharCode(code);
}
}
var stderrBuffer = "";
function stderr(code) {
if (code === "\n".charCodeAt(0) && stderrBuffer !== "") {
console.log(stderrBuffer);
stderrBuffer = "";
} else {
stderrBuffer += String.fromCharCode(code);
}
}
FS.init(stdin, stdout, stderr);
}
};
Rather than editing the output of Emscripten, you could monkey patch the Window object
window.prompt = function() {
return 'This will appear to come from standard input';
};
Not wonderful, but I would deem this less of a hack than editing the Emscripten-generated Javascript.
According the question "Edit" , I made my function , thx a lot.
Just hope the code below can help someone else.
comment run(); in the end of emscript
// in my emscript
// shouldRunNow refers to calling main(), not run().
var shouldRunNow = true;
if (Module['noInitialRun']) {
shouldRunNow = false;
}
//run(); // << here
// {{POST_RUN_ADDITIONS}}
result = areaInput(); // As the question mentioned
add the code below in your html file to activate run() in emscript
<script>
var message;
var point = -1;
function getArea(){
message = document.getElementById('input').value.split('\n');
}
function areaInput(){
if(point >= message.length - 1){
return null;
}
point += 1;
return message[point];
}
function execEmscript(){
window.console = {
log: function(str){
document.getElementById("output").value += "\n" + str;
}
}
getArea();
run();
}
</script>
remember io textareas in your html
<textarea id="input" cols="80" rows="30"></textarea>
<textarea id="output" cols="80" rows="30"></textarea>
and a button
<button onclick="execEmscript();">run</button>
I'm running into an odd problem using FileReader.readAsArrayBuffer that only seems to affect Firefox (I tested in the current version - v40). I can't tell if I'm just doing something wrong or if this is a Firefox bug.
I have some JavaScript that uses readAsArrayBuffer to read a file specified in an <input> field. Under normal circumstances, everything works correctly. However, if the user modifies the file after selecting it in the <input> field, readAsArrayBuffer can get very confused.
The ArrayBuffer I get back from readAsArrayBuffer always has the length that the file was originally. If the user changes the file to make it larger, I don't get any of the bytes after the original size. If the user changes the file to make it smaller, the buffer is still the same size and the 'excess' in the buffer is filled with character codes 90 (capital letter 'Z' if viewed as a string).
Since this code is so simple and works perfectly in every other browser I tested, I'm thinking it's a Firefox issue. I've reported it as a bug to Firefox but I want to make sure this isn't just something obvious I'm doing wrong.
The behavior can be reproduced by the following code snippet. All you have to do is:
Browse for a text file that has 10 characters in it (10 is not a magic number - I'm just using it as an example)
Observe that the result is an array of 10 items representing the character codes of each item
While this is still running, delete 5 characters from the file and save
Observe that the result is still an array of 10 items - the first 5 are correct but the last 5 are all 90 (capital letter Z)
Now added 10 characters (so the file is now 15 characters long)
Observe that the result is still an array of 10 items - the last 5 are not returned
function ReadFile() {
var input = document.getElementsByTagName("input")[0];
var output = document.getElementsByTagName("textarea")[0];
if (input.files.length === 0) {
output.value = 'No file selected';
window.setTimeout(ReadFile, 1000);
return;
}
var fr = new FileReader();
fr.onload = function() {
var data = fr.result;
var array = new Int8Array(data);
output.value = JSON.stringify(array, null, ' ');
window.setTimeout(ReadFile, 1000);
};
fr.readAsArrayBuffer(input.files[0]);
//These two methods work correctly
//fr.readAsText(input.files[0]);
//fr.readAsBinaryString(input.files[0]);
}
ReadFile();
<input type="file" />
<br/>
<textarea cols="80" rows="10"></textarea>
In case the snippet does not work, the sample code is also available as a JSFiddle here: https://jsfiddle.net/Lv5y9m2u/
Interesting, looks like Firefox is caching the buffer size even the file is modified.
You can refer to this link, replaced readAsArrayBuffer with is custom functionality which uses readAsBinaryString. Its working fine in Firefox and Chrome
function ReadFile() {
var input = document.getElementsByTagName("input")[0];
var output = document.getElementsByTagName("textarea")[0];
if (input.files.length === 0) {
output.value = 'No file selected';
window.setTimeout(ReadFile, 1000);
return;
}
var fr = new FileReader();
fr.onload = function () {
var data = fr.result;
var array = new Int8Array(data);
output.value = JSON.stringify(array, null, ' ');
window.setTimeout(ReadFile, 1000);
};
fr.readAsArrayBuffer(input.files[0]);
//These two methods work correctly
//fr.readAsText(input.files[0]);
//fr.readAsBinaryString(input.files[0]);
}
if (FileReader.prototype.readAsArrayBuffer && FileReader.prototype.readAsBinaryString) {
FileReader.prototype.readAsArrayBuffer = function readAsArrayBuffer () {
this.readAsBinaryString.apply(this, arguments);
this.__defineGetter__('resultString', this.__lookupGetter__('result'));
this.__defineGetter__('result', function () {
var string = this.resultString;
var result = new Uint8Array(string.length);
for (var i = 0; i < string.length; i++) {
result[i] = string.charCodeAt(i);
}
return result.buffer;
});
};
}
ReadFile();
I think you are hitting a bug of Firefox. However, as you pointed out, readAsArrayBuffer behaves correctly in every supported browser except Firefox while readAsBinaryString is supported by every browser except IE.
Therefore, it is possible to prefer readAsBinaryString when it exists and fail back to readAsArrayBuffer otherwise.
function readFileAsArrayBuffer(file, success, error) {
var fr = new FileReader();
fr.addEventListener('error', error, false);
if (fr.readAsBinaryString) {
fr.addEventListener('load', function () {
var string = this.resultString != null ? this.resultString : this.result;
var result = new Uint8Array(string.length);
for (var i = 0; i < string.length; i++) {
result[i] = string.charCodeAt(i);
}
success(result.buffer);
}, false);
return fr.readAsBinaryString(file);
} else {
fr.addEventListener('load', function () {
success(this.result);
}, false);
return fr.readAsArrayBuffer(file);
}
}
Usage:
readFileAsArrayBuffer(input.files[0], function(data) {
var array = new Int8Array(data);
output.value = JSON.stringify(array, null, ' ');
window.setTimeout(ReadFile, 1000);
}, function (e) {
console.error(e);
});
Working fiddle: https://jsfiddle.net/Lv5y9m2u/6/
Browser Support:
Firefox: Uses readAsBinaryString, which is not problematic.
IE >= 10: Uses readAsArrayBuffer which is supported.
IE <= 9: The entire FileReader API is not supported.
Almost all other browsers: Uses readAsBinaryString.
I'm using Javascript to write an application that will be used with Phonegap to make an Android application. I'm using the Phonegap File API to read directories and files. The relevant code is shown below:
document.addEventListener("deviceready", onDeviceReady, false);
// PhoneGap is ready
//
function onDeviceReady() {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, onFileSystemSuccess, fail);
}
function onFileSystemSuccess(fileSystem) {
fileSystem.root.getDirectory("/sdcard", {create: false, exclusive: false}, getDirSuccess, fail);
}
function getDirSuccess(dirEntry) {
// Get a directory reader
var directoryReader = dirEntry.createReader();
// Get a list of all the entries in the directory
directoryReader.readEntries(readerSuccess,fail);
}
var numDirs = 0;
var numFiles = 0;
function readerSuccess(entries) {
var i;
for (i=0; i<entries.length; i++)
{
if(entries[i].isFile === true)
{
numFiles++;
entries[i].file(fileSuccess,fail);
}
else if (entries[i].isDirectory === true)
{
numDirs++;
getDirSuccess(entries[i]);
}
}
}
So as of now, the program works fine. The reader will read the contents of the /sdcard directory..if it encounters a file, it will call fileSuccess (which I've excluded in the code for brevity), and if it encounters another directory, it will call getDirSuccess again. My question is this: How can I know when the entire /sdcard directory is read? I can't think of a good way of accomplishing this without going through the /sdcard directory more than one time. Any ideas are appreciated, and thank you in advance!
+1 on a good question since I have to do this anyway myself. I would use the old setTimeout trick. Once the cancel doesn't occur anymore, you know you are done and can fire your event, but just ensure its only fired once.
Here's what I mean and I've named the variables long simply to be more readable (not my style)...
// create timeout var outside your "readerSuccess" function scope
var readerTimeout = null, millisecondsBetweenReadSuccess = 100;
function readerSuccess(entries) {
var i = 0, len = entries.length;
for (; i < len; i++) {
if (entries[i].isFile) {
numFiles++;
entries[i].file(fileSuccess,fail);
} else if (entries[i].isDirectory) {
numDirs++;
getDirSuccess(entries[i]);
}
if (readerTimeout) {
window.clearTimeout(readerTimeout);
}
}
if (readerTimeout) {
window.clearTimeout(readerTimeout);
}
readerTimeout = window.setTimeout(weAreDone, millisecondsBetweenReadSuccess);
}
// additional event to call when totally done
function weAreDone() {
// do something
}
So the logic in this is you keep cancelling the "weAreDone" function from being called as you are reading through stuff. Not sure if this is the best way or more efficient but it would not result in more than one loop given the appropriate "millisecondsBetweenReadSuccess".
Instead of using a setTimeout, which can fail if you have a very slow device, you can use a counter to see how many callbacks still need to be called. If the counter reaches zero, you're all done :)
This is the recursive code:
var fileSync = new function(){
this.filesystem = null;
this.getFileSystem = function(callback){
var rfs = window.requestFileSystem || window.webkitRequestFileSystem;
rfs(
1// '1' means PERSISTENT
, 0// '0' is about max. storage size: 0==we don't know yet
, function(filesystem){
fileSync.filesystem = filesystem;
callback(filesystem);
}
, function(e){
alert('An error occured while requesting the fileSystem:\n\n'+ e.message);
}
);
}
this.readFilesFromReader = function(reader, callback, recurse, recurseFinishedCallback, recurseCounter)
{
if (recurse && !recurseCounter)
recurseCounter = [1];
reader.readEntries(function(res){
callback(res);
if (recurse)
{
for (var i=0; i<res.length; i++) {
/* only handle directories */
if (res[i].isDirectory == true)
{
recurseCounter[0]++;
fileSync.readFilesFromReader(res[i].createReader(), callback, recurse, recurseFinishedCallback, recurseCounter);
}
}
}
/* W3C specs say: Continue calling readEntries() until an empty array is returned.
* You have to do this because the API might not return all entries in a single call.
* But... Phonegap doesn't seem to accommodate this, and instead always returns the same dir-entries... OMG, an infinite loop is created :-/
*/
//if (res.length)
// fileSync.readFilesFromReader(reader, callback, recurse, recurseFinishedCallback, recurseCounter);
//else
if (recurse && --recurseCounter[0] == 0)
{
recurseFinishedCallback();
}
}
, function(e){
fileSync.onError(e);
if (recurse && --recurseCounter[0] == 0)
recurseFinishedCallback();
});
};
this.onError = function(e){
utils.log('onError in fileSync: ' + JSON.stringify(e));
if (utils.isDebugEnvironment())
alert('onError in fileSync: '+JSON.stringify(e));
}
}
var utils = new function(){
this.log = function(){
for (var i=0;i<arguments.length;i++)
console.log(arguments[i]);
}
this.isDebugEnvironment = function(){ return true }// simplified
}
Example code to test this:
var myFiles = [];
var directoryCount = 0;
window.onerror = function(){ alert('window.onerror=\n\n' + arguments.join('\n')) }
var gotFilesCallback = function(entries)
{
for (var i=0;i<entries.length;i++)
{
if (entries[i].isFile == true)
myFiles.push(entries[i].fullPath)
else
++directoryCount;
}
}
var allDoneCallback = function(){
alert('All files and directories were read.\nWe found '+myFiles.length+' files and '+directoryCount+' directories, shown on-screen now...');
var div = document.createElement('div');
div.innerHTML = '<div style="border: 1px solid red; position: absolute;top:10px;left:10%;width:80%; background: #eee;">'
+ '<b>Filesystem root:</b><i>' + fileSync.filesystem.root.fullPath + '</i><br><br>'
+ myFiles.join('<br>').split(fileSync.filesystem.root.fullPath).join('')
+ '</div>';
document.body.appendChild(div);
}
/* on-device-ready / on-load, get the filesystem, and start reading files */
var docReadyEvent = window.cordova ? 'deviceready':'load';
document.addEventListener(docReadyEvent, function()
{
fileSync.getFileSystem(function(filesystem){
var rootDirReader = filesystem.root.createReader();
fileSync.readFilesFromReader(rootDirReader, gotFilesCallback, true, allDoneCallback);
})
}, false);