What I know
As we all know in HTML files we usually use
<head>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
to link an external css stylesheet to a html file so this last one will be formatted as we need and also we use
<head>
<script src="somescript.js"></script>
</head>
to make our html file use an external script.
Question
Is it possible to use the same approach by linking into a Viewer.html file an external file (or even more than one) to load from a simple database saved for example as csv, txt, db, json, xml, and so on?
HTML Pseudo code Example:
<head>
<database src="somedata.db"></database>
</head>
Of course, once the data is available to the html file, a js will be used to put it where it has to go, for example into a table contained into the Viewer.html file.
Punctualizzations:
No server of any kind must be involved, just only local files approach.
No frameworks (no jquery, no Node...)
I'm looking an approach that makes use just of html (HTML 5) + javascript (ES6) and the db file (*.csv, *.txt, *.json, *.xml, *.db, ...) containing only utf8 text. The records and fields in it will follow my specifics:
text field 1|text field 2|text field...|text field N
text field 1|text field 2|text field...|text field N
text field 1|text field 2|text field...|text field N
where the pipe symbol | is my custom field separator and the newline is the record separator.
Try this solution if it feel your needs. It make use of json format:
index.html:
<html>
<head>
<script id="jsonDatas" type="application/javascript" src="./datas.json"></script>
<script src="./index.js"></script>
</head>
<body onload="javascript:checkDatas();">
<div id="datas"></div>
</body>
</html>
datas.json:
let datas = [
{"firstname":"alain","lastname":"deseine"},
{"firstname":"robert","lastname":"dupont"},
{"firstname":"john","lastname":"query"},
{"firstname":"albert","lastname":"dumoulin"},
{"firstname":"bob","lastname":"thesponge"}
];
index.js:
function checkDatas(){
console.log('%o', datas);
}
With this solution you will have access of datas in local file datas.json.
UPDATE
This is the only way to achieve what you describe with local files.
Adding let datas... to datas.json is mandatory to make browser loading datas in a javascript var that you can access later. Browsers will blocks every attempt to access src loaded content for security reasons.
You can also use XMLHttpRequest or fetch to achieve what you want, but for this you need to serve your files with an HTTP server (which can be local). HTTP Server is required because file:// protocol is not supported by CORS. And CORS will block every requests originating from another server accordingly to CORS HEADERs that are set.
To bypass CORS with chrome browser, you can start chrome with thiese flags: --disable-web-security --user-data-dir see for details: Disable same origin policy in Chrome There is aloso some chrome extensions that block CORS (not tested). But ATTENTION, these solutions need user actions and they dramatically restrict browser security.
You can load the data using prefetch/preload in the link.
<link id="user_data" rel="preload" as="fetch" crossorigin="anonymous" href="user-data.json">
But your browser will not take any action on it and you can't access the loaded data in the javascript context.
In order to use the data in the javascript context, you have to call the fetch() function with the link URL. This will not load the data twice since the data is already preloaded on the page load.
function readData(selector){
const link = document.querySelector(selector)
if(link){
return fetch(link.href)
.then( res => res.json()) // use res.text() for XML or CSV
}else{
throw 'Invalid selector on loadData(selector)'
}
};
function abc(){
//...
readData('#user_data').then(data => {
console.log(data)
})
//...
}
Alternative solution
You can define your own custom element to get the desired feature
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="data-loader.js"> </script>
<!-- this script must be called before the custom element -->
<data-loader id="json" src="data.json" onload="onJSONFetch"></data-loader>
<script src="script.js"> </script>
</head>
<body>
<data-loader id="phone-xml" src="phone-number.xml" onload="onXMLFetch(event)"></data-loader>
<data-loader id="user-data" src="user.csv"></data-loader>
</body>
</html>
data-loader.js
class DataLoader extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.load();
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'src') {
this.load();
}
}
load() {
const attr = this.getAttribute('src');
if (attr) {
fetch(attr).then(res => res.text()).then((data) => {
const event = new CustomEvent('load', { detail: data })
this.dispatchEvent(event);
const inlineEventHandlerName = this.getAttribute('onload');
const cb = inlineEventHandlerName && window[inlineEventHandlerName];
if((typeof cb) === 'function'){
cb(event);
}
})
}
}
}
customElements.define('data-loader', DataLoader);
script.js
const documentReady = () => {
document.querySelector('#user-data').addEventListener('load', function (event) {
console.log('user-data loaded', event.detail);
})
}
function onXMLFetch(event){
console.log('onXMLFetch', event.detail);
}
function onJSONFetch(event){
console.log('onJSONFetch', event.detail);
}
document.onreadystatechange = () => {
if (document.readyState === 'interactive') {
documentReady();
}
}
Thanks to Alaindeseine's answer I got some inspirations and I did this:
into any text file (so no necessarily *.json) I put these records (notice that the following is a template literal that makes use of back ticks `, not single ' or double " quotes):
var db =
`
my data field | my data field | my data field | my data field
my data field | my data field | my data field | my data field
my data field | my data field | my data field | my data field
`
Also because of the use of var instead of let, I have the advantage that the variable db gets hoisted so I can make use of it everywhere into the file and get its content from any other script or function. Also it can be potentially declared and overwritten multiple times after the previous one is elaborated so it will be also possible to queue multiple db files to show them into the same viewer.html, which is a great advantage, for my case at least.
I already tried this way with different text file types and works great. For example I've tested
*.json
*.tsv
*.csv
*.txt
*.db
*.ext
*(no extension at all)
So at this point I believe that this can also handle other generic files extensions, at the condition they contain text enclosed into a template literal, similarly to the above.
Of course into the html file I have to point/link to the database file as if it was a script like the following:
<script src="someDBfile.ext"></script> // This links the database
<script src="myJavascript.js"></script> //This links the javascript functions that get the data from the **db** variable and create the table/s to show the well formatted data contained into the database.
Nevertheless let's hope browser developers will implement in browsers a standard and more semantically correct way of doing this with an appropriate and semantically correct tag as
<database src="somedata.db"></database>
that works similarly.
Also such procedure allows me to have just one Viewer.html to use to show all compatible files, which is also great.
Related
I'm new to Web Development (including JavaScript and HTML) and have a few issues within my personal project that seem to have no clear fixes.
Overview
My project is taking input from a user on the website, and feeding it to my back-end to output a list of word completion suggestions.
For example, input => "bass", then the program would suggest "bassist", "bassa", "bassalia", "bassalian", "bassalan", etc. as possible completions for the pattern "bass" (these are words extracted from an English dictionary text file).
The backend - running on Node JS libraries
trie.js file:
/* code for the trie not fully shown */
var Deque = require("collections/deque"); // to be used somewhere
function add_word_to_trie(word) { ... }
function get_words_matching_pattern(pattern, number_to_get = DEFAULT_FETCH) { ... }
// read in words from English dictionary
var file = require('fs');
const DICTIONARY = 'somefile.txt';
function preprocess() {
file.readFileSync(DICTIONARY, 'utf-8')
.split('\n')
.forEach( (item) => {
add_word_to_trie(item.replace(/\r?\n|\r/g, ""));
});
}
preprocess();
module.exports = get_words_matching_trie;
The frontend
An HTML script that renders the visuals for the website, as well as getting input from the user and passing it onto the backend script for getting possible suggestions. It looks something like this:
index.html script:
<!DOCTYPE HTML>
<html>
<!-- code for formatting website and headers not shown -->
<body>
<script src = "./trie.js">
function get_predicted_text() {
const autofill_options = get_words_matching_pattern(input.value);
/* add the first suggestion we get from the autofill options to the user's input
arbitrary, because I couldn't get this to actually work. Actual version of
autofill would be more sophisticated. */
document.querySelector("input").value += autofill_options[0];
}
</script>
<input placeholder="Enter text..." oninput="get_predicted_text()">
<!-- I get a runtime error here saying that get_predicted_text is not defined -->
</body>
</html>
Errors I get
Firstly, I get the obvious error of 'require()' being undefined on the client-side. This, I fix using browserify.
Secondly, there is the issue of 'fs' not existing on the client-side, for being a node.js module. I have tried running the trie.js file using node and treating it with some server-side code:
function respond_to_user_input() {
fs.readFile('./index.html', null, (err, html) => {
if (err) throw err;
http.createServer( (request, response) => {
response.write(html);
response.end();
}).listen(PORT);
});
respond_to_user_input();
}
With this, I'm not exactly sure how to edit document elements, such as changing input.value in index.html, or calling the oninput event listener within the input field. Also, my CSS formatting script is not called if I invoke the HTML file through node trie.js command in terminal.
This leaves me with the question: is it even possible to run index.html directly (through Google Chrome) and have it use node JS modules when it calls the trie.js script? Can the server-side code I described above with the HTTP module, how can I fix the issues of invoking my external CSS script (which my HTML file sends an href to) and accessing document.querySelector("input") to edit my input field?
I have MqttConnect.js file and mqttws31.js lib . I have to mqttws31.js all source code include my MqttConnect.js file, How it possible?.
when I copy everything from mqttws31.js and past mqttconnect.js file .that time this error occur:
ReferenceError: Messaging is not defined
if I try this way it is working fine :
<head>
<meta charset="UTF-8">
<title>Title of the document</title>
<script src="http://www.hivemq.com/demos/websocket-client/js/mqttws31.js" type="text/javascript"></script>
<script src="MqttJS/MqttConnect.js"></script>
</head>
MqttConnect.js file code :
// Using the HiveMQ public Broker, with a random client Id
var client = new Messaging.Client("broker.mqttdashboard.com",8000, "myclientid_" + parseInt(Math.random() * 100, 10));
//Connect Options
var options = {
timeout: 60,
keepAliveInterval:450,
cleanSession:false,
//Gets Called if the connection has sucessfully been established
onSuccess: function () {
alert("Connected:");
},
//Gets Called if the connection could not be established
onFailure: function (message) {
alert("Connection failed -: " + message.errorMessage);
}
};
function Connect(){
try {
client.connect(options)
}
catch(err){
alert(err.message);
}
}
mqttws31.js code:
http://www.hivemq.com/demos/websocket-client/js/mqttws31.js
UPDATE
where I want use this , there have no html page
This may be due to a quirk of how JavaScript loads. You can find a good example of how it should be done in this answer.
The quick answer is to place the loading of both JavaScript files into the body of the HTML document hosting them, with the MQTT library above your script.
Do NOT just copy the library into your own file, that's very poor form and a copyright violation if you don't credit the library's source properly.
Copy content of mqttws31.js into MqttConnect.js at the top (not at the bottom) and then load MqttConnect.js file:
<head>
<meta charset="UTF-8">
<title>Title of the document</title>
<script src="MqttJS/MqttConnect.js"></script>
</head>
I tried this myself, I am not getting any error. (window is undefined)
There is a dependency between the two files, that is, there is code in MqttConnect.js which needs the code in mqttws31.js in order to work properly. So I'm assuming you pasted the contents of mqttws31.js at the end of MqttConnect.js. Pasting the contents of mqttws31.js at the beginning of MqttConnect.js should fix this. Your MqttConnect.js should look like
// Contents of mqttws31.js ...
// Contents of MqttConnect.js ...
I had a coding interview quiz for front-end working with JSON and whatnot. I submitted my file but I'd just like to learn what I was missing.
And one of the reqs was Should not require a web server, and should be able to run offline..
I used jQuery and used $.getJSON() to get the data from the .JSON file. I threw it up on my WAMP localserver and it worked flawlessly across all three major browsers (IE, Firefox, Chrome). Then I moved that project to Desktop, so essentally, without a LOCALSERVER.
On Firefox 30.0, it worked great. No problems.
Oon Google Chrome, I know you can't access local files without a web server...
On Internet Explorer 11, however... it didn't work. Why?
Here is what I am using. It's not complex.
function loadTasks() {
console.log("Loading tasks...");
$.getJSON("data.json", function(result) {
$.each(result, function(i, task) {
$("#load_tasks").append(
"<div class='row'><span class='data-task'>" + task.name +
"</span> <span class='data-date'>" + task.date +
"</span> <span class='data-name'>" + task.assigned +
"</span> </div>");
});
});
}
and here is data.json
This seems to be a bug in jQuery. This bug has been reported to jQuery. The bugs status is fixed. But it seems, the bug is still at large.
Explanation
Generally in IE, ajax is implemented through ActiveXObjects. But in IE11, they made some tweaks to ActiveXObject implementation that if we try to do the following:
typeof(window.ActiveXObject)
instead of returning 'function', as it is said in IE docs, it returns undefined. jQuery used to use this to switch between xhr in normal browsers and between one in IE. Since the check evaluates to undefined, code used to create xhr object in normal browsers is run.(which of-course is a bug, strangely, for non-local files it working fine).
In a bug filed to bugs.jquery.com, the bug reporter asks,
To fix the problem it's enough to change the condition: use
"window.ActiveXObject !== undefined ?" instead of
"window.ActiveXObject ?"
jQuery developers does try to fix this with this commit, but the comment under the commit says its still not fixed and also suggests a possible way to approach this problem.
var activex; // save activex somewhere so that it only need to check once
if ( activex === undefined )
try {
new ActiveXObject("MSXML2.XMLHTTP.3.0");
activex = true;
} catch (e) {
activex = false
}
xhr = activex ? createActiveXHR() : createStandardXHR();
I tried running your code in my machine and it works fine in IE.
However if this is not running in your machine there should be some issue with IE settings. Apart from this if you want to read local file you can try the below code to resolve this issue for IE
function showData(){
function getLocalPath(fileName/*file name assuming in same directory*/){
// Remove any location or query part of the URL
var directoryPath = window.location.href.split("#")[0].split("?")[0];
var localPath;
if (directoryPath.charAt(9) == ":") {
localPath = unescape(directoryPath.substr(8)).replace(new RegExp("/","g"),"\\");
}
localPath = localPath.substring(0, localPath.lastIndexOf("\\")+1)+fileName;
console.log(localPath);
return localPath;
}
var content = null;
try {
var fileSystemObj = new ActiveXObject("Scripting.FileSystemObject");
var file = fileSystemObj.OpenTextFile(getLocalPath("data.json"),1);
content = file.ReadAll();
file.Close();
} catch(ex) {
console.log(ex);
}
console.log(content);
}
showData();
Run your html file in browser from file path and try running above function in console. It will output the content of json file in console.
You can create a wrapper for above code to use in XHR request. Let me know if you need help in integrating this with jQuery AJAX request.
What you we're missing was the use of appCache,
<html manifest="example.appcache">
in your HTACCESS add
AddType text/cache-manifest .appcache
inside example.appcache
CACHE MANIFEST
data.json
index.php
someimage.png
# continue for all the file needed for the web site to work
This means that once you have connected and downloaded the content once it's not needed again. on another note you not supposed to be able to access a file:// URI though XHR/ajax as there is no way to send the content if you wanted it offline you could have just embedded the content of the json file into you code as a string and just use var jsonStr = '{}'; var jsonObj = JSON.parse(jsonStr); where jsonStr is you code. this would have meant no connections to the server as there would be no ajax/XHR request
jQuery .getJSON uses ajax. http://api.jquery.com/jquery.getjson/
.ajax uses a XMLHttpRequest
The web security of chrome and other browsers block XMLHttpRequest to local files because it is a security issue.
Via Security in Depth: Local Web Pages
http://blog.chromium.org/2008/12/security-in-depth-local-web-pages.html
You receive an email message from an attacker containing a web page as
an attachment, which you download.
You open the now-local web page in your browser.
The local web page creates an iframe whose source is
https://mail.google.com/mail/.
Because you are logged in to Gmail, the frame loads the messages in
your inbox.
The local web page reads the contents of the frame by using JavaScript
to access frames[0].document.documentElement.innerHTML. (An Internet
web page would not be able to perform this step because it would come
from a non-Gmail origin; the same-origin policy would cause the read
to fail.)
The local web page places the contents of your inbox into a
and submits the data via a form POST to the attacker's web server. Now
the attacker has your inbox, which may be useful for spamming or
identify theft.
The solution for data which does not need same-origin policy security, is padded json. Since jsonp is not a secure format for data. Jsonp does not have the same-origin policy.
/* secured json */
{
"one": "Singular sensation",
"two": "Beady little eyes",
"three": "Little birds pitch by my doorstep"
}
/* padded json aka jsonp */
Mycallback ({
"one": "Singular sensation",
"two": "Beady little eyes",
"three": "Little birds pitch by my doorstep"
});
Since with jsonp the json is wrapped in a valid javascript function it can be opened the same way as any one would add any javascript to a page.
var element = document.createElement("script");
element.src = "jsonp.js";
document.body.appendChild(element);
And your callback processes the data,
function Mycallback(jsondata) {
}
This is functionally the same as a ajax request but different because it is a jsonp request, which is actually easier.
jQuery libs do directly support jsonp as well http://api.jquery.com/jquery.getjson/ See the example using Flickr's JSONP API; unless one was aware of the dual standards they may not even notice that jsonp is being used.
(function() { /* jsonp request note callback in url, otherwise same json*/
var flickerAPI = "http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?";
$.getJSON( flickerAPI, {
tags: "mount rainier",
tagmode: "any",
format: "json"
})
.done(function( data ) {
$.each( data.items, function( i, item ) {
$( "<img>" ).attr( "src", item.media.m ).appendTo( "#images" );
if ( i === 3 ) {
return false;
}
});
});
})();
Local access to json can be enabled but it is done differently depending on browswer.
Use --allow-file-access-from-files to enable it in chrome. https://code.google.com/p/chromium/issues/detail?id=40787
FYI: they are working on encripted json https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-encryption-08 I am fairly certain that there will be no method of using this locally the intention is to make it really, really secure.
Source: https://stackoverflow.com/a/22368301/1845953
Posting the answer just in case somebody else runs into it. In my case
IE was loading a version of jquery that apparently causes "JSON
undefined" error. Here is what I did to solve it:
<!--[if lt IE 9]>
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<![endif]-->
<!--[if gte IE 9]><!-->
<script src="http://code.jquery.com/jquery-2.0.3.js"></script>
<!--<![endif]-->
The latest one is jquery 2.1.1: direct link but it says:
(IE <9 not supported)
So I guess jquery 1.11.1: direct link
And I found out you can develop ajax and jquery stuff in Chrome on local files if you use Chrome with this flag: --allow-file-access-from-files (source)
<meta http-equiv="X-UA-Compatible" content="IE=edge">
Try adding this meta tag and check in IE
Here's a working solution.
I've included handlebars because it's cleaner.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>JSON TEST</title>
</head>
<body>
<div id="load-tasks">
</div>
<script src="jquery.min.js"></script>
<script src="handlebars.min.js"></script>
<script id="tasks-template" type="text/x-handlebars-template">
{{#each .}}
<div class="row">
<span class="data-task">
{{this.name}}
</span> <span class="data-date">
{{this.date}}
</span> <span class="data-name">
{{this.assigned}}
</span>
</div>
{{/each}}
</script>
<script>
$(function () {
var loadTasksContainer = $('#load-tasks'),
tasksTemplate = Handlebars.compile($('#tasks-template').html());
$.ajax({
type: "GET",
url: "data.json",
dataType: "json",
cache: false,
success: function (data) {
var html = tasksTemplate(data);
loadTasksContainer.append(html);
},
error: function (xhr, status, error) {
//log error and status
}
});
});
</script>
</body>
</html>
Using JSONP you could make this work for all browsers with or without a web server or even cross domain.
Example data.jsonp file:
loadTasks([
{name:"Task 1", date:"Date 1", assigned:"John Doe"},
{name:"Task 2", date:"Date 2", assigned:"Jane Doe"}
]);
Then on your page just load the data.jsonp using a script tag:
<script>
function loadTasks(tasks) {
$.each(tasks, function (i, task) {
$("#load_tasks").append(
"<div class='row'><span class='data-task'>" + task.name +
"</span> <span class='data-date'>" + task.date +
"</span> <span class='data-name'>" + task.assigned +
"</span> </div>");
});
}
</script>
<script src="data.jsonp"></script>
Try including an error callback ; jqxhr.responseText may still contain data.json .
data.json
{"data":{"abc":[123]}}
json.html
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="jquery-1.11.1.min.js"></script>
<script type="text/javascript">
$(function() {
$.getJSON(document.location.protocol + "data.json")
.then(function(data, textStatus, jqxhr) {
var response = JSON.parse(data);
console.log(textStatus, response);
}
// `error` callback
, function(jqxhr, textStatus, errorThrown) {
var response = JSON.parse(jqxhr.responseText);
console.log(textStatus, errorThrown, response);
$("body").append(response.data.abc);
});
})
</script>
</head>
<body>
</body>
</html>
Dealing with this problem will lead you to anywhere. It is a difficult task and it could be easily solved using any http server.
If your problem is that it is difficult to set up one, try this:
https://www.npmjs.org/package/http-server
On your shell you go to the directory where are your files and then you just type
http-server ./ -p 12345
where 12345 can be changed by any valid and not already used port of your choice.
I have a small html/javascript webpage that I want to run in a browser offline.
In the same way the page can include an image or a css file and use it while offline, I want to include a 3mb spreadsheet that the javascript reads into a 2d-array, and I'm hoping for something that would work on IE8 as well as modern browsers.
C:\Folder\index.html
C:\Folder\code.js
C:\Folder\picture.png
C:\Folder\spreadsheet.csv
I've found multiple methods online like
<script src="jquery-csv.js"></script>
var table = $.csv.toArrays("spreadsheet.csv");
or
d3.text('spreadsheet.csv', function(error, _data){
var table = d3.csv.parseRows(_data);
});
or
$(document).ready(function() {
$.ajax({
type: "GET",
url: "data.txt",
dataType: "text",
success: function(data) {processData(data);}
});
});
But I tend to get same-origin policy errors such as:
XMLHttpRequest cannot load file://data.txt. Received an invalid response. Origin 'null' is therefore not allowed access.
Uncaught SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "null" from accessing a frame with origin "null". Protocols, domains, and ports must match.
I can't seem to get these to work offline. How could I accomplish this?
Edit:
I'm managed to get the following to work for a text file only on Firefox using the CSVToArray function found here, which is pretty sluggish with a file of this size, and a hidden iframe.
Ultimately, it would be preferable if this was capable of running on IE8, and if I used a csv rather than a txt file, but at least it's a start.
<iframe style="display:none;" id='text' src = 'file.txt' onload='read_text_file()'>
</iframe>
<script type="text/javascript" >
function read_text_file() {
var text = document.getElementById('text').contentDocument.body.firstChild.innerHTML;
var table = CSVToArray(text);
}
For IE8 I managed to get this to work on a small scale but with the 3mb file it will occasionally crash the browser and will always accost the user with both a ton of warning messages that activex is being used and a wave of warnings that the script will slow down the computer.
window.onLoad = readFileInIE("file.csv");
function readFileInIE(filePath) {
try {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var file = fso.OpenTextFile(filePath, true);
var text = file.ReadAll();
var table = CSVToArray(text);
file.Close();
return fileContent;
} catch (e) {
if (e.number == -2146827859) {
alert('Unable to access local files due to browser security settings. ' +
'To overcome this, go to Tools->Internet Options->Security->Custom Level. ' +
'Find the setting for "Initialize and script ActiveX controls not marked as safe" and change it to "Enable" or "Prompt"');
}
}
}
This might not work in IE8, but the HTML5 API is really useful for this. Just use:
window.onload = function() {
var fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', function(e) {
var file = fileInput.files[0];
var textType = //format you'd like to recieve;
if (file.type.match(textType)) {
var reader = new FileReader();
reader.onload = function(e) {
// apply magic here
}
reader.readAsText(file);
}
else
{
fileDisplayArea.innerText ="Sorry matey, can't help you with that filetype."
}
});
}
Then after that, a simple .html file that looks like this would do the trick:
<html lang="en">
<head>
<script src="script.js"></script>
</head>
<body>
<div id="page-wrapper">
<div>
<input type="file" id="fileInput">
</div>
<pre id="fileDisplayArea"></pre> //display any output here
</div>
</body>
</html>
It's not quite clear what you want to do.
Using jQuery it's possible to modify events that happen in the DOM. Using this you could potentially save the source code when you're done making changes. You would then need to replace your current source code with the saved code to use the changes the next time you open up the page. However, this would be a very laborious process and there are likely a number of better ways to accomplish what you want to do depending on what that is.
Also, in regards to Shota's post. You can't use AJAX unless you have a server running in the background. If you decide to set the system up on a server there are a number of options for accomplishing what you want.
My comment become too long.
You can't include data files in the same way as media. The easiest way would be to preprocess the csv into a js array and then include the csv like js <script src="mydata.csv.js"></script>.
By offline you mean local files and not public? The first suggestion would be to upgrade your browser. It doesn't quiet make sense if its a local file supporting all major browsers. Sorry I'm sure you have reasons why you can't. But upgrading would get around the non Ecmascript 5 support in ie8.
To get around the cross origin policy you'd have to run your file on a local webserver. So your html page would be on something like localhost:8080 and your csv localhost:8080/mydata.csv this gives privileges to the html to allow access to the csv file as they're now on the same domain. D3, jquerycsv should now work. Its a big security risk allowing any html file to access the filesystem freely.
If a local server isn't an option. You have to select the file each time you load with an input field. This grants the browser permissions to access this file.
After selecting the file, to read the contents for the main browsers (with Ecma5) look into FileReader on MDN, and an example of use can be found here. For ie8 + 9 there is VBscript support to read files. You can use VB just like JS using <script type="text/vbscript"></script>
If you really want to access local resources from a sever page then you need also a local page that allows the access. A local HTML page inside an <iframe> could read the text file and post contents to the main page via window.postMessage().
There might also be a way with HTML5 iframes and the sandbox attribute, but not in IE9 and below.
see:
https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe
As you have realized, any AJAX-based solution will be affected by security restrictions for local file access. Instead of finding browser-specific workarounds, you could go the JSONP way which avoids AJAX.
This would require you to pre-process your CSV data and save it in a more JS-friendly format. But this would be a good idea anyway, as native JS parsing is likely to perform better than a CSV parser implemented in JS.
It could look roughly like this:
index.html
</head>
<body>
<div id="page-wrapper">
<div>
<input type="file" id="fileInput">
</div>
<pre id="fileDisplayArea"></pre> <!-- display any output here -->
</div>
<script src="script.js"></script>
<script src="data.js"></script>
</body>
</html>
script.js
function processData(data) {
// Your logic
// (will be called once data.js is loaded)
}
data.js
processData([
["your", "data"]
]);
PAY ATTENTION!
You can't include Github scripts directly from Github after this change.
We added the X-Content-Type-Options: nosniff header to our raw URL responses way back in 2011 as a first step in combating hotlinking. This has the effect of forcing the browser to treat content in accordance with the Content-Type header. That means that when we set Content-Type: text/plain for raw views of files, the browser will refuse to treat that file as JavaScript or CSS.
But there are alternatives. Check my answer to this question.
I am trying to include a JavaScript file from GitHub into a local HTML file for testing (like an image found on the internet: <img src="http://...">).
I would like something like this:
<script src="https://github.com/[username]/[repository]/blob/master/public/[fileName].js"></script>
The problem is that this doesn't work.
How can I do this?
You will be able to do it with a URL similar to this:
https://rawgit.com/h5bp/html5-boilerplate/master/src/js/plugins.js
Note that this is not the same as clicking on the "raw" button within GitHub;
that button will also give you a clean version of the file, but it will be sent
with the wrong headers.
A Word of warning; the file is not not being served from GitHub. It is being
redirected through the rawgit.com domain. As is stated on https://rawgit.com:
Hey! rawgit.com is just for fun and is not associated with GitHub in any
way.
Keep in mind that the owner of that domain is now in control of the traffic and
is able to manipulate it as they see fit.
After enabling GitHub pages of your Repository, use following link:
<script src="https://[username].github.io/[repository]/[filename].js"></script>
rawgit looks like shutting down by end of 2019,
some options for delivering content with with proper Content-Type headers.
https://raw.githack.com/ , https://combinatronics.com=>exact alternative but it cannot be used for
fetching from client side javascript, as cors is enabled here.
jsdelivr =>for delivering javascript files
You can include hosted CSS, HTML and JS file in GITHUB PAGES
Just click at the settings on your github repository
then at this tab scroll down to the GitHub Pages and select with the dropdown
Then HOray you can now access it live
This is the raw that returns text/plain mime type
https://raw.githubusercontent.com/bdalina54/bdalina54.github.io/master/assets/js/terebra/acrior.js
<script src="https://raw.githubusercontent.com/bdalina54/bdalina54.github.io/master/assets/js/terebra/acrior.js"></script>
And this is the live version
https://bdalina54.github.io/assets/js/terebra/acrior.js
<script src="https://bdalina54.github.io/assets/js/terebra/acrior.js"></script>
You can check my screenshot how I did it
https://prnt.sc/obbrpn
https://prnt.sc/obbt69
https://prnt.sc/obbskb
This should work:
<script src="https://raw.github.com/[username]/[repository]/[branch]/[filename].js"></script>
Here is how you can get redirected to the needed address in github:
UPDATED ANSWER:
The old answer I gave in 2014 has stopped working, but you can use 3rd party CDN to serve js directly from github. Jsdelivr is one of those CDNs, powered by CloudFlare and Fastly.
Example:
<script src="https://cdn.jsdelivr.net/gh/<user>/<repo>/<filename>.js">
Or use their tool to convert: https://www.jsdelivr.com/github
OLD ANSWER:
This works even with github's recent change:
<script>
$.getScript("https://raw.github.com/username/repo/master/src/script.js");
</script>
PS. requires jQuery.
2021 Working Solution: Use Combinatorics.
See this answer for examples. Copying here a quick one:
The only change is from raw.github.com that becomes combinatronics.com:
<script
type="text/javascript"
src="https://combinatronics.com/username/repo/master/src/file.js"
></script>
Try somethig like this:
<html>
<head>
<script src="https://raw.github.com/e0ne/BlogSamples/master/ModalDialog/AdvancedPopup/jquery.min.js"></script>
</head>
It's working for me
You can use the API provided by GitHub to get all the context, and then use a method similar to eval to force write it in.
I don't recommend you use the way in any official product, but as a test or write some practice scripts, handy, can save a lot of duplication of code
Docs GitHub API get contents
python solution
javascript solution (see below script GithubExplorer)
Script and Example
I create a component that allows you drags the file to the input.
https://api.github.com/repos/CarsonSlovoka/excel/contents/app/urls/static/js/pkg/input/ask-file.js?ref=d625296
Below will show you how to load the content and embed it such that you can use it.
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"
integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"/>
<!-- 👆 Above CSS are not must be given, I want it more pretty, that all. -->
<input data-com="ask-file" placeholder="select or drag the file to attach" multiple>
<script type="module">
function GithubExplorer() {
/**
* #param {string} owner Username
* #param {string} repo repository name
* #param {string} path filepath
* #param {string} branch branch name or SHA1
* #param {string} token The token is used for project private. generate new token 👉 https://github.com/settings/tokens
* */
this.Query = async (owner, repo, path, {branch = "master", token = undefined}) => {
// https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#supplying_request_options
const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path}?ref=${branch}`
const headers = {
accept: "application/vnd.github.v3.raw",
}
if (token) {
headers["authorization"] = `token ${token}`
}
const response = await fetch(url, {
method: 'GET',
headers,
})
if (!response.ok) {
const errMsg = await response.text()
throw Error(`${response.statusText} (${response.status}) | ${errMsg} `)
}
return await response.blob()
}
}
(async () => {
const github = new GithubExplorer()
const blobAskFileScript = await github.Query("CarsonSlovoka", "excel", "app/urls/static/js/pkg/input/ask-file.js", {branch: "d625296"})
let askFileScriptText = await blobAskFileScript.text()
askFileScriptText = askFileScriptText.replaceAll("export class AskInputFile", "class AskInputFile")
document.querySelector(`head`).append(
document.createRange().createContextualFragment(`
<script>${askFileScriptText}<\/script>`)
)
AskInputFile.BuildAll() // This function is from the script.
})()
</script>
below is a simple script that you know how to do after loading the content.
const body = document.querySelector(`body`)
const range = document.createRange()
const content = `<script>console.log("hello world")<\/script>`
const frag = range.createContextualFragment(content)
body.append(frag)