Removing or replacing a stylesheet (a <link>) with JavaScript/jQuery - javascript

How can I do this?
I tried
$('link[title="mystyle"]').remove();
and although the element is removed, the styles are still applied to the current page (in both Opera and Firefox).
Is there any other way?

To cater for ie you have to set the stylesheet to be disabled as it keeps the css styles in memory so removing the element will not work, it can also cause it to crash in some instances if I remember correctly.
This also works for cross browser.
e.g
document.styleSheets[0].disabled = true;
//so in your case using jquery try
$('link[title=mystyle]')[0].disabled=true;

I managed to do it with:
$('link[title="mystyle"]').attr('disabled', 'disabled');
it seems this is the only way to remove the styles from memory.
then I added:
$('link[title="mystyle"]').remove();
to remove the element too.

To disable your selected stylesheet:
$('link[title="mystyle"]').prop('disabled', true);
If you never want that stylesheet to be applied again, you can then .remove() it. But don’t do that if you want to be able to re-enable it later.
To re-enable the stylesheet, do this (as long as you didn’t remove the stylesheet’s element):
$('link[title="mystyle"]').prop('disabled', false);
In the code above, it is important to use .prop, not .attr. If you use .attr, the code will work in some browsers, but not Firefox. This is because, according to MDN, disabled is a property of the HTMLLinkElement DOM object, but not an attribute of the link HTML element. Using disabled as an HTML attribute is nonstandard.

no jQuery solution
if you can add id to your link tag
<link rel="stylesheet" href="css/animations.css" id="styles-animations">
document.getElementById("styles-animations").disabled = true;
if you know index position of your css file in document
document.styleSheets[0].disabled = true; // first
document.styleSheets[document.styleSheets.length - 1].disabled = true; // last
if you want to disable style by name you can use this function
/**
* #param [string] [styleName] [filename with suffix e.g. "style.css"]
* #param [boolean] [disabled] [true disables style]
*/
var disableStyle = function(styleName, disabled) {
var styles = document.styleSheets;
var href = "";
for (var i = 0; i < styles.length; i++) {
href = styles[i].href.split("/");
href = href[href.length - 1];
if (href === styleName) {
styles[i].disabled = disabled;
break;
}
}
};
note: make sure style file name is unique so you don't have "dir1/style.css" and "dir2/style.css". In that case it would disable only first style.

Using pure javascript:
var stylesheet = document.getElementById('stylesheetID');
stylesheet.parentNode.removeChild(stylesheet);

To remove a stylesheet:
$('link[src="<path>"]').remove();
To Replace a stylesheet:
$('link[src="<path>"]').attr('src','<NEW_FILE_PATH>');

If you want to do it only with the href attribute:
$('link[href="https://example.com/mycss.css"]').remove()

ES6 solution:
const disableStyle = styleName => {
const styles = document.styleSheets;
let href = "";
for (let i = 0; i < styles.length; i++) {
if (!styles[i].href) {
continue;
}
href = styles[i].href.split("/");
href = href[href.length - 1];
if (href === styleName) {
styles[i].disabled = true;
break;
}
}
};
Use it like disableStyle("MyUnwantedFile.css");.

Here's both an add & remove using the disabling principle mentioned in a number of these other posts to prevent cross browser issues. Note how my add checks to see if the sheet already exists, in which case it just enables it. Also, in contrast to some answers, this is designed to work using the url to a .css file as the sole argument to the functions (insulating the client from the use of id or title attributes).
function element( id ){ return document.getElementById( id ); }
function addStyleSheet( url ){
var id = _styleSheetUrlToId( url );
if( !_enableStyleSheet( id ) ) {
var link = document.createElement("link");
link.href = url;
link.type = "text/css";
link.rel = "stylesheet";
link.id = id;
document.getElementsByTagName("head")[0].appendChild( link );
}
}
function removeStyleSheet( url )
{ _enableStyleSheet( _styleSheetUrlToId( url ), false ); }
// "protected" function
function _styleSheetUrlToId( url ){
var urlParts = url.split("/");
return urlParts[urlParts.length-1].split(".")[0]
+ "-style";
}
// "protected" function
// returns if the sheet was found
function _enableStyleSheet( id, enable ) {
if( typeof(enable) == "undefined" ) enable = true;
var sheet = element( id );
if( sheet ) {
sheet.disabled = !enable;
return true;
}
return false;
}

Related

How to add alt and title attributes along with image in quill editor

var range = this.quill.getSelection();
var value = prompt('please copy paste the image url here.');
if(value){
this.quill.insertEmbed(range.index, 'image', value, Quill.sources.USER);
}
I solved the problem of adding images by linking in the quill editor with the api code above. But I couldn't find how to add alt and title properties with the help of api. I can edit it later with the following javascript code, but I need to edit it at the image insertion stage.
if (e.target.tagName=='IMG') {
console.log(e.target.tagName)
var el = e.target;
el.setAttribute("title", "asdasdasd");
}
})
Also, when I add a or tag to the editor, it is surrounded by a p tag and cannot be edited. It puts everything in the p tag and doesn't allow tags like br. How can I solve these problems?
Sorry for the bad english.
There seems to be no easy and elegant way to do it. The API does not allow it (or I have not seen it) and the source code does not seem to be documented.
I propose this code while waiting for a better solution.
It is based on a solution to observe dynamically created elements. I have added the caption of the title and alt attribute.
To get the code to work, you will need to explain the following to your users:
They must write the title and alt in this format wherever they want to insert the image:
%title% A title %alt% An alternative text
Then, they must select that same:
%title% A title %alt% An alternative text
With that text selected they must click the image button and open the image.
Notice, at the moment, you cannot escape "%alt%", so you cannot use the "%alt%" expression within the value of an attribute.
Example:
%title% The title is before %alt% %alt% the %alt% attribute
This causes an unwanted alt attribute.
Paste this code after creating an editor.
BTW, it is only valid for the first editor that exists.
var FER_alt;
var FER_title;
function FER_callback(records) {
records.forEach(function (record) {
var list = record.addedNodes;
var i = list.length - 1;
for ( ; i > -1; i-- ) {
if (list[i].nodeName === 'IMG') {
if(FER_title.length > 0){
list[i].setAttribute('title',FER_title)
}
if(FER_title.length > 0){
list[i].setAttribute('alt',FER_alt)
}
}
}
});
}
var FER_observer = new MutationObserver(FER_callback);
var FER_targetNode = document.querySelector('.ql-editor')
FER_observer.observe(FER_targetNode, {
childList: true,
subtree: true
});
function FER_getTitleAlt(){
var selection = quill.getSelection();
var texto =quill.getText(selection.index,selection.length);
var titleE = texto.search("%alt%")
FER_title = texto.substr(7,titleE-7);
var titleI = titleE + 5
FER_alt = texto.substring(titleI)
}
var FER_imageboton = document.querySelector(".ql-image")
FER_imageboton.addEventListener("click",FER_getTitleAlt)
Instead of insertEmbed you can use getContents and setContents.
let delta = {
ops: [
{
attributes: {
alt: yourAltValue
},
insert: {
image: yourSrcValue
}
}]
};
let existingDelta = this.quill.getContents();
let combinedDelta = existingDelta.concat(delta);
this.quill.setContents(combinedDelta);
Extends Image blot and override the create method
const Image = Quill.import('formats/image');
class ImageBlot extends Image {
static create(value) {
const node = super.create(value);
if (typeof value === 'string') {
node.setAttribute('src', this.sanitize(value));
node.setAttribute('alt', this.sanitize(value).split('/').reverse()[0]);
}
return node;
}
}
Quill.register(ImageBlot);
In this example, we set alt attribute with image's basename

enable disable stylesheet using javascript in chrome

Rephrase of question: What is the best way to provide alternate stylesheets for a document?
I have a list of stylesheets, all of which are referenced in the html file.
I use javascript to disable all but one file.
example:
style1 disabled = false
style2 disabled = true
In practice, the last stylesheet to load (style2) is the active one, regardless of the disabled property.
How can I alternate between stylesheets on a document in chrome?
I tried to set the value of href attribute, but it seems to be read only.
example of code I have been using: (I am using an object called MenuStyles that is storing various css information)
function setActiveStyleSheet(name) {
var selectedSheet;
var currentSheet;
for (var i = 0; i < MenuStyles.styleSheets.length; i++) {
currentSheet = MenuStyles.styleSheets[i];
if (currentSheet.name === name) {
selectedSheet = currentSheet.sheetObj;
currentSheet.disabled = false;
} else {
currentSheet.disabled = true;
}
}
return selectedSheet;
}
EDIT: it turns out the problem was due entirely to bugs in the code. disabled property works fine. below is the fixed function:
function setActiveStyleSheet(name) {
var selectedSheet;
var currentSheet;
for (var i = 0; i < MenuStyles.styleSheets.length; i++) {
currentSheet = MenuStyles.styleSheets[i];
if (currentSheet.name === name) {
selectedSheet = currentSheet.sheetObj;
currentSheet.sheetObj.disabled = false;
} else {
currentSheet.sheetObj.disabled = true;
}
}
return selectedSheet;
}
In general you'd subclass off the BODY tag and use a single stylesheet that uses these classes. Then just swap the BODY class, not the sylesheet. Otherwise, you should be doing this server-side.
<body class="sheet1">
then
sheet1.h1 {
...
}
sheet2.h1 {
...
}
If you know the order of your stylesheets you can use-
document.styleSheets[i].disabled=true or
document.styleSheets[i].disabled=false;
If you have 2 stylesheets you can toggle between them with-
var S=document.styleSheets;
if(S[0].disabled){
S[0].disabled=false;
S[1].disabled=true;
}
else{
S[1].disabled=false;
S[0].disabled=true;
}
Current browsers offer reasonable ability to dynamically enable/disable stylesheets through the use of either the 'disabled' DOM property (Gecko) or by adding/removing the disabled attribute (Webkit and IE).
Unfortunately, these approaches only reliably work on 'link' tags that reference an external stylesheet (not 'style' tags), unless you are using IE10+. Yes - I said that - only IE does the right thing here.
For inline CSS using 'style' tags on non-IE browsers, you need to find a more crude way to enable/disable like those discussed above (remove the style element, etc).
I was able to get this to work with setting the disabled property and by including a 'title' attribute the stylesheets.
title property makes the stylesheet PREFERRED rather than PERSISTENT. see http://www.alistapart.com/articles/alternate/
I've found a great way (IMHO) to achieve this:
Let's suppose you know the exactly order of your stylesheet. Let's say you want to alternate stylesheet 0 and 1 (first and second):
To get a stylesheet state (enabled/disabled) you can try this (i.e. testing the second one):
document.styleSheets[1].disabled
...and it returns trueor false.
So to alternate you can write this code in an onclick event:
document.styleSheets[0].disabled = !(
document.styleSheets[1].disabled = !(document.styleSheets[1].disabled)
);
HTH!
For me if the link is disabled, document.styleSheets does not return the link in the collection ( in Chrome) . Only the enabled links are returned.
I use document.head.getElementsByTagName('LINK'), to get them all, out of HEAD.
Like:
private changeStyle(styleName: string): void {
const links = document.head.getElementsByTagName('LINK');
for (let i = 0; i < links.length; i++) {
const link = links[i] as any;
if( !link.href) continue;
if (link.href.indexOf(styleName) === -1) {
link.disabled = true;
} else {
link.disabled = false;
}
}
}

Class of ID Change based on URL - URL Based Image Swap -

What I'm trying to achieve:
Based on URL (ie., foo.com/item1), the div element "logoswap" receives a different class.
The following is the code I put together but it seems completely wrong. I'm not a JS pro by any means, XHTML/CSS is more my speed (some PHP)... I cannot use PHP, even if it is possible in PHP (and I know it is because I have a PHP version of what I need done already, but I can't call the PHP properly.
I'm really just trying to get a different logo to show up based on the directory/url... It doesn't have to be a background element called in by the CSS class necessarily, I just need a different image to load based on the aforementioned url variable...
$(function() {
var url = location.pathname;
if(url.indexOf('item1') > -1) {
document.getElementById("logoswap").className += " class1";
}
elseif(url.indexOf('item2') > -1) {
document.getElementById("logoswap").className += "class2";
}
elseif(url.indexOf('item3') > -1) {
document.getElementById("logoswap").className += "class3";
}
elseif(url.indexOf('item4') > -1) {
document.getElementById("logoswap").className += "class4";
}
elseif(url.indexOf('item5') > -1) {
document.getElementById("logoswap").className += "class5";
}
else {
document.getElementById("logoswap").className += "class1";
}
});
That's what I have... Ugly I'm sure.
That's why I'm here though, I definitely need some help.
Assigning CSS Class By URL Pathname
A jsfiddle has been setup for
this solution.
Here is a case for using numeric expressions if they are available. This does not apply to the above question.
$(function() {
var rgx = /item(\d+)$/,
url = location.pathname,
id = (rgx.test(url)) ? url.match(rgx)[1] : '1';
$("#logoswap").addClass("class" + id);
});
UPDATE:
In light of the new details you may need an array of values, these should be derived from or exactly equal to the class names you intend to use.
$(function(){
// my favorite way to make string arrays.
var matches = "brand1 brand2 brand3".split(" "),
url = location.pathname.match(/\w+$/)[0], // get the last item
id = matches.indexOf(url),
className = matches[(id > -1) ? id : 0];
$("#logoswap").addClass(className);
});
To make this work you will need a few things in place. I will assume that the paths will end in a number as we have outlined here. The default ends with 1. You will need the images to be accessible. You need to define the styles for each possibility.
CSS Setup
#logoswap {
height : 200px;
width : 200px;
}
.class1 {
background-image : url(/path/to/default.jpg);
}
.class2 {
background-image : url(/path/to/second.jpg);
}
.brand1 {
background-image : url(/path/to/brand/1/logo.jpg);
}
...
Without jQuery
if you do not have jQuery in your code you may need to use window.onload.
(function(){
var old = window.onload;
window.onload = function(){
old();
var r = /item(\d+)$/,
url = location.pathname,
id = (r.test(url)) ? url.match(r)[1] : '1';
document.getElementById('logoswap').className += "class" + id;
};
})()
I just want to take a moment here to
encourage anyone who is doing this
type of code to get used to Regular
Expressions and learn them. They are
far and away the most frequently used
cross language part of my development
arsenal.
There's nothing that wrong with what you have. You could tidy it up with something like below.
$(function() {
var url = location.pathname;
var logo = document.getElementById("logoswap");
var i = 6;
logo.className = "class1";
while(i--)
{
if(url.indexOf("item" + i) > -1) {
logo.className = "class" + i;
}
}
});
Hope this helps.
Using just HTML/CSS, you could add (or append via javascript) an id to the body of the page:
<body id="item1">
Then in your CSS, create a selector:
#item1 #logoswap {
// class1 CSS
}

How to use Javascript to check and load CSS if not loaded?

I need to check (in Javascript) if a CSS file is loaded and if not then to load it. jQuery is fine.
Just check to see if a <link> element exists with the href attribute set to your CSS file's URL:
if (!$("link[href='/path/to.css']").length)
$('<link href="/path/to.css" rel="stylesheet">').appendTo("head");
The plain ol' JS method is simple too, using the document.styleSheets collection:
function loadCSSIfNotAlreadyLoadedForSomeReason () {
var ss = document.styleSheets;
for (var i = 0, max = ss.length; i < max; i++) {
if (ss[i].href == "/path/to.css")
return;
}
var link = document.createElement("link");
link.rel = "stylesheet";
link.href = "/path/to.css";
document.getElementsByTagName("head")[0].appendChild(link);
}
loadCSSIfNotAlreadyLoadedForSomeReason();
I just had to write something like that and I wanted to share it. This one is prepared for multiple cases.
If there is no request for the css file (css file isn't linked ...)
If there is a request for the css file, but if it failed (css file is no longer available ...)
var styles = document.styleSheets;
for (var i = 0; i < styles.length; i++) {
// checking if there is a request for template.css
if (styles[i].href.match("template")) {
console.log("(Iteration: " + i + ") Request for template.css is found.");
// checking if the request is not successful
// when it is successful .cssRules property is set to null
if (styles[i].cssRules != null && styles[i].cssRules.length == 0) {
console.log("(Iteration: " + i + ") Request for template.css failed.");
// fallback, make your modification
// since the request failed, we don't need to iterate through other stylesheets
break;
} else {
console.log("(Iteration: " + i + ") Request for template.css is successful.");
// template.css is loaded successfully, we don't need to iterate through other stylesheets
break;
}
}
// if there isn't a request, we fallback
// but we need to fallback when the iteration is done
// because we don't want to apply the fallback each iteration
// it's not like our css file is the first css to be loaded
else if (i == styles.length-1) {
console.log("(Iteration: " + i + ") There is no request for template.css.");
// fallback, make your modification
}
}
TL;DR version
var styles = document.styleSheets;
for (var i = 0; i < styles.length; i++) {
if (styles[i].href.match("css-file-name-here")) {
if (styles[i].cssRules != null && styles[i].cssRules.length == 0) {
// request for css file failed, make modification
break;
}
} else if (i == styles.length-1) {
// there is no request for the css file, make modification
}
}
Update: Since my answer got a few upvotes and this led me to revise the code, I decided to update it.
// document.styleSheets holds the style sheets from LINK and STYLE elements
for (var i = 0; i < document.styleSheets.length; i++) {
// Checking if there is a request for the css file
// We iterate the style sheets with href attribute that are created from LINK elements
// STYLE elements don't have href attribute, so we ignore them
// We also check if the href contains the css file name
if (document.styleSheets[i].href && document.styleSheets[i].href.match("/template.css")) {
console.log("There is a request for the css file.");
// Checking if the request is unsuccessful
// There is a request for the css file, but is it loaded?
// If it is, the length of styleSheets.cssRules should be greater than 0
// styleSheets.cssRules contains all of the rules in the css file
// E.g. b { color: red; } that's a rule
if (document.styleSheets[i].cssRules.length == 0) {
// There is no rule in styleSheets.cssRules, this suggests two things
// Either the browser couldn't load the css file, that the request failed
// or the css file is empty. Browser might have loaded the css file,
// but if it's empty, .cssRules will be empty. I couldn't find a way to
// detect if the request for the css file failed or if the css file is empty
console.log("Request for the css file failed.");
// There is a request for the css file, but it failed. Fallback
// We don't need to check other sheets, so we break;
break;
} else {
// If styleSheets.cssRules.length is not 0 (>0), this means
// rules from css file is loaded and the request is successful
console.log("Request for the css file is successful.");
break;
}
}
// If there isn't a request for the css file, we fallback
// But only when the iteration is done
// Because we don't want to apply the fallback at each iteration
else if (i == document.styleSheets.length - 1) {
// Fallback
console.log("There is no request for the css file.");
}
}
TL;DR
for (var i = 0; i < document.styleSheets.length; i++) {
if (document.styleSheets[i].href && document.styleSheets[i].href.match("/template.css")) {
if (document.styleSheets[i].cssRules.length == 0) {
// Fallback. There is a request for the css file, but it failed.
break;
}
} else if (i == document.styleSheets.length - 1) {
// Fallback. There is no request for the css file.
}
}
Something like this will do (using jQuery):
function checkStyleSheet(url){
var found = false;
for(var i = 0; i < document.styleSheets.length; i++){
if(document.styleSheets[i].href==url){
found=true;
break;
}
}
if(!found){
$('head').append(
$('<link rel="stylesheet" type="text/css" href="' + url + '" />')
);
}
}
Peer to the comment made by JFK about the accepted answer:
I understood the question as "how to check whether a css file is
loaded or not" rather than "how to check if the element
exists".
The element may exist (and the path may be correct too) but it
doesn't mean that the css file was successful loaded.
If you access a link Element via getElementById you'll not be able to check/read the style defined inside the CSS file.
In order to check if a style has been successfully loaded we have to use getComputedStyle (or currentStyle for IE).
HTML
//somewhere in your html document
<div id="css_anchor"></div>
CSS
//somewhere in your main stylesheet
#css_anchor{display:none;}
JAVASCRIPT
//js function to check the computed value of a style element
function get_computed_style(id, name){
var element = document.getElementById(id);
return element.currentStyle ? element.currentStyle[name] : window.getComputedStyle ? window.getComputedStyle(element, null).getPropertyValue(name) : null;
}
//on document ready check if #css_anchor has been loaded
$(document).ready( function() {
if(get_computed_style('css_anchor', 'display')!='none'){
//if #css_anchor style doesn't exist append an alternate stylesheet
var alternateCssUrl = 'http://example.com/my_alternate_stylesheet.css';
var stylesheet = document.createElement('link');
stylesheet.href = alternateCssUrl;
stylesheet.rel = 'stylesheet';
stylesheet.type = 'text/css';
document.getElementsByTagName('head')[0].appendChild(stylesheet);
}
});
Part of the answer comes from: myDiv.style.display returns blank when set in master stylesheet
Demo here: http://jsfiddle.net/R9F7R/
Apart from all the nice answers above, you can simply put a dummy element inside your markup and in your css file, give it any style other than default. Then in the code check if the attribute is applied to the dummy element, and if not, load the css. Just a thought though, not a neat way to do that thing you want done.
My 2 cents. This checks whether there are any rules set on the css or not, meaning that it was or not successfully loaded
if(jQuery("link[href='/style.css']").prop('sheet').cssRules.length == 0){
//Load the css you want
}
The document object contains a stylesheet collection with all the loaded stylesheets.
For a reference see http://www.javascriptkit.com/domref/stylesheet.shtml
You can loop this collection to verify that the stylesheet you want to verify is in it and thus loaded by the browser.
document.styleSheets[0] //access the first external style sheet on the page
There are some browser incompatibilities you should look out for though.
One way: use document.getElementsByTagName("link") iterate over each and check if its href is equal to the CSS file you check.
Another way: if you know some CSS rule being set only in that file, check if this rule really apply e.g. check if background of something is really red.
You can either check if the filename is within your markup, like:
var lnks = document.getElementsByTagName('link'),
loadcss = true;
for(var link in lnks) {
href = link.getAttribute('href');
if( href.indexOf('foooobar.css') > -1) ){
loadcss = false;
return false;
}
});
if( loadcss ) {
var lnk = document.createElement('link'),
head = document.getElementsByTagName('head')[0] || document.documentElement;
lnk.rel = 'stylesheet';
lnk.type = 'text/css';
lnk.href = '//' + location.host + 'foooobar.css';
head.insertBefore(lnk, head.firstChild);
}
or you could check for a specific className which should be available, if the stylesheet was loaded. This probably comes a little closer to a feature detection.
var links = document.getElementsByTagName('link');
var file = 'my/file.css';
var found = false;
for ( var i in links )
{
if ( links[i].type == 'text/css' && file == links[i].href ) {
found = true; break;
}
}
if ( !( found ) ) {
var styles = document.getElementsByTagName('style');
var regexp = new RegExp('/\#import url\("?' + file + '"?\);/');
for ( var i in styles )
{
if ( styles[i].src == file ) {
found = true; break;
} else if ( styles[i].innerHTML.match(regexp) ) {
found = true; break;
}
}
}
if ( !( found ) ) {
var elm = document.createElement('link');
elm.href = file;
document.documentElement.appendChild(elm);
}
For a nice consistent and repeatable experience, I've written these two jQuery plugins that mimic the $.getScript(url, callback) jQuery method (however they will NOT force reloading from the server like $.getScript(). There are two methods: one that will load a CSS file anytime it's called, and one that will only load it once. I find the former handy during development when I'm making changes, and the latter great for a speedy deployment.
/**
* An AJAX method to asynchronously load a CACHED CSS resource
* Note: This removes the jQuery default behaviour of forcing a refresh by means
* of appending a datestamp to the request URL. Actual caching WILL be subject to
* server/browser policies
*/
$.getCachedCss = function getCachedCss(url, callback)
{
$('<link>',{rel:'stylesheet', type:'text/css', 'href':url, media:'screen'}).appendTo('head');
if (typeof callback == 'function')
callback();
}
/**
* An AJAX method to asynchronously load a CACHED CSS resource Only ONCE.
* Note: This removes the jQuery default behaviour of forcing a refresh by means
* of appending a datestamp to the request URL. Actual caching WILL be subject to
* server/browser policies
*/
$.getCachedCssOnce = function getCachedCssOnce(url, callback)
{
if (!$("link[href='" + url + "']").length) {
$.getCachedCss(url, callback);
if (typeof callback == 'function')
callback();
}
}
Usage example:
$(function() {
$.getCachedCssOnce("pathToMyCss/main.css");
)}
Usage example with callback:
$(function() {
$.getCachedCssOnce("pathToMyCss/main.css", function() {
// Do something once the CSS is loaded
});
use .sheet in jQuery:
HTML:
<link rel="stylesheet" href="custom.css">
jQuery:
if($("link[href='custom.css']")[0].sheet.cssRules.length==0){
//custom.css was not loaded, do your backup loading here
}
simple way using javascript..,
loadCssIfNotLoaded('https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css');
loadCssIfNotLoaded('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css');
function loadCssIfNotLoaded(url) {
var element=document.querySelectorAll('link[href="' + url + '"]');
if (element.length == 0)
{
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = url;
document.getElementsByTagName("head")[0].appendChild(link);
}
}
In one line, with jQuery.
If the #witness div is visible, we have to load the css file.
In the HTML, we have a:
<div id="witness"></div>
In the CSS file to load, we have:
#witness{display:none;}
So, if the css file is loaded, the #witness div is not visible. We can check with jQuery and make decision.
!$('#witness').is(':visible') || loadCss() ;
As a snippet:
function loadCss(){
//...
console.log('Css file required');
};
!$('#witness').is(':visible') || loadCss();
#witness{display:none;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<div id="witness"></div>

HOW TO check if an external (cross-domain) CSS file is loaded using Javascript

I have a function doing the following using javascript:
Create link element and set href=cssFile.
Insert the link element in head tag.
Create a div element.
Set the class name using setAttribute
appendChild the div on body.
Now getting CSS rule value using document.defaultView.getComputedStyle(divElement, null)[cssRule].
Now getComputedStyle is returning the default values, and if I wait on breakpoint using Firebug before getComputedStyle call, then it returns the CSS rule from the CSS injected.
Regards,
Munim
You can create the dynamic css url and fetch the css as plain text using a normal ajax call.
Then use this to load the css:
function loadCss(cssText, callback){
var style = document.createElement('style');
style.type='text/css';
if(callBack != undefined){
style.onload = function(){
callBack();
};
}
style.innerHTML = cssText;
head.appendChild(style);
}
And use it like this:
loadCss(ajaxResponseText, function(){
console.log("yaay css loaded, now i can access css defs");
})
This is actually what I did.
To ensure a specific CSS file is loaded, I added a style in the end of the CSS file. For example:
#ensure-cssload-8473649 {
display: none
}
Now I have a JavaScript function which will fire the callback specified when the above style is loaded on the page:
var onCssLoad = function (options, callback) {
var body = $("body");
var div = document.createElement(constants.TAG_DIV);
for (var key in options) {
if (options.hasOwnProperty(key)) {
if (key.toLowerCase() === "css") {
continue;
}
div[key] = options[key];
}
}
var css = options.css;
if (css) {
body.appendChild(div);
var handle = -1;
handle = window.setInterval(function () {
var match = true;
for (var key in css) {
if (css.hasOwnProperty(key)) {
match = match && utils.getStyle(div, key) === css[key];
}
}
if (match === true) {
window.clearTimeout(handle);
body.removeChild(div);
callback();
}
}, 100);
}
}
And this is how I used the function above:
onCssLoad({
"id": "ensure-cssload-8473649",
css: {
display: "none"
}
}, function () {
// code when you want to execute
// after your CSS file is loaded
});
Here the 1st parameter takes the options where id is to check against the test style and css property to verify against what loaded from the CSS.
I assume you are doing this because you need to dynamically create the URL of the stylesheet.
Couple options come to mind:
1) Create the URL server-side and avoid this problem altogether.
2) Use a setTimeout to check whether or not the style has been loaded and check every 20ms or so until getComputedStyle returns the value you want.
I don't like #2 at all...but it's an option. If you use #2 make sure to clear the timeout even if there is an exception.
Here is a solution that seems to work across all browsers.
function loadCss(fileUrl) {
// check for css file type
if (fileUrl.indexOf(".css")==fileUrl.length-4) {
// Create link element
var fileref=document.createElement("link");
fileref.setAttribute("rel", "stylesheet");
fileref.setAttribute("type", "text/css");
fileref.setAttribute("href", fileUrl);
if (typeof fileref!="undefined") {
// remove the . if this is a relative link
if(fileUrl.indexOf('.')==0) {
fileUrl = fileUrl.substr(1);
}
// generate the full URL to use as the fileId
var pathname = window.location.pathname;
var pathUrl = pathname.substr(0,pathname.lastIndexOf("/"));
var fileId = window.location.protocol + "//" + window.location.host + pathUrl + fileUrl;
// append the newly created link tag to the head of the document
document.getElementsByTagName("head")[0].appendChild(fileref);
// begin checking for completion (100ms intervals up to 2000ms)
this.checkCSSLoaded(fileId,100,0,2000);
} else throw 'INVALID_CSS_ERROR';
} else throw 'INVALID_CSS_ERROR';
}
function checkCSSLoaded(cssHref,milliPerCheck,milliPerCount,milliTimeout) {
// Look through all sheets and try to find the cssHref
var atSheet = -1;
var sheetLength = document.styleSheets.length;
while(++atSheet < sheetLength ) {
if(cssHref == document.styleSheets[atSheet].href) {
// If found dispatch and event or call a procedure
/* Do whatever is next in your code here */
return;
}
}
// check for timeout
if(milliCount > milliTimeout) {
alert('INVALID_CSS_ERROR::'+" ("+cssHref+"+ not found!");
/* Do whatever happens if timeout is reached here */
return;
}
// else keep trying
setTimeout(checkCSSLoaded ,milliPerCheck, cssHref, milliPerCheck, milliCount+millPerCheck, milliTimeout);
}
Essentially we
Create a link tag.
Set its attributes so it knows its a stylesheet link tag
Create a file id in such a way that it will always be the full file URL
Append the link tag to the head of the document head
Perform consecutive tests to see if (stylesheet.href == fileID) comes into existence
If found do something else if timeout do something else keep checking
Using document.styleSheets to check if a css is loaded is wrong, since as soon as a css link is being added to the DOM, it will be available from document.styleSheets, even if it is not loaded yet.
Adding a marker to CSS is hacky too.
The correct solution is to listen to the onload event :
var loadedCss = {};
cssHref = "http://www.foo.com/bar.css";
css = document.createElement("link");
css.setAttribute("rel", "stylesheet");
css.setAttribute("type", "text/css");
css.setAttribute("href", cssHref);
css.onload = function(){
loadedCss[cssHref] = true;
}
document.getElementsByTagName("head")[0].appendChild(css);
function isCssLoaded(url) {
return loadCss[url];
}

Categories

Resources