Including JavaScript files from GitHub into HTML pages - javascript

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)

Related

Link to external file as in css o scripts but with database

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.

I am running a basic HTML & Javascript app (connecting to Google and Twilio API), and keep getting the reference error that a variable is not defined

I built a basic HTML & Javascript app to translate a few words from the Google Translate API then text them to a number via Twilio. Here is my HTML:
<!DOCTYPE html>
<html>
<head>
<script type = "text/javascript" src="script.js"></script>
</head>
<body>
<p>Click the button to receive 3 Hebrew texts</p>
<input id="clickMe" type="button" value="clickme" onclick="myFunction();" />
</body>
</html>
And here is script.js:
function myFunction(){
// Imports the Google Cloud client library
const {Translate} =require('#google-cloud/translate').v2;
// Creates a client in Google API
const projectId = 'Xx'
const keyFilename = '/Users/x/Downloads/vocal-lead-306923-b3d8f6749397.json'
const translate = new Translate({projectId, keyFilename});
const lang = "he"
// Creates a client in Twilio API
const accountSid = 'Xx'
const authToken = 'Xx'
const client = require('twilio')(accountSid,authToken);
/** Set variables for input in Google API */
const text = ['One day'];
const target = lang;
async function translateText() {
// Translates the text into the target language. "text" can be a string for
// translating a single piece of text, or an array of strings for translating
// multiple texts.
let [translations] = await translate.translate(text, target);
translations = Array.isArray(translations) ? translations : [translations];
//console.log('Translations:');
translations.forEach((translation, i) => {
setTimeout(() => {
// Sends messages via Twilio
client.messages.create({
to:'+phone',
from:'+phone',
body: `${translation}`
})
}, i * 10000);
});
}
translateText();
}
myFunction();
By itself, the script works but it doesn't work when I run it from my local browser. I hit inspect and I get this error:
Uncaught ReferenceError: require is not defined
at myFunction (script.js:5)
at HTMLInputElement.onclick (index.html:8)
I took out auth keys/any personal data but I think that is all correct. Any advice would be helpful!
If you're trying to run the script in browser, it won't work. This is because require() is a nodejs feature, and so anything that depends on libraries by require needs to be done in a nodejs backend (you can communicate between html frontend and nodejs backend over http for example; see https://expressjs.com/ and https://nodejs.org/en/ the latter has builtin http but for routing express is recommended).
You mention that you've removed private information for this SO post, but keep in mind that when you publish this site and the script.js is visible to the user (i.e. inspect element) it'll be freely accessible. It is not good practice to put secrets in the frontend code. Consider this: a bad actor uses your API key to send spam SMS on your behalf... not good.
Also see: How to use google translation api with react

does window.location.reload(true) clear cache of asynchronous loaded resources? [duplicate]

How do I clear a browsers cache with JavaScript?
We deployed the latest JavaScript code but we are unable to get the latest JavaScript code.
Editorial Note: This question is semi-duplicated in the following places, and the answer in the first of the following questions is probably the best. This accepted answer is no longer the ideal solution.
How to force browser to reload cached CSS/JS files?
How can I force clients to refresh JavaScript files?
Dynamically reload local Javascript source / json data
Update: See location.reload() has no parameter for background on this nonstandard parameter and how Firefox is likely the only modern browser with support.
You can call window.location.reload(true) to reload the current page. It will ignore any cached items and retrieve new copies of the page, css, images, JavaScript, etc from the server. This doesn't clear the whole cache, but has the effect of clearing the cache for the page you are on.
However, your best strategy is to version the path or filename as mentioned in various other answers. In addition, see Revving Filenames: don’t use querystring for reasons not to use ?v=n as your versioning scheme.
You can't clear the cache with javascript.
A common way is to append the revision number or last updated timestamp to the file, like this:
myscript.123.js
or
myscript.js?updated=1234567890
Try changing the JavaScript file's src? From this:
<script language="JavaScript" src="js/myscript.js"></script>
To this:
<script language="JavaScript" src="js/myscript.js?n=1"></script>
This method should force your browser to load a new copy of the JS file.
Other than caching every hour, or every week, you may cache according to file data.
Example (in PHP):
<script src="js/my_script.js?v=<?=md5_file('js/my_script.js')?>"></script>
or even use file modification time:
<script src="js/my_script.js?v=<?=filemtime('js/my_script.js')?>"></script>
You can also force the code to be reloaded every hour, like this, in PHP :
<?php
echo '<script language="JavaScript" src="js/myscript.js?token='.date('YmdH').'">';
?>
or
<script type="text/javascript" src="js/myscript.js?v=<?php echo date('YmdHis'); ?>"></script>
window.location.reload(true) seems to have been deprecated by the HTML5 standard. One way to do this without using query strings is to use the Clear-Site-Data header, which seems to being standardized.
put this at the end of your template :
var scripts = document.getElementsByTagName('script');
var torefreshs = ['myscript.js', 'myscript2.js'] ; // list of js to be refresh
var key = 1; // change this key every time you want force a refresh
for(var i=0;i<scripts.length;i++){
for(var j=0;j<torefreshs.length;j++){
if(scripts[i].src && (scripts[i].src.indexOf(torefreshs[j]) > -1)){
new_src = scripts[i].src.replace(torefreshs[j],torefreshs[j] + 'k=' + key );
scripts[i].src = new_src; // change src in order to refresh js
}
}
}
try using this
<script language="JavaScript" src="js/myscript.js"></script>
To this:
<script language="JavaScript" src="js/myscript.js?n=1"></script>
Here's a snippet of what I'm using for my latest project.
From the controller:
if ( IS_DEV ) {
$this->view->cacheBust = microtime(true);
} else {
$this->view->cacheBust = file_exists($versionFile)
// The version file exists, encode it
? urlencode( file_get_contents($versionFile) )
// Use today's year and week number to still have caching and busting
: date("YW");
}
From the view:
<script type="text/javascript" src="/javascript/somefile.js?v=<?= $this->cacheBust; ?>"></script>
<link rel="stylesheet" type="text/css" href="/css/layout.css?v=<?= $this->cacheBust; ?>">
Our publishing process generates a file with the revision number of the current build. This works by URL encoding that file and using that as a cache buster. As a fail-over, if that file doesn't exist, the year and week number are used so that caching still works, and it will be refreshed at least once a week.
Also, this provides cache busting for every page load while in the development environment so that developers don't have to worry with clearing the cache for any resources (javascript, css, ajax calls, etc).
or you can just read js file by server with file_get_contets and then put in echo in the header the js contents
Maybe "clearing cache" is not as easy as it should be. Instead of clearing cache on my browsers, I realized that "touching" the file will actually change the date of the source file cached on the server (Tested on Edge, Chrome and Firefox) and most browsers will automatically download the most current fresh copy of whats on your server (code, graphics any multimedia too). I suggest you just copy the most current scripts on the server and "do the touch thing" solution before your program runs, so it will change the date of all your problem files to a most current date and time, then it downloads a fresh copy to your browser:
<?php
touch('/www/control/file1.js');
touch('/www/control/file2.js');
touch('/www/control/file2.js');
?>
...the rest of your program...
It took me some time to resolve this issue (as many browsers act differently to different commands, but they all check time of files and compare to your downloaded copy in your browser, if different date and time, will do the refresh), If you can't go the supposed right way, there is always another usable and better solution to it. Best Regards and happy camping.
I had some troubles with the code suggested by yboussard. The inner j loop didn't work. Here is the modified code that I use with success.
function reloadScripts(toRefreshList/* list of js to be refresh */, key /* change this key every time you want force a refresh */) {
var scripts = document.getElementsByTagName('script');
for(var i = 0; i < scripts.length; i++) {
var aScript = scripts[i];
for(var j = 0; j < toRefreshList.length; j++) {
var toRefresh = toRefreshList[j];
if(aScript.src && (aScript.src.indexOf(toRefresh) > -1)) {
new_src = aScript.src.replace(toRefresh, toRefresh + '?k=' + key);
// console.log('Force refresh on cached script files. From: ' + aScript.src + ' to ' + new_src)
aScript.src = new_src;
}
}
}
}
If you are using php can do:
<script src="js/myscript.js?rev=<?php echo time();?>"
type="text/javascript"></script>
Please do not give incorrect information.
Cache api is a diferent type of cache from http cache
HTTP cache is fired when the server sends the correct headers, you can't access with javasvipt.
Cache api in the other hand is fired when you want, it is usefull when working with service worker so you can intersect request and answer it from this type of cache
see:ilustration 1 ilustration 2 course
You could use these techiques to have always a fresh content on your users:
Use location.reload(true) this does not work for me, so I wouldn't recomend it.
Use Cache api in order to save into the cache and intersect the
request with service worker, be carefull with this one because
if the server has sent the cache headers for the files you want
to refresh, the browser will answer from the HTTP cache first, and if it does not find it, then it will go to the network, so you could end up with and old file
Change the url from you stactics files, my recomendation is you should name it with the change of your files content, I use md5 and then convert it to string and url friendly, and the md5 will change with the content of the file, there you can freely send HTTP cache headers long enough
I would recomend the third one see
You can also disable browser caching with meta HTML tags just put html tags in the head section to avoid the web page to be cached while you are coding/testing and when you are done you can remove the meta tags.
(in the head section)
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0"/>
Refresh your page after pasting this in the head and should refresh the new javascript code too.
This link will give you other options if you need them
http://cristian.sulea.net/blog/disable-browser-caching-with-meta-html-tags/
or you can just create a button like so
<button type="button" onclick="location.reload(true)">Refresh</button>
it refreshes and avoid caching but it will be there on your page till you finish testing, then you can take it off. Fist option is best I thing.
I tend to version my framework then apply the version number to script and style paths
<cfset fw.version = '001' />
<script src="/scripts/#fw.version#/foo.js"/>
Cache.delete() can be used for new chrome, firefox and opera.
I found a solution to this problem recently. In my case, I was trying to update an html element using javascript; I had been using XHR to update text based on data retrieved from a GET request. Although the XHR request happened frequently, the cached HTML data remained frustratingly the same.
Recently, I discovered a cache busting method in the fetch api. The fetch api replaces XHR, and it is super simple to use. Here's an example:
async function updateHTMLElement(t) {
let res = await fetch(url, {cache: "no-store"});
if(res.ok){
let myTxt = await res.text();
document.getElementById('myElement').innerHTML = myTxt;
}
}
Notice that {cache: "no-store"} argument? This causes the browser to bust the cache for that element, so that new data gets loaded properly. My goodness, this was a godsend for me. I hope this is helpful for you, too.
Tangentially, to bust the cache for an image that gets updated on the server side, but keeps the same src attribute, the simplest and oldest method is to simply use Date.now(), and append that number as a url variable to the src attribute for that image. This works reliably for images, but not for HTML elements. But between these two techniques, you can update any info you need to now :-)
Most of the right answers are already mentioned in this topic. However I want to add link to the one article which is the best one I was able to read.
https://www.fastly.com/blog/clearing-cache-browser
As far as I can see the most suitable solution is:
POST in an iframe. Next is a small subtract from the suggested post:
=============
const ifr = document.createElement('iframe');
ifr.name = ifr.id = 'ifr_'+Date.now();
document.body.appendChild(ifr);
const form = document.createElement('form');
form.method = "POST";
form.target = ifr.name;
form.action = ‘/thing/stuck/in/cache’;
document.body.appendChild(form);
form.submit();
There’s a few obvious side effects: this will create a browser history entry, and is subject to the same issues of non-caching of the response. But it escapes the preflight requirements that exist for fetch, and since it’s a navigation, browsers that split caches will be clearing the right one.
This one almost nails it. Firefox will hold on to the stuck object for cross-origin resources but only for subsequent fetches. Every browser will invalidate the navigation cache for the object, both for same and cross origin resources.
==============================
We tried many things but that one works pretty well. The only issue is there you need to be able to bring this script somehow to end user page so you are able to reset cache. We were lucky in our particular case.
window.parent.caches.delete("call")
close and open the browser after executing the code in console.
Cause browser cache same link, you should add a random number end of the url.
new Date().getTime() generate a different number.
Just add new Date().getTime() end of link as like
call
'https://stackoverflow.com/questions.php?' + new Date().getTime()
Output: https://stackoverflow.com/questions.php?1571737901173
I've solved this issue by using
ETag
Etags are similar to fingerprints, and if the resource at a given URL changes, a new Etag value must be generated. A comparison of them can determine whether two representations of a resource are the same.
Ref: https://developer.mozilla.org/en-US/docs/Web/API/Cache/delete
Cache.delete()
Method
Syntax:
cache.delete(request, {options}).then(function(found) {
// your cache entry has been deleted if found
});

How to load a txt/csv file into javascript string/array while offline

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"]
]);

How can I force clients to refresh JavaScript files?

We are currently working in a private beta and so are still in the process of making fairly rapid changes, although obviously as usage is starting to ramp up, we will be slowing down this process. That being said, one issue we are running into is that after we push out an update with new JavaScript files, the client browsers still use the cached version of the file and they do not see the update. Obviously, on a support call, we can simply inform them to do a ctrlF5 refresh to ensure that they get the up-to-date files from the server, but it would be preferable to handle this before that time.
Our current thought is to simply attach a version number onto the name of the JavaScript files and then when changes are made, increment the version on the script and update all references. This definitely gets the job done, but updating the references on each release could get cumbersome.
As I'm sure we're not the first ones to deal with this, I figured I would throw it out to the community. How are you ensuring clients update their cache when you update your code? If you're using the method described above, are you using a process that simplifies the change?
As far as I know a common solution is to add a ?<version> to the script's src link.
For instance:
<script type="text/javascript" src="myfile.js?1500"></script>
I assume at this point that there isn't a better way than find-replace to increment these "version numbers" in all of the script tags?
You might have a version control system do that for you? Most version control systems have a way to automatically inject the revision number on check-in for instance.
It would look something like this:
<script type="text/javascript" src="myfile.js?$$REVISION$$"></script>
Of course, there are always better solutions like this one.
Appending the current time to the URL is indeed a common solution. However, you can also manage this at the web server level, if you want to. The server can be configured to send different HTTP headers for javascript files.
For example, to force the file to be cached for no longer than 1 day, you would send:
Cache-Control: max-age=86400, must-revalidate
For beta, if you want to force the user to always get the latest, you would use:
Cache-Control: no-cache, must-revalidate
Google Page-Speed: Don't include a query string in the URL for static resources.
Most proxies, most notably Squid up through version 3.0, do not cache resources with a "?" in their URL even if a Cache-control: public header is present in the response. To enable proxy caching for these resources, remove query strings from references to static resources, and instead encode the parameters into the file names themselves.
In this case, you can include the version into URL ex: http://abc.com/v1.2/script.js and use apache mod_rewrite to redirect the link to http://abc.com/script.js. When you change the version, client browser will update the new file.
How about adding the filesize as a load parameter?
<script type='text/javascript' src='path/to/file/mylibrary.js?filever=<?=filesize('path/to/file/mylibrary.js')?>'></script>
So every time you update the file the "filever" parameter changes.
How about when you update the file and your update results in the same file size? what are the odds?
This usage has been deprected:
https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache
This answer is only 6 years late, but I don't see this answer in many places... HTML5 has introduced Application Cache which is used to solve this problem. I was finding that new server code I was writing was crashing old javascript stored in people's browsers, so I wanted to find a way to expire their javascript. Use a manifest file that looks like this:
CACHE MANIFEST
# Aug 14, 2014
/mycode.js
NETWORK:
*
and generate this file with a new time stamp every time you want users to update their cache. As a side note, if you add this, the browser will not reload (even when a user refreshes the page) until the manifest tells it to.
Not all browsers cache files with '?' in it. What I did to make sure it was cached as much as possible, I included the version in the filename.
So instead of stuff.js?123, I did stuff_123.js
I used mod_redirect(I think) in apache to to have stuff_*.js to go stuff.js
The common practice nowadays is to generate a content hash code as part of the file name to force the browser especially IE to reload the javascript files or css files.
For example,
vendor.a7561fb0e9a071baadb9.js
main.b746e3eb72875af2caa9.js
It is generally the job for the build tools such as webpack. Here is more details if anyone wants to try out if you are using webpack.
For ASP.NET pages I am using the following
BEFORE
<script src="/Scripts/pages/common.js" type="text/javascript"></script>
AFTER (force reload)
<script src="/Scripts/pages/common.js?ver<%=DateTime.Now.Ticks.ToString()%>" type="text/javascript"></script>
Adding the DateTime.Now.Ticks works very well.
For ASP.NET I suppose next solution with advanced options (debug/release mode, versions):
Js or Css files included by such way:
<script type="text/javascript" src="Scripts/exampleScript<%=Global.JsPostfix%>" />
<link rel="stylesheet" type="text/css" href="Css/exampleCss<%=Global.CssPostfix%>" />
Global.JsPostfix and Global.CssPostfix is calculated by the following way in Global.asax:
protected void Application_Start(object sender, EventArgs e)
{
...
string jsVersion = ConfigurationManager.AppSettings["JsVersion"];
bool updateEveryAppStart = Convert.ToBoolean(ConfigurationManager.AppSettings["UpdateJsEveryAppStart"]);
int buildNumber = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Revision;
JsPostfix = "";
#if !DEBUG
JsPostfix += ".min";
#endif
JsPostfix += ".js?" + jsVersion + "_" + buildNumber;
if (updateEveryAppStart)
{
Random rand = new Random();
JsPosfix += "_" + rand.Next();
}
...
}
If you're generating the page that links to the JS files a simple solution is appending the file's last modification timestamp to the generated links.
This is very similar to Huppie's answer, but works in version control systems without keyword substitution. It's also better than append the current time, since that would prevent caching even when the file didn't change at all.
In PHP:
function latest_version($file_name){
echo $file_name."?".filemtime($_SERVER['DOCUMENT_ROOT'] .$file_name);
}
In HTML:
<script type="text/javascript" src="<?php latest_version('/a-o/javascript/almanacka.js'); ?>">< /script>
How it works:
In HTML, write the filepath and name as you wold do, but in the function only.
PHP gets the filetime of the file and returns the filepath+name+"?"+time of latest change
We have been creating a SaaS for users and providing them a script to attach in their website page, and it was not possible to attach a version with the script as user will attach the script to their website for functionalities and i can't force them to change the version each time we update the script
So, we found a way to load the newer version of the script each time user calls the original script
the script link provided to user
<script src="https://thesaasdomain.com/somejsfile.js" data-ut="user_token"></script>
the script file
if($('script[src^="https://thesaasdomain.com/somejsfile.js?"]').length !== 0) {
init();
} else {
loadScript("https://thesaasdomain.com/somejsfile.js?" + guid());
}
var loadscript = function(scriptURL) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = scriptURL;
head.appendChild(script);
}
var guid = function() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
var init = function() {
// our main code
}
Explanation:
The user have attached the script provided to them in their website and we checked for the unique token attached with the script exists or not using jQuery selector and if not then load it dynamically with newer token (or version)
This is call the same script twice which could be a performance issue, but it really solves the problem of forcing the script to not load from the cache without putting the version in the actual script link given to the user or client
Disclaimer: Do not use if performance is a big issue in your case.
The jQuery function getScript can also be used to ensure that a js file is indeed loaded every time the page is loaded.
This is how I did it:
$(document).ready(function(){
$.getScript("../data/playlist.js", function(data, textStatus, jqxhr){
startProgram();
});
});
Check the function at http://api.jquery.com/jQuery.getScript/
By default, $.getScript() sets the cache setting to false. This appends a timestamped query parameter to the request URL to ensure that the browser downloads the script each time it is requested.
My colleague just found a reference to that method right after I posted (in reference to css) at http://www.stefanhayden.com/blog/2006/04/03/css-caching-hack/. Good to see that others are using it and it seems to work. I assume at this point that there isn't a better way than find-replace to increment these "version numbers" in all of the script tags?
In asp.net mvc you can use #DateTime.UtcNow.ToString() for js file version number. Version number auto change with date and you force clients browser to refresh automatically js file. I using this method and this is work well.
<script src="~/JsFilePath/JsFile.js?v=#DateTime.UtcNow.ToString()"></script>
One solution is to append a query string with a timestamp in it to the URL when fetching the resource. This takes advantage of the fact that a browser will not cache resources fetched from URLs with query strings in them.
You probably don't want the browser not to cache these resources at all though; it's more likely that you want them cached, but you want the browser to fetch a new version of the file when it is made available.
The most common solution seems to be to embed a timestamp or revision number in the file name itself. This is a little more work, because your code needs to be modified to request the correct files, but it means that, e.g. version 7 of your snazzy_javascript_file.js (i.e. snazzy_javascript_file_7.js) is cached on the browser until you release version 8, and then your code changes to fetch snazzy_javascript_file_8.js instead.
The advantage of using a file.js?V=1 over a fileV1.js is that you do not need to store multiple versions of the JavaScript files on the server.
The trouble I see with file.js?V=1 is that you may have dependant code in another JavaScript file that breaks when using the new version of the library utilities.
For the sake of backwards compatibility, I think it is much better to use jQuery.1.3.js for your new pages and let existing pages use jQuery.1.1.js, until you are ready to upgrade the older pages, if necessary.
Use a version GET variable to prevent browser caching.
Appending ?v=AUTO_INCREMENT_VERSION to the end of your url prevents browser caching - avoiding any and all cached scripts.
Cache Busting in ASP.NET Core via a tag helper will handle this for you and allow your browser to keep cached scripts/css until the file changes. Simply add the tag helper asp-append-version="true" to your script (js) or link (css) tag:
<link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true"/>
Dave Paquette has a good example and explanation of cache busting here (bottom of page) Cache Busting
location.reload(true);
see https://www.w3schools.com/jsref/met_loc_reload.asp
I dynamically call this line of code in order to ensure that javascript has been re-retrieved from the web server instead of from the browser's cache in order to escape this problem.
Athough it is framework specific, Django 1.4 has the staticfiles app functionality which works in a similar fashion to the 'greenfelt' site in the above answer
One simple way.
Edit htaccess
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} \.(jpe?g|bmp|png|gif|css|js|mp3|ogg)$ [NC]
RewriteCond %{QUERY_STRING} !^(.+?&v33|)v=33[^&]*(?:&(.*)|)$ [NC]
RewriteRule ^ %{REQUEST_URI}?v=33 [R=301,L]
You can add file version to your file name so it will be like:
https://www.example.com/script_fv25.js
fv25 => file version nr. 25
And in your .htaccess put this block which will delete the version part from link:
RewriteEngine On
RewriteRule (.*)_fv\d+\.(js|css|txt|jpe?g|png|svg|ico|gif) $1.$2 [L]
so the final link will be:
https://www.example.com/script.js
FRONT-END OPTION
I made this code specifically for those who can't change any settings on the backend. In this case the best way to prevent a very long cache is with:
new Date().getTime()
However, for most programmers the cache can be a few minutes or hours so the simple code above ends up forcing all users to download "the each page browsed". To specify how long this item will remain without reloading I made this code and left several examples below:
// cache-expires-after.js v1
function cacheExpiresAfter(delay = 1, prefix = '', suffix = '') { // seconds
let now = new Date().getTime().toString();
now = now.substring(now.length - 11, 10); // remove decades and milliseconds
now = parseInt(now / delay).toString();
return prefix + now + suffix;
};
// examples (of the delay argument):
// the value changes every 1 second
var cache = cacheExpiresAfter(1);
// see the sync
setInterval(function(){
console.log(cacheExpiresAfter(1), new Date().getSeconds() + 's');
}, 1000);
// the value changes every 1 minute
var cache = cacheExpiresAfter(60);
// see the sync
setInterval(function(){
console.log(cacheExpiresAfter(60), new Date().getMinutes() + 'm:' + new Date().getSeconds() + 's');
}, 1000);
// the value changes every 5 minutes
var cache = cacheExpiresAfter(60 * 5); // OR 300
// the value changes every 1 hour
var cache = cacheExpiresAfter(60 * 60); // OR 3600
// the value changes every 3 hours
var cache = cacheExpiresAfter(60 * 60 * 3); // OR 10800
// the value changes every 1 day
var cache = cacheExpiresAfter(60 * 60 * 24); // OR 86400
// usage example:
let head = document.head || document.getElementsByTagName('head')[0];
let script = document.createElement('script');
script.setAttribute('src', '//unpkg.com/sweetalert#2.1.2/dist/sweetalert.min.js' + cacheExpiresAfter(60 * 5, '?'));
head.append(script);
// this works?
let waitSwal = setInterval(function() {
if (window.swal) {
clearInterval(waitSwal);
swal('Script successfully injected', script.outerHTML);
};
}, 100);
Simplest solution? Don't let the browser cache at all. Append the current time (in ms) as a query.
(You are still in beta, so you could make a reasonable case for not optimizing for performance. But YMMV here.)
Below worked for me:
<head>
<meta charset="UTF-8">
<meta http-equiv="cache-control" content="no-cache, must-revalidate, post-check=0, pre-check=0" />
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />
</head>
If you are using PHP and Javascript then the following should work for you especially in the situation where you are doing multiple times changes on the file. So, every time you cannot change its version. So, the idea is to create a random number in PHP and then assign it as a version of the JS file.
$fileVersion = rand();
<script src="addNewStudent.js?v=<?php echo $fileVersion; ?>"></script>
<script>
var version = new Date().getTime();
var script = document.createElement("script");
script.src = "app.js?=" + version;
document.body.appendChild(script);
</script>
Feel free to delete this if someone's already posted it somewhere in the plethora of answers above.
You can do this with .htaccess
Add into your .htaccess file the following lines:
# DISABLE CACHING
<IfModule mod_headers.c>
<FilesMatch "\.js$">
Header set Cache-Control "no-store, max-age=0"
</FilesMatch>
</IfModule>
A simple trick that works fine for me to prevent conflicts between older and newer javascript files. That means: If there is a conflict and some error occurs, the user will be prompted to press Ctrl-F5.
At the top of the page add something like
<h1 id="welcome"> Welcome to this page <span style="color:red">... press Ctrl-F5</span></h1>
looking like
Let this line of javascript be the last to be executed when loading the page:
document.getElementById("welcome").innerHTML = "Welcome to this page"
In case that no error occurs the welcome greeting above will hardly be visible and almost immediately be replaced by

Categories