Accessing a local file using HTML/javascript - javascript

I am trying to access local files. The method works with Firefox (and was surprised Edge) but not Chrome.
The files in question are 2 html files each containing a huge tables that are used as databases. The tables are basic tables (table, tbody for each group, tr's, and td's with data).
The method I am using is to load the html files into 2 hidden iframes then accessing the tables inside - html file 1 is a master spell list and html file 2 is similar file for a pencil and paper RPG. Works beautifully in Firefox - tables are read into memory, selects/options are all loaded up, popups and page modifications (showing results of what you selected, memory versions of tables modified as needed, generated customized function working - if this file exists at loadup it automatically updates the memory versions of the tables, if the tables are modified - user is shown the function and can copy/save by using a text editor to local file system). Again beautifully.
But Chrome is a different matter. I can load the files in the iframes, but can't access the tables within. It throws an error about cross server access even though all files are in the same directory (the master html file, functions.js file, 2 table files, and if generated and saved by user the customization.js).
So my question is: is there a way to load/import/access a second or third html file in the main html that will work in FF, Chrome, Edge, and most other modern browsers without changing any security settings?
I would love something as simple as how js and the iframe files can be loaded () and accessable. Can xmlrequest work on local files (I could load and render the tables)?
I would like to share the files with the other players, but can't assume browser choices, security settings, and some may not be technically minded enough to make or want said changes.
PS: I am not looking to write any files back to file system, user is the only one with those options.
OK, the other methods (using new tag attributes) failed so looking into a way to hijack the tag and use JSON.
Another user here posted this code (I have cleaned it up - easier to read - and added the suggested but not included part of the code - adding/initializing rowIx and its incrementer)
function getTable() {
var jsonArr = [];
var obj = {};
var jsonObj = {};
var rowIx = 0
//this assumes only one table in the whole page, and table has column headers
var thNum = document.getElementsByTagName('th').length;
var arrLength = document.getElementsByTagName('td').length;
for(i = 0; i < arrLength; i++){
if(i%thNum === 0){ obj = {}; }
var head = document.getElementsByTagName('th')[i%thNum].innerHTML;
var content = document.getElementsByTagName('td')[i].innerHTML;
obj[head] = content;
if(i%thNum === 0){
jsonObj[rowIx++] = obj;
}
}
return JSON.stringify({"Values": jsonObj})
}
the caller then displays (in a P tag using .innerText since .innerHTML tries to render the data; there are p and br tags in some of the table cells) the returned value so it can be copy/pasted/saved in a separate .js file.
Testing the JSON.parse function in the original HTML (that contains the table I want to later import elsewhere) works just fine, although not like the original: array.Values[x].property vs array.rows[x].cells[y].innerHTML but I can work with that.
format:
{"Values":{"numeric index":{7 key/value pairings},{pattern repeated 122 more times}}}
But when the data is placed in a separate js file, it won't parse back to the original data (error is found when developer options/web console is activated, see below).
source HTML file (has the table database, generates the JSON data for copy/paste/save)
large Table (style="display:none;" which hides it, 123 rows by 7 cells each)
the above function getTable
var test1 = getTable()
update p tag using .innerText for copying with test1 data
var schematics = JSON.parse(test1)
alert(schematics.Values[0].Name)
(all of that works)
js File contents (schematics.json.js)
var schematics = JSON.parse( copy/pasted data goes here );
html file
<script language="javascript" src="schematics.json.js"></script>
<script language="javascript">
alert(schematics.Values[0].name); //data restored test
function rebuildTable(){
//use schematics data to rebuild hidden table
)
</script>
<script language="javascript" src="_functions.js"></script>
all other code is in the last script tag
Web Console, reported error
unexpected character at line 1 column 2 of the JSON data
So what am I doing wrong with the JSON containing js file or secondary HTML page?

This is a difference in the security models and choices of Firefox (and Edge) vs the more strict Chrome. You could argue for the utility vs security of either approach.
To make this work with Chrome the way the other two browsers do, you'll need to disable that security measure with a command line flag when you start Chrome:
> chrome --allow-file-access-from-files
The other alternative is to run a local webserver (e.g. WAMP or XAMPP) and load your files via http://localhost/.

Ok, found a way that works.
In the two webpages that function as my databases, I added code to read the tables into a 2-dimensional arrays (row by cells).
These are then JSON.stringified and "var variableName = " is tacked on the beginning of the returned strings. All this is then added to a p tag (.innerText since there is also HTML code in the JSON data, rendering is not desired).
The presented data is then copied and saved using a plain text editor in a JSON.variableName.js file (the JSON in the name is to remind me what's in the file). Loading it is as easy as loading javascript code using a script tag with src="".
Also, now everything works in Firefox, Edge, and Chrome. I don't have Safari or other browsers. Bonus for me, it works in Android Firefox as well.
The two database webpages can be easily updated and they will generate the new JSON data output.
All in all, there are 6 base files: the main webpage, functions.js, two JSON variable js files, and the 2 database/JSON generator webpages. All local, and no additional webserver needed.

Related

Embedded Javascript Code for Adobe Acrobat: TypeError: this.getField is not a function

So I want some JavaScript code to run at Document Open, so I have placed my .js file into my Acrobat\JavaScripts folder (in Program Files). I'm trying to run the following code:
function ChangeFont()
{
var nNumFields = this.numFields;
console.println("There are " + nNumFields + " in this document.");
var cFieldName; var oField;
for(i = 0; i < nNumFields; i++)
{
cFieldName = this.getNthFieldName(i);
oField = this.getField(cFieldName);
oField.textFont = "PTSans";
}
}
ChangeFont()
Opening a PDF runs other code I have inserted into the same folder, but not this one (as the fonts do not change). When manually pasting this code into the Acrobat JavaScript Debugger, selecting all of the code and hitting Ctrl+Enter, it works perfectly. So why isn't it working at Document open??
I tried to isolate the problem by making a separate .js that selects one specific field and changes it's font, like so:
var f = this.getField("myField");
f.textFont = "PTSans";
After placing the the test.js into the JavaScripts folder, and opening a PDF document with Acrobat, I get the following error immediately:
"TypeError: "this.getField" is not a function."
Again, I ran it manually in the debugger console and it works perfectly.
What's going on here? I don't think I'm using an LiveCycle Designer interface, it's just Adobe Acrobat 10.
Edit: The purpose is to have all the fields at a certain font when the document is opened.
Scripts at the folder level run when Acrobat loads but before a document is opened. The numFields property belongs to the Doc object, which doesn't exist yet. Just remove the last line and you'll be able to run the function from buttons within the document.

set file attribute filesystemobject javascript

I have created a file as part of a script on a network drive and i am trying to make it hidden so that if the script is run again it should be able to see the file and act on the information contained within it but i am having trouble doing this. what i have so far is:
function doesRegisterExist(oFs, Date, newFolder) {
dbEcho("doesRegisterExist() triggered");
sExpectedRegisterFile = newFolder+"\\Register.txt"
if(oFs.FileExists(sExpectedRegisterFile)==false){
newFile = oFs.OpenTextFile(sExpectedRegisterFile,8,true)
newFile.close()
newReg = oFs.GetFile(sExpectedRegisterFile)
dbEcho(newReg.Attributes)
newReg.Attributes = newReg.Attributes+2
}
}
Windows Script Host does not actually produce an error here and the script runs throgh to competion. the only guides i have found online i have been attempting to translate from VBscript with limited success.
variables passed to this function are roughly declared as such
var oFs = new ActiveXObject("Scripting.FileSystemObject")
var Date = "29-12-2017"
var newFolder = "\\\\File-Server\\path\\to\\folder"
I know ActiveX is a dirty word to a lot of people and i should be shot for even thinking about using it but it really is a perfect fit for what i am trying to do.
Please help.
sExpectedRegisterFolder resolves to \\\\File-Server\\path\\to\\folder\\Register which is a folder and not a file.
I get an Error: file not found when I wrap the code into a try/catch block.
I tested the code on a text file as well, and there it works.
So you're either using the wrong method if you want to set the folder to hidden.
Or you forgot to include the path to the text if you want to change a file to hidden.
( Edit: Or if Register is the name of the file, add the filetype .txt ? )
If you change GetFile to GetFolder as described in https://msdn.microsoft.com/en-us/library/6tkce7xa(v=vs.84).aspx
the folder will get hidden correctly.

How can I force the browser/javascript to clear/ignore a cached file?

I have a Javascript program that extracts data from a text file (just a plain *.txt file) and then displays it in a table. It works as intended except for one issue: If I update the text file where the data lives in the update does not shows up on the table. The reason is that the file is being cached by the browser.
Is there a way to force Javascript to read from the latest version of the file and not from the cached version? Again, this is not a problem with the javascript file as doing Ctrl-5 and or Shift+Ctrl+R does not works and also updating the javascript file itself behaves as expected. it is only the file where the data is in that is the problem.
To read the text file I use the Webix toolkit which uses AJAX to read the file. The reading and parsing of the text file is done via Javascript and the Webix toolkit. There is very little html in my program.
//the name of the file is dependant of an user specified input
var theURL = rossObj.store_number.store_number + "macaddress.txt ";
webix.ajax(theURL,{
//response
error:function(text, xml, XmlHttpRequest){
webix.alert({ ok:"OK", type:"alert-warning", text:"could not open the following URL --> "+theURL, width:"400px"});
return "mac_address_error";
},
success:function(text, xml, XmlHttpRequest){
//parse the file;
}
});
Try adding a random number to the end of the url as a query string, the server will ignore but the browser will treat it as a new file
var theURL = rossObj.store_number.store_number +
"macaddress.txt?" +
Math.floor((Math.random() * 10000) + 1);

Javascript error: disk is full

With relation to Exception "The disk is full " is thrown when trying to store data in usedata object in IE7+ which has been left unanswered:
I am heavily browsing a government website created with Oracle ADF using WatiN.
The website is located in a WPF window --> WindowsFormsHost --> WebBrowser control.
The website makes heavy use of this: http://msdn.microsoft.com/en-us/library/ie/ms531424(v=vs.85).aspx, via the save and load methods.
After 2-3 minutes of browsing, I get the following javascript error during one of the "save" calls:
The disk is full, character #, line ####.
When I get this error, the WebBrowser control is rendered completely useless (no further javascript commands can be executed) and my app must be restarted.
I have tried to clear browser cache, change it's location, clear localStorage, everything to no avail.
The PC that reproduces the error has IE10 installed, but via the registry I force IE8 / IE9 mode in the webbrowser control.
Is there any way to get around this problem?
Information on this is very scarce, so any help will be greatly appreciated.
I'm on linux, so no way to test this now, but the files in question are not stored in browser cache, but in
Note: As of IE 10 this no longer holds water. Ref. edit 2 below.
W7+: %HOMEPATH%\AppData\Roaming\Microsoft\Internet Explorer\UserData
# c:\users\*user-name*\...
XP : %HOMEPATH%\Application Data\Microsoft\Internet Explorer\UserData
# c:\Documents and Settings\*user-name*\...
Or, I guess, this one also work (as a short-cut), :
%APPDATA%\Roaming\Microsoft\Internet Explorer\UserData
Modify or delete the files there.
Note that the files are tagged as protected operating system files, so to view in Explorer you have to change view to include these. If you use cmd, as in Command Prompt you have to include the /a flag as in:
dir /a
Edit 1:
Note, that index.dat is the one holding information about allocated size etc. so it won't (probably) help to only delete/move the xml files.
Edit 2:
OK. Had a look at this in Windows 7 running IE 10.
In IE 7 (on XP) the above mentioned path have an index.dat file that gets updated on save by userData. The file holds various information such as size of the index file, number of sub folders, size of all files. Then an entry for each file with a number identifying folder, url where it was saved from, name of xml file, dates etc. Wrote a simple VBScript parser for this, but as IE 10 does not use the index.dat file it is a waste.
Under IE 10 there is no longer various index.dat files but a central database file in:
%APPDATA%\Local\Microsoft\Windows\WebCache\
On my system the database file is named WebCacheV01.dat, the V part seems to differ between systems and is perhaps an in-house version number rather then a file type version.
The files are tightly locked, and as such, if one want to poke at them one solution is to make a shadow copy by using tools such as vscsc, Shadowcopy etc.
Anyhow, hacking WebCacheVxx.dat would need a lot more work, so no attempts on that on my part (for now at least).
But, register that the file gets an entry with path to the old location – so e.g. on write of someElement.save("someStorageName");, WebCacheVxx.dat gets an entry like:
...\AppData\Roaming\Microsoft\Internet Explorer\UserData\DDFFGGHH\someStorageName[1].xml
and a corresponding file is created in the above path.
The local container.dat, however, is not updated.
userData
As for the issue at hand, clearing localStorage will not help, as userData is not part of that API.
Can not find a good example on how to clear userData. Though, one way is to use the console.
Example from testing on this page:
Save some text.
Hit F12 and enter the following to clear the data:
/* ud as an acronym for userData */
var i, at,
ud_name = "oXMLBranch",
ud_id = "oPersistText",
ud = document.getElementById(ud_id);
/* To modify the storage one have to ensure it is loaded. */
ud.load(ud_name);
/* After load, ud should have a xmlDocument where first child should hold
* the attributes for the storage. Attributes as in named entries.
*
* Example: ud.setAttribute("someText", "Some text");
* ud.save(ud_name);
*
* XML-document now has attribute "someText" with value "Some text".
*/
at = ud.xmlDocument.firstChild.attributes;
/* Loop attributes and remove each one from userData. */
for (i = 0; i < at.length; ++i)
ud.removeAttribute(at[i].nodeName);
/* Finally update the file by saving the storage. */
ud.save(ud_name);
Or as a one-liner:
var ud_name = "oXMLBranch", ud_id = "oPersistText", i, at, ud = document.getElementById(ud_id); ud.load(ud_name); at = ud.xmlDocument.firstChild.attributes; for (i = 0; i < at.length; ++i) ud.removeAttribute(at[i].nodeName); ud.save(ud_name);
Eliminating one restriction
There are some issues with this. We can eliminate at least one, by ignoring the ud_id and instead create a new DOM object:
var i, at,
ud_name = "oXMLBranch",
ud = document.createElement('INPUT');
/* Needed to extend properties of input to include userData to userdata. */
ud.style.behavior = 'url(#default#userdata)';
/* Needed to not get access denied. */
document.body.appendChild(ud);
ud.load(ud_name);
at = ud.xmlDocument.firstChild.attributes;
for (i = 0; i < at.length; ++i)
ud.removeAttribute(at[i].nodeName);
/* Save, or nothing is changed on disk. */
ud.save(ud_name);
/* Clean up the DOM tree */
ud.parentNode.removeChild(ud);
So by this one should be able to clear userData by knowing name of the storage, which should be same as the file name (excluding [1].xml) or by looking at the page source.
More issues
Testing on the page mentioned above I reach a disk is full limit at 65,506 bytes.
Your problem is likely not that the disk is full, but that a write attempt is done where input data is above limit. You could try to clear the data as mentioned above and see if it continues, else you would need to clear the data about to be written.
Then again this would most likely break the application in question.
In other words, error text should have been something like:
Write of NNN bytes is above limit of NNN and not disk is full.
Tested by attaching to window onerror but unfortunately source of error was not found:
var x1, x2, x3, x4 ;
window.onerror = function () {
x1 = window.event;
x2 = x1.fromElement; // Yield null
x3 = x1.srcElement; // Yield null
x4 = x1.type;
};
End note
Unless the clear userData method solves the issue, I do not know where to go next. Have not found any option to increase the limit by registry or other means.
But perhaps it get you a little further.
There might be someone over at Super User that is able to help.

read value from txt file in javascript

I have a simple html file in which there's javascript code referring to google charts.
The code I use is this (I'll show the important part):
function drawChart(){
var data = google.visualization
.arrayToDataTable([ ['Label', 'Value'],['Temp', 22.75],]);
// etc...
}
I use a bash command (sed) to replace that 22.75 value with a new one from the last line of a .txt file. However, this throws some errors which I haven't been able to neither correct nor ever identify.
So is there any javascript code that takes that file, extracts the last value and simply displays it on the right place of the code?
UPDATE:
Sorry for the lack of info in this question, I really appreciate all the people that took the time on reading my question. I'll try to fill with more information in the next minutes.
I am able to extract the last line of the .txt file, extract the value on the right part of the '-' symbol and store it in a variable. Then that value is taken to update the html file with a sed command. The error comes when the value is updated but with no value. I guess that happends due to a failed record of temperature in the txt file, then the extracted value is a null. Finally is the html fiel with javascrit code happens to be like this:
(...)['Temp', ],]);
Then the updater can't update the value since due to the way that sed command is written I guess there's no way that it can detect a no-number-value in there. So the html remains without a value all the time.
TXT File structure:
(...)
20:25:03-23.312
20:26:02-23.312
20:27:03-23.375
20:28:03-23.375
20:29:02-23.375
20:30:02-23.312
Bash script:
# (...code...)
lastRecord=`cat /home/pi/scripts/temp_control/logs/"$today".log | awk 'END{print}'`
function rightNow {
lastTemp=`echo $lastRecord | cut -d'-' -f2`
timeOfTemp=`echo $lastRecord | cut -d'-' -f1` # Not used yet
#Command used to update
sed -i "s/['Temp', [0-9]\{1,2\}.[0-9]\{1,3\}]/$lastTemp]/" /var/www/rightnow.html
}
rightNow
You cud get your file just like any other ajax request.
Using javascript
var request = new XMLHttpRequest();
request.open('GET', 'public_path_to_file.txt', false);
request.send();
var textFileContent = request.responseText
Using jQuery
var textFileContent;
$.get('public_path_to_file.txt', function(data) {
textFileContent = data;
});
Whats left is to get the right part from textFileContent. Dependent of the structure of the file we can do this in different ways. Without an example file you are on your own but here is some examples.
If you need the last line
var lines = textFileContent.split("\n");
var lastLine = lines[lines.length - 1];
If you need to use regex
var regex = //* some regex to get your content*//gm;
var result = regex.exec(textFileContent);
// result should now the content who matches your regex
First I'll assume that you ultimately want to read a local file with your browser and your current workflow is something like a local 'bash-script' that
first updates/modifies an inline piece of javascript (inside a locally stored html
file) with the last occurring value retrieved from a local txt-file (using sed)
opens the (just modified html-) file (via commandline) inside a common browser.
Then I assume the sed-route once worked but now doesn't work anymore (probably because the html file has changed?) and now you'd like the inline javascript (in the html file) to fetch that value from the textfile itself and subsequently use it (thus without the need for the 'bash-script'/sed solution.
Thus, the answer (based on above assumptions) to your final question: 'is there any javascript code that takes that file, extracts the last value and simply displays it on the right place of the code?', depends on your final requirement:
are you ok with a file-input where you select the text-file every time you view the html-file?
If your answer is YES, then, (depending on the browser you use) you can read a local file (and work your magic on it's contents).
In modern browsers, using the File API (which was added to the DOM in HTML5) it's now possible for web content to ask the user to select local files, then read the contents of those files.
For example, using FireFox's 'FileReader' you could do:
html:
<input type="file" id="fileinput" multiple />
javascript:
function readAllFiles(evt){
var files = evt.target.files, i = 0, r, f;
if(files){
for(; f = files[i++]; ){
r = new FileReader();
r.onload = (function(f){
return function(e){
alert(e.target.result);
};
})(f);
r.readAsText(f);
}
} else {
alert("Error loading files");
}
}
document.getElementById('fileinput')
.addEventListener('change', readAllFiles, false);
Note that for accessing local files in Chrome you must start Chrome with this switch: chrome --disable-web-security
However,
if the answer is NO (so you want to specify the file, and more importantly it's path, inside the 'code', so you don't have to select the text-file every time your local app runs) then you (usually) can't (because you can't get/set the path, thank the great maker)...
Unless you choose a specific older/unpatched browser (specifically for this task) where you know of a (hack) way to do this anyway (like the IE xml vulnerability or the XMLHTTP vulnerability or etc... you get the picture..).
Some alternative solutions (that don't require you to select the correct textfile over and over again)
Setup a fullblown web (LAMP) server (to use the XMLHttpRequest way as used in aross answer, but this might feel like shooting at a mosquito with a cannon..)
Explore different script languages (but effectively still do the same as your now broken sed-solution)
Combine 1 and 2, choosing from php (the latest version has a small webserver included, you might start/stop it when needed (even in the bash-script workflow) OR using node.js (which is 'javascript' and where you can program/control a small task-specific server in just a couple of lines).
Hope this helps!
Update:
Based on your updated question, comments and request for recommendation, I'd like to suggest to use PHP to dynamically fetch the value from your log txt file and have it generate your html code with inline javascript on the fly (every time you visit the page).
The browser will never see the php code, only what php inserted to your page (in this example the last found value or 0).
You'd rename the rightnow.html file to rightnow.php and modify it (something like) this:
<!DOCTYPE html>
<html><head>
<!-- your header code -->
<script type="text/javascript">
//parts of your javascript
<?php // start php script
$logFile= '/pathToYour/logFile.log'; // <-Modify
if( $fp= #fopen($logFile, "r") ){ // if logfile succesfully opened,
fseek($fp, -30, SEEK_END); // set pointer 30 chars from EOF
$val= array_pop(explode("-", rtrim(fread($fp, 30)))); //get last value
fclose($fp); // close file
}
?> // end php script
function drawChart(){
var data=google.visualization
.arrayToDataTable([ ['Label', 'Value'],
['Temp', <?php echo $val? $val : "0"; ?>],
]); // ^php above inserts value or 0
// etc...
}
//parts of your javascript
</script>
</head><body>
<!-- your body code -->
</body></html>
Note that fopen in combination with setting the filepointer via fseek and sequentially fread-ing from the pointer to EOF does not load the complete logfile (60min * 24hour=1440 lines of 16 bytes=22.5kB at the end of the day) into memory (good for this purpose), but only the last 30 chars (as in this example).
The variable to your logfile and path must still be modified to your situation (I don't know the format of your $today variable).
Depending on your further needs you might want to perform some extra checks/logic on the array of values that explode returns (instead of popping the last value). Or what about modifying the html a little so you could also include the last temperature's time reading, etc. (But this tested piece of code should get you started and explains the procedure of going the php way).
Update:
Since you have chosen to place the last known value of your logfile as in textfile placed inside your public www-root (with a bash script I assume, every minute of the day?), you can now indeed go the 'ajax' way, as answered by aross!
However I want to hint that the code/solutions in all current answers here could be mixed (since you now also have ajax working): instead of ajax-ing (loading) a txt file, you could have php fetch and send this value to the browser on-the-fly/on-demand!
So, instead of requesting http://url_to_my_rpi/file_to_download.txt, you could request http://url_to_my_rpi/read_last_temperature.PHP which should fetch the last known value out of the log-file (set proper security/access) and send it to the browser (set proper headers), just like your text-file did. You wouldn't have to change anything in the html/javascript except the url you request.
The advantage would be (depending on how your current bash-scripts works) that your PI now only does this 'work' (of getting the last value of your logfile) when you are viewing your monitor-page. And that you are not writing that file in your www-root every minute of every day (as I suspect).
The solution achieved, finally, was like this:
I did it with a jQuery statement and reusing the javascript code of Google Charts.
First I added javascript and jQuery tags in the html file:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type='text/javascript' src='https://www.google.com/jsapi'></script>
Then I merged jquery code and javascript code that I had in one script:
<script type='text/javascript'>
// Needed this var so that I could use it in other places of the code
var t;
jQuery.get('http://url_to_my_rpi/file_to_download.txt',function(data){
console.log(data)
t=data;
},'text');
google.load('visualization', '1', {packages:['gauge']});
google.setOnLoadCallback(drawChart);
function drawChart() {
t=eval(t);
var data = google.visualization.arrayToDataTable([
['Label', 'Value'],
['Temp', t],]);
// (... more javascript with Google Charts options, display parameters..)
</script>
Finally, and even if it's not listed as the main question, be sure to enable *mod_headers* on your apache and add Header set to apache2.conf file (In my case: /etc/apache2/apache2.conf)
1) Enable the module:
a2enmod headers
2) Add the line on your configuration file
Header set Access-Control-Allow-Origin "*"
3) Restart apache 2
4) In case the 3 steps above didn't work, follow the instrcutions by entering in this website or reinstall apache2.

Categories

Resources