Jquery - reload css with google fonts link - javascript

I need to reload css files after the user select his theme colors with colorpicker.
Into another question here i found this good solution :
/**
* Forces a reload of all stylesheets by appending a unique query string
* to each stylesheet URL.
*/
function reloadStylesheets() {
var queryString = '?reload=' + new Date().getTime();
$('link[rel="stylesheet"]').each(function () {
this.href = this.href.replace(/\?.*|$/, queryString);
});
}
my problem is that i have a google fonts linked into the pages
<link href='http://fonts.googleapis.com/css?family=Varela+Round' rel="stylesheet">
and in console i recieve this error :
Failed to load resource: the server responded with a status of 400 (Bad Request)
http://fonts.googleapis.com/css?reload=1397489335832
The other css stored into my server are reloaded well.
e.g. <link href="css/style.css" rel="stylesheet" type="text/css" />
How i can "separate" the stylesheet google from the others ?

Your link to the fonts is http://fonts.googleapis.com/css?family=Varela+Round, therefore your reload link should be http://fonts.googleapis.com/css?family=Varela+Round&reload=1397489335832
You need to update your function to take into account cases where there is already a parameter in the URL.
function reloadStylesheets() {
var queryString = 'reload=' + new Date().getTime();
$('link[rel="stylesheet"]').each(function () {
if(this.href.indexOf('?') !== -1){
this.href = this.href + '&' + queryString;
}
else{
this.href = this.href + '?' + queryString;
}
});
}

You can test for the google stylesheet link easily enough:
var googleUrl = new RegExp('fonts.googleapis.com/css\\?family=Varela\\+Round');
$('link[rel="stylesheet"]').each(function () {
if (googleUrl.test(this.href)) {
continue;
}
However, the root problem is that your reloadStylesheets function is too aggressive in replacing the queryString. Instead of blindly replacing everything after the question mark with your new reload parameter, you should be more precise. That way, if you ever load a local stylesheet where the query string is important (e.g., a server-generated style sheet with only a subset of styles for mobile), you don't break your page with the script.
This will also obviate the need to exclude the Google stylesheet, but since it's unlikely that is going to change, you should continue to exclude it and let it load from browser cache.

Related

Force hard reload in Nextjs [duplicate]

How can I force the web browser to do a hard refresh of the page via JavaScript?
Hard refresh means getting a fresh copy of the page AND refresh all the external resources (images, JavaScript, CSS, etc.).
⚠️ This solution won't work on all browsers. MDN page for location.reload():
Note: Firefox supports a non-standard forceGet boolean parameter for location.reload(), to tell Firefox to bypass its cache and force-reload the current document. However, in all other browsers, any parameter you specify in a location.reload() call will be ignored and have no effect of any kind.
Try:
location.reload(true);
When this method receives a true value as argument, it will cause the page to always be reloaded from the server. If it is false or not specified, the browser may reload the page from its cache.
More info:
The location object
window.location.href = window.location.href
Accepted answer above no longer does anything except just a normal reloading on mostly new version of web browsers today. I've tried on my recently updated Chrome all those, including location.reload(true), location.href = location.href, and <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />. None of them worked.
My solution is by using server-side capability to append non-repeating query string to all included source files reference as like below example.
<script src="script.js?t=<?=time();?>"></script>
So you also need to control it dynamically when to keep previous file and when to update it. The only issue is when files inclusion is performed via script by plugins you have no control to modify it. Don't worry about source files flooding. When older file is unlinked it will be automatically garbage collected.
Changing the current URL with a search parameter will cause browsers to pass that same parameter to the server, which in other words, forces a refresh.
(No guarantees if you use intercept with a Service Worker though.)
const url = new URL(window.location.href);
url.searchParams.set('reloadTime', Date.now().toString());
window.location.href = url.toString();
If you want support older browsers:
if ('URL' in window) {
const url = new URL(window.location.href);
url.searchParams.set('reloadTime', Date.now().toString());
window.location.href = url.toString();
} else {
window.location.href = window.location.origin
+ window.location.pathname
+ window.location.search
+ (window.location.search ? '&' : '?')
+ 'reloadTime='
+ Date.now().toString()
+ window.location.hash;
}
That said, forcing all your CSS and JS to refresh is a bit more laborious. You would want to do the same process of adding a searchParam for all the src attributes in <script> and href in <link>. That said it won't unload the current JS, but would work fine for CSS.
document.querySelectorAll('link').forEach((link) => link.href = addTimestamp(link.href));
I won't bother with a JS sample since it'll likely just cause problems.
You can save this hassle by adding a timestamp as a search param in your JS and CSS links when compiling the HTML.
This is a 2022 update with 2 methods, considering SPA's with # in url:
METHOD 1:
As mentioned in other answers one solution would be to put a random parameter to query string. In javascript it could be achieved with this:
function urlWithRndQueryParam(url, paramName) {
const ulrArr = url.split('#');
const urlQry = ulrArr[0].split('?');
const usp = new URLSearchParams(urlQry[1] || '');
usp.set(paramName || '_z', `${Date.now()}`);
urlQry[1] = usp.toString();
ulrArr[0] = urlQry.join('?');
return ulrArr.join('#');
}
function handleHardReload(url) {
window.location.href = urlWithRndQueryParam(url);
// This is to ensure reload with url's having '#'
window.location.reload();
}
handleHardReload(window.location.href);
The bad part is that it changes the current url and sometimes, in clean url's, it could seem little bit ugly for users.
METHOD 2:
Taking the idea from https://splunktool.com/force-a-reload-of-page-in-chrome-using-javascript-no-cache, the process could be to get the url without cache first and then reload the page:
async function handleHardReload(url) {
await fetch(url, {
headers: {
Pragma: 'no-cache',
Expires: '-1',
'Cache-Control': 'no-cache',
},
});
window.location.href = url;
// This is to ensure reload with url's having '#'
window.location.reload();
}
handleHardReload(window.location.href);
Could be even combined with method 1, but I think that with headers should be enought:
async function handleHardReload(url) {
const newUrl = urlWithRndQueryParam(url);
await fetch(newUrl, {
headers: {
Pragma: 'no-cache',
Expires: '-1',
'Cache-Control': 'no-cache',
},
});
window.location.href = url;
// This is to ensure reload with url's having '#'
window.location.reload();
}
handleHardReload(window.location.href);
UPDATED to refresh all the external resources (images, JavaScript, CSS, etc.)
Put this in file named HardRefresh.js:
function hardRefresh() {
const t = parseInt(Date.now() / 10000); //10s tics
const x = localStorage.getItem("t");
localStorage.setItem("t", t);
if (x != t) location.reload(true) //force page refresh from server
else { //refreshed from server within 10s
const a = document.querySelectorAll("a, link, script, img")
var n = a.length
while(n--) {
var tag = a[n]
var url = new URL(tag.href || tag.src);
url.searchParams.set('r', t.toString());
tag.href = url.toString(); //a, link, ...
tag.src = tag.href; //rerun script, refresh img
}
}
}
window.addEventListener("DOMContentLoaded", hardRefresh);
window.addEventListener("deviceorientation", hardRefresh, true);
This code do a fully controled forced hard refresh for every visitor, so that any update will show up without a cashing problem.
Duplicated DOM rendering is not a performance issue, because the first render is from cache and it stops rendering in <script src="js/HardRefresh.js"> where it reload a page from server. When it run a refreshed page it also refresh urls in page.
The last refresh time x is stored in localStorage. It is compared with the current time t to refresh within 10 seconds. Assuming a load from server not take more than 10 sec we manage to stop a page refresh loop, so do not have it less than 10s.
For a visitor of page the x != t is true since long time ago or first visit; that will get page from server. Then diff is less than 10s and x == t, that will make the else part add query strings to href and src having sources to refresh.
The refresh() function can be called by a button or other conditioned ways. Full control is managed by refining exclusion and inclusion of urls in your code.
For angular users and as found here, you can do the following:
<form [action]="myAppURL" method="POST" #refreshForm></form>
import { Component, OnInit, ViewChild } from '#angular/core';
#Component({
// ...
})
export class FooComponent {
#ViewChild('refreshForm', { static: false }) refreshForm;
forceReload() {
this.refreshForm.nativeElement.submit();
}
}
The reason why it worked was explained on this website: https://www.xspdf.com/resolution/52192666.html
You'll also find how the hard reload works for every framework and more in this article
explanation: Angular
Location: reload(), The Location.reload() method reloads the current URL, like the Refresh button. Using only location.reload(); is not a solution if you want to perform a force-reload (as done with e.g. Ctrl + F5) in order to reload all resources from the server and not from the browser cache. The solution to this issue is, to execute a POST request to the current location as this always makes the browser to reload everything.
The most reliable way I've found is to use a chache buster by adding a value to the querystring.
Here's a generic routine that I use:
function reloadUrl() {
// cache busting: Reliable but modifies URL
var queryParams = new URLSearchParams(window.location.search);
queryParams.set("lr", new Date().getTime());
var query = queryParams.toString();
window.location.search = query; // navigates
}
Calling this will produce something like this:
https://somesite.com/page?lr=1665958485293
after a reload.
This works to force reload every time, but the caveat is that the URL changes. In most applications this won't matter, but if the server relies on specific parameters this can cause potential side effects.

Can I use JavaScript to change the JavaScript files a HTML document accesses?

I am trying to write a HTML page that asks users a series of questions. The answers to these questions are evaluated by my JavaScript code and used to determine which additional JavaScript file the user needs to access. My code then adds the additional JavaScript file to the head tag of my HTML page. I don't want to merge the code into a single JavaScript file because these additional files are large enough to be a nightmare if they're together, and I don't want to add them all to the head when the page first loads because I will have too many variable conflicts. I'm reluctant to redirect to a new webpage for each dictionary because this will make a lot of redundant coding. I'm not using any libraries.
I begin with the following HTML code:
<head>
<link rel="stylesheet" type="text/css" href="main.css">
<script src="firstSheet.js" type="text/JavaScript"></script>
</head>
//Lots of HTML.
<div id="mainUserMenu">
</div>
And I have the following JavaScript function:
function thirdLevelQuestions(secondLevelAnswer) {
//Code here to calculate the variables. This part works.
activeDictionary = firstKey + secondKey + '.js';
//Changing the HTML header to load the correct dictionary.
document.head.innerHTML = '<link rel="stylesheet" type="text/css" href="main.css"><script src="' + activeDictionary + '" type="text/JavaScript"></script><script src="firstSheet.js" type="text/JavaScript"></script>';
//for loop to generate the next level of buttons.
for (var i = 0; i < availableOptions.length; i++) {
document.getElementById('mainUserMenu').innerHTML += '<button onclick="fourthLevelQuestions(' + i + ')">' + availableOptions[i] + '</button>';
}
}
This creates the buttons that I want, and when I inspect the head element I can see both JavaScript files there. When I click on any of the buttons at this level they should call a function in the second file. Instead Chrome tells me "Uncaught ReferenceError: fourthLevelQuestions is not defined" (html:1). If I paste the code back into firstSheet.js the function works, so I assume the problem is that my HTML document is not actually accessing the activeDictionary file. Is there a way to do this?
What Can be done
You are trying to load Javascript on Demand. This has been a well thought out problem lately and most of the native solutions didn't work well across bowser implementations. Check a study here with different solutions and background of the problem explained well.
For the case of large web applications the solution was to use some javascript library that helped with modularising code and loading them on demand using some script loaders. The focus is on modularizing code and not in just script loading. Check some libraries here. There are heavier ones which includes architectures like MVC with them.
If you use AJAX implementation of jQuery with the correct dataType jQuery will help you evaluate the scripts, they are famous for handling browser differences. You can as well take a look at the exclusive getScript() which is indeed a shorthand for AJAX with dataType script. Keep in mind that loading script with native AJAX does not guarantee evaluation of the javascript included, jQuery is doing the evaluation internally during the processing stage.
What is wrong
What you have done above might work in most modern browsers (not sure), but there is an essential flaw in your code. You are adding the script tags to your head using innerHTML which inserts those lines to your HTML. Even if your browser loads the script it takes a network delay time and we call it asynchronous loading, you cannot use the script right away. Then what do you do? Use the script when its ready or loaded. Surprisingly you have an event for that, just use it. Can be something like:
var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.type= 'text/javascript';
script.onreadystatechange= function () {
if (this.readyState == 'complete') helper();
}
script.onload= helper;
script.src= 'helper.js';
head.appendChild(script);
Check this article for help with implementation without using external libraries
From the variable name activeDictionary If I guess that you are loading some data sets as opposed to javascript programs, you should try looking into JSON and loading and using them dynamically.
If this Question/Answer satisfies your needs, you should delete your question to avoid duplicate entries in SO.
The best way to achieve this would be with jQuery:
$(document).ready(function() {
$('#button').click(function() {
var html = "<script src='newfile.js' type='text/javascript'></script>";
var oldhtml = "<script src='firstSheet.js' type='text/javascript'></script>";
if ($(this).attr('src') == 'firstSheet.js') {
$('script[src="firstSheet.js"]').replace(html);
return;
}
$('script[src="newfile.js"]').replace(oldhtml);
});
});
I would suggest you create the elements how they should be and then append them. Also, if you are dynamically adding the firstSheet.js you shouldn't include it in your .html file.
function thirdLevelQuestions(secondLevelAnswer) {
var mainUserMenu = document.getElementById('mainUserMenu');
activeDictionary = firstKey + secondKey + '.js';
var css = document.createElement('link');
css.rel = 'stylesheet';
css.type = 'text/css';
css.href = 'main.css';
var script1 = document.createElement('script');
script1.type = 'text/javascript';
script1.src = 'firstSheet.js';
var script2 = document.createElement('script');
script2.type = 'text/javascript';
script2.src = activeDictionary;
document.head.appendChild(css);
document.head.appendChild(script1);
document.head.appendChild(script2);
for (var i = 0; i < availableOptions.length; i++) {
var btn = document.createElement('button');
btn.onclick = 'fourthLevelQuestions(' + i + ')';
var val = document.createTextNode(availableOptions[i]);
btn.appendChild(val);
mainUserMenu.appendChild(btn);
}
}

Avoid jQuery Mobile to force script/CSS reload using _=TIMESTAMP query string parameter

As far as I know, if you want to load JavaScript or CSS files together with a specific page that is automatically loaded via ajax then you have to put the CSS/JavaScript references within the <div data-role="page"> container.
Example:
<div data-role="page" data-theme="e">
<script type="text/javascript" src="/js/jquery/plugins/plugins.js"></script>
In general, this works fine. However, somewhere along the way, the script url gets modified:
/js/some_sepcial_script.js becomes e.g. js/some_sepcial_script.js?_=1299308309681
Where 1299308309681 is the current Unix timestamp which changes on every request and thus prevents caching. I am pretty sure that this is intended behaviour but does anyone know how you can prevent the timestamp from being appended to the script/CSS urls if you want to make the file cacheable?
Have you tried:?
$.ajax ({
// Disable caching of AJAX response */
cache: false
});
It should globally change ajax requests. I'm just not sure about external scripts.
[EDIT]
This is the source code involved for jquery mobile 1.0a3:
var all = $("<div></div>");
//workaround to allow scripts to execute when included in page divs
all.get(0).innerHTML = html;
to = all.find('[data-role="page"], [data-role="dialog"]').first();
//rewrite src and href attrs to use a base url
if( !$.support.dynamicBaseTag ){
var newPath = path.get( fileUrl );
to.find('[src],link[href]').each(function(){
var thisAttr = $(this).is('[href]') ? 'href' : 'src',
thisUrl = $(this).attr(thisAttr);
//if full path exists and is same, chop it - helps IE out
thisUrl.replace( location.protocol + '//' + location.host + location.pathname, '' );
if( !/^(\w+:|#|\/)/.test(thisUrl) ){
$(this).attr(thisAttr, newPath + thisUrl);
}
});
}
Nothing on there adds a cache preventing param.
[EDIT 2]
I know this goes beyond troubleshooting to a work around but have you tried dynamically loading the js like explained here: http://www.javascriptkit.com/javatutors/loadjavascriptcss.shtml
(I know it can be done through jQuery but for testing purposes I'm trying to avoid jQuery)
if I include jQuery 1.4.3 instead of 1.5 everything works fine. That's a sufficient solution for me. Thanks again for your support.
Try running:
$.ajaxPrefilter("script", function (s) {
if (s.cache === undefined) {
s.cache = true;
}
});
Does it change this behavior?

Is there an easy way to reload css without reloading the page?

I'm trying to make a live, in-page css editor with a preview function that would reload the stylesheet and apply it without needing to reload the page. What would be the best way to go about this?
Possibly not applicable for your situation, but here's the jQuery function I use for reloading external stylesheets:
/**
* Forces a reload of all stylesheets by appending a unique query string
* to each stylesheet URL.
*/
function reloadStylesheets() {
var queryString = '?reload=' + new Date().getTime();
$('link[rel="stylesheet"]').each(function () {
this.href = this.href.replace(/\?.*|$/, queryString);
});
}
On the "edit" page, instead of including your CSS in the normal way (with a <link> tag), write it all to a <style> tag. Editing the innerHTML property of that will automatically update the page, even without a round-trip to the server.
<style type="text/css" id="styles">
p {
color: #f0f;
}
</style>
<textarea id="editor"></textarea>
<button id="preview">Preview</button>
The Javascript, using jQuery:
jQuery(function($) {
var $ed = $('#editor')
, $style = $('#styles')
, $button = $('#preview')
;
$ed.val($style.html());
$button.click(function() {
$style.html($ed.val());
return false;
});
});
And that should be it!
If you wanted to be really fancy, attach the function to the keydown on the textarea, though you could get some unwanted side-effects (the page would be changing constantly as you type)
Edit: tested and works (in Firefox 3.5, at least, though should be fine with other browsers). See demo here: http://jsbin.com/owapi
There is absolutely no need to use jQuery for this. The following JavaScript function will reload all your CSS files:
function reloadCss()
{
var links = document.getElementsByTagName("link");
for (var cl in links)
{
var link = links[cl];
if (link.rel === "stylesheet")
link.href += "";
}
}
A shorter version in Vanilla JS and in one line:
document.querySelectorAll("link[rel=stylesheet]").forEach(link => link.href = link.href.replace(/\?.*|$/, "?" + Date.now()))
It loops trough all stylesheet links and appends (or updates) a timestamp to the URL.
Check out Andrew Davey's snazzy Vogue project - http://aboutcode.net/vogue/
One more jQuery solution
For a single stylesheet with id "css" try this:
$('#css').replaceWith('<link id="css" rel="stylesheet" href="css/main.css?t=' + Date.now() + '"></link>');
Wrap it in a function that has global scrope and you can use it from the Developer Console in Chrome or Firebug in Firefox:
var reloadCSS = function() {
$('#css').replaceWith('<link id="css" rel="stylesheet" href="css/main.css?t=' + Date.now() + '"></link>');
};
Based on previous solutions, I have created bookmark with JavaScript code:
javascript: { var toAppend = "trvhpqi=" + (new Date()).getTime(); var links = document.getElementsByTagName("link"); for (var i = 0; i < links.length;i++) { var link = links[i]; if (link.rel === "stylesheet") { if (link.href.indexOf("?") === -1) { link.href += "?" + toAppend; } else { if (link.href.indexOf("trvhpqi") === -1) { link.href += "&" + toAppend; } else { link.href = link.href.replace(/trvhpqi=\d{13}/, toAppend)} }; } } }; void(0);
Image from Firefox:
What does it do?
It reloads CSS by adding query string params (as solutions above):
Content/Site.css becomes Content/Site.css?trvhpqi=1409572193189 (adds date)
Content/Site.css?trvhpqi=1409572193189 becomes Content/Site.css?trvhpqi=1409572193200 (date changes)
http://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,800italic,800,700italic,700,600italic,600&subset=latin,latin-ext becomes http://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,800italic,800,700italic,700,600italic,600&subset=latin,latin-ext&trvhpqi=1409572193189 (adds new query string param with date)
Since this question was shown in the stackoverflow in 2019, I'd like to add my contribution using a more modern JavaScript.
Specifically, for CSS Stylesheet that are not inline – since that is already covered from the original question, somehow.
First of all, notice that we still don't have Constructable Stylesheet Objects. However, we hope to have them landed soon.
In the meantime, assuming the following HTML content:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link id="theme" rel="stylesheet" type="text/css" href="./index.css" />
<script src="./index.js"></script>
</head>
<body>
<p>Hello World</p>
<button onclick="reload('theme')">Reload</button>
</body>
</html>
We could have, in index.js:
// Utility function to generate a promise that is
// resolved when the `target` resource is loaded,
// and rejected if it fails to load.
//
const load = target =>
new Promise((rs, rj) => {
target.addEventListener("load", rs, { once: true });
target.addEventListener(
"error",
rj.bind(null, `Can't load ${target.href}`),
{ once: true }
);
});
// Here the reload function called by the button.
// It takes an `id` of the stylesheet that needs to be reloaded
async function reload(id) {
const link = document.getElementById(id);
if (!link || !link.href) {
throw new Error(`Can't reload '${id}', element or href attribute missing.`);
}
// Here the relevant part.
// We're fetching the stylesheet from the server, specifying `reload`
// as cache setting, since that is our intention.
// With `reload`, the browser fetches the resource *without* first looking
// in the cache, but then will update the cache with the downloaded resource.
// So any other pages that request the same file and hit the cache first,
// will use the updated version instead of the old ones.
let response = await fetch(link.href, { cache: "reload" });
// Once we fetched the stylesheet and replaced in the cache,
// We want also to replace it in the document, so we're
// creating a URL from the response's blob:
let url = await URL.createObjectURL(await response.blob());
// Then, we create another `<link>` element to display the updated style,
// linked to the original one; but only if we didn't create previously:
let updated = document.querySelector(`[data-link-id=${id}]`);
if (!updated) {
updated = document.createElement("link");
updated.rel = "stylesheet";
updated.type = "text/css";
updated.dataset.linkId = id;
link.parentElement.insertBefore(updated, link);
// At this point we disable the original stylesheet,
// so it won't be applied to the document anymore.
link.disabled = true;
}
// We set the new <link> href...
updated.href = url;
// ...Waiting that is loaded...
await load(updated);
// ...and finally tell to the browser that we don't need
// the blob's URL anymore, so it can be released.
URL.revokeObjectURL(url);
}
i now have this:
function swapStyleSheet() {
var old = $('#pagestyle').attr('href');
var newCss = $('#changeCss').attr('href');
var sheet = newCss +Math.random(0,10);
$('#pagestyle').attr('href',sheet);
$('#profile').attr('href',old);
}
$("#changeCss").on("click", function(event) {
swapStyleSheet();
} );
make any element in your page with id changeCss with a href attribute with the new css url in it. and a link element with the starting css:
<link id="pagestyle" rel="stylesheet" type="text/css" href="css1.css?t=" />
<img src="click.jpg" id="changeCss" href="css2.css?t=">
Another answer:
There's a bookmarklet called ReCSS. I haven't used it extensively, but seems to work.
There's a bookmarklet on that page to drag and drop onto your address bar (Can't seem to make one here). In case that's broke, here's the code:
javascript:void(function()%7Bvar%20i,a,s;a=document.getElementsByTagName('link');for(i=0;i%3Ca.length;i++)%7Bs=a[i];if(s.rel.toLowerCase().indexOf('stylesheet')%3E=0&&s.href)%20%7Bvar%20h=s.href.replace(/(&%7C%5C?)forceReload=%5Cd%20/,'');s.href=h%20(h.indexOf('?')%3E=0?'&':'?')%20'forceReload='%20(new%20Date().valueOf())%7D%7D%7D)();
simple if u are using php
Just append the current time at the end of the css like
<link href="css/name.css?<?php echo
time(); ?>" rel="stylesheet">
So now everytime u reload whatever it is , the time changes and browser thinks its a different file since the last bit keeps changing.... U can do this for any file u force the browser to always refresh using whatever scripting language u want
In a simple manner you can use rel="preload" instead of rel="stylesheet" .
<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">
Based on https://stackoverflow.com/a/59176853/3917091 on this page
function refreshStylesheets() {
// In my case, I'm getting all urls on my site (mysite.dev).
(document.querySelectorAll('link[rel="stylesheet"][href*="mysite.dev\/"],link[rel="stylesheet"][data-href*="mysite.dev\/"]') || []).forEach(async link => {
// Reload the file, by data-href first if it's available, otherwise use href
const reload = await fetch(link.dataset.href || link.href, { cache: "reload" }),
// Generate url
url = URL.createObjectURL(await reload.blob());
// preserve real url
if (!link.dataset.href) link.dataset.href = link.href;
link.href = url.toString();
});
}
The advantage this has, over appending to the url, is that this actually removes it from the browser cache. Using other scripts works great, but when you refresh the page, it reverts to what it had cached. Minor annoyance. However, this does not revert upon refresh.
It's a nice way to quickly change css for testing without ctrl F5 refresh all of the time, and then you roll out the change by server-side updating the filename or the query string on the style sheet as normal.
The data-href 'preserving' is important, or the permanency of refreshing on your cache only works once per page-view.
The same sort of script can be written for script[src] but I would not advise that, because you may end up with all kinds of bugs with certain things being done twice, like event listeners.
Yes, reload the css tag. And remember to make the new url unique (usually by appending a random query parameter). I have code to do this but not with me right now. Will edit later...
edit: too late... harto and nickf beat me to it ;-)

How to insert external stylesheet in JavaScript (dynamically)

...with right path.
For example. I have script called foo.js. I'd like to insert stylesheet declaration which I can do with following instruction:
$('head').append('<link rel="stylesheet" href="/template/foo.css" type="text/css" />');
Problem: I have to put full path to the stylesheet file. So instead of /template/foo.css I have to put: http://hostname/directory/template/foo.css. I can't set it statically beacause script can be placed in different servers and different locations. So it can be: http://foo.com/bar/foo.css or http://foo.com/foo.css.
It would be very useful if I can get path of foo.js file on the server. That would be good enough beacause then I could set stylesheet location based on the javascrpt's file.
I've always done:
$('body').append('<link rel="stylesheet" href="/template/foo.css" type="text/css" />');
instead of head
Ahh... sorry I just realised what your problem is. One strategy is to extract the path of the script from the DOM itself:
$('script').each(function(i,el){
var path = el.src.match(/^(.+)\/foo.js$/);
if (path) {
$('body').append('<link rel="stylesheet" ' +
'href="' + path[1] + '/foo.css" ' +
'type="text/css" />'
);
}
})
This is a common technique that I use to get the current script url:
var scriptUrl = (function() {
var scripts = document.getElementsByTagName('script'),
script = scripts[scripts.length - 1];
return script.src;
})();
It works basically because when the script is being executed, it is the last script tag on the DOM.
You can use window.location and obtain the path from that. For example for this page it is:
>>> window.location
http://stackoverflow.com/questions/2033742/how-to-insert-external-stylesheet-in-javascript-dynamically

Categories