Iframe enter fullscreen mode - javascript

I need to make iframe enter fullscreen mode,
i am using iframe to display pdf file by google docs viewer
i need this iframe to enter fullscreen.
I have found an code in the internet for displaying html video and iframe and there full screen but when i try to remove the video, the fullscreen never work
In this code the iframe (fullscreen) not working
<!DOCTYPE HTML>
<link rel="stylesheet" type="text/css" href="_styles.css" media="screen">
<title>Fullscreen API | The CSS Ninja</title>
<div class="fl">
<iframe src="http://thecssninja.com/talks/dnd_and_friends/" width="320" height="240" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe><br />
<button id="fullscreeniframe" class="button">Fullscreen iframe</button>
</div>
<script>
(function(window, document){
var $ = function(selector,context){return(context||document).querySelector(selector)};
var video = $("video"),
iframe = $("iframe"),
domPrefixes = 'Webkit Moz O ms Khtml'.split(' ');
var fullscreen = function(elem) {
var prefix;
// Mozilla and webkit intialise fullscreen slightly differently
for ( var i = -1, len = domPrefixes.length; ++i < len; ) {
prefix = domPrefixes[i].toLowerCase();
if ( elem[prefix + 'EnterFullScreen'] ) {
// Webkit uses EnterFullScreen for video
return prefix + 'EnterFullScreen';
break;
} else if( elem[prefix + 'RequestFullScreen'] ) {
// Mozilla uses RequestFullScreen for all elements and webkit uses it for non video elements
return prefix + 'RequestFullScreen';
break;
}
}
return false;
};
// Will return fullscreen method as a string if supported e.g. "mozRequestFullScreen" || false;
var fullscreenvideo = fullscreen(document.createElement("video"));
// Webkit uses "requestFullScreen" for non video elements
var fullscreenother = fullscreen(document.createElement("iframe"));
if(!fullscreen) {
alert("Fullscreen won't work, please make sure you're using a browser that supports it and you have enabled the feature");
return;
}
// Should add prefixed events for potential ms/o or unprefixed support too
video.addEventListener("webkitfullscreenchange",function(){
console.log(document.webkitIsFullScreen);
}, false);
video.addEventListener("mozfullscreenchange",function(){
console.log(document.mozFullScreen);
}, false);
$("#fullscreenvid").addEventListener("click", function(){
// The test returns a string so we can easily call it on a click event
video[fullscreenvideo]();
}, false);
$("#fullscreeniframe").addEventListener("click", function(){
// iframe fullscreen and non video elements in webkit use request over enter
iframe[fullscreenother]();
}, false);
})(this, this.document);
</script>
http://www.thecssninja.com/demo/fullscreen/

I've removed video references, try that:
(function(window, document){
var $ = function(selector,context){return(context||document).querySelector(selector)};
var iframe = $("iframe"),
domPrefixes = 'Webkit Moz O ms Khtml'.split(' ');
var fullscreen = function(elem) {
var prefix;
// Mozilla and webkit intialise fullscreen slightly differently
for ( var i = -1, len = domPrefixes.length; ++i < len; ) {
prefix = domPrefixes[i].toLowerCase();
if ( elem[prefix + 'EnterFullScreen'] ) {
// Webkit uses EnterFullScreen for video
return prefix + 'EnterFullScreen';
break;
} else if( elem[prefix + 'RequestFullScreen'] ) {
// Mozilla uses RequestFullScreen for all elements and webkit uses it for non video elements
return prefix + 'RequestFullScreen';
break;
}
}
return false;
};
// Webkit uses "requestFullScreen" for non video elements
var fullscreenother = fullscreen(document.createElement("iframe"));
if(!fullscreen) {
alert("Fullscreen won't work, please make sure you're using a browser that supports it and you have enabled the feature");
return;
}
$("#fullscreeniframe").addEventListener("click", function(){
// iframe fullscreen and non video elements in webkit use request over enter
iframe[fullscreenother]();
}, false);
})(this, this.document);

I have extended the solution provided by #A.Wolff , I have added a button within the Iframe
you can check the solution right here on w3
Full screen toogle with inside/internal button| W3
Regards

Related

Reading iframe content doesn't work under Chrome

I need to use a content of a .txt file on a web page. The problem is that I can't do it easy way (server-side php). I figured out the trick of opening a text file in the iframe and then asking for innerHTML/innerText. It turns out that people were there before - found the following code, much cleaner than my attempts, at https://zipcon.net/~swhite/docs/computers/browsers/extern_via_iframe.html
It works locally under FireFox and IE, but does not under Chrome. How to make it work under Chrome?
function getIframeContentText( frameID )
{
var elt = document.getElementById(frameID);
//alert( "getIframeContentText:" + elt );
//alert( "getIframeContentText Content:" + elt.contentDocument );
if( elt.contentDocument ) // DOM
{
var iframe_doc = elt.contentDocument;
var range = iframe_doc.createRange();
range.selectNodeContents( iframe_doc.body );
return range.toString();
}
else // IE6
{
var iframe_doc = document.all[frameID].contentWindow.document;
//return iframe_doc.body.innerHTML; // gets HTML
return iframe_doc.body.outerText;
}
}
This is because handling iFrames in ie and firefox is differentthan chrome ,because of chromes same-origin policy
start the browser using chrome.exe --user-data-dir="." --disable-web-security
and you have to wait for the document to load fully ie all the contents of the page ,it may happen there may be iFrame inside iFrame (for generic solution )
$(window).load(function()
{
chromeFrameInitializers(document);//for handling frames and IFrames
});
function chromeFrameInitializers(document)
{
var frame=document.getElementsByTagName("frame");
for(var i=0;i<frame.length;i++)
{
var subDocFrame=frame[i].contentDocument;
//do your stuf
chromeFrameInitializers(subDocFrame)
}
var iFrame=document.getElementsByTagName("iFrame");
for(var i=0;i<iFrame.length;i++)
{
var subDocIFrame=iFrame[i].contentDocument;
//do your stuf
chromeFrameInitializers(subDocIFrame)
}
}
`
it handles for both frame and iFrame (recursively ). for this $(window).load jquery needed

Passing Variables via URL to change source tag

I have 15 videos I need to show. Instead of creating 15 pages with each html5 video embed targeting a different video, I rather have just one page and via the URL tell the player what to load. This way I can just have 15 custom links but just one player and one html page. Need this to be supported by all browsers, iOS and Android.
Example:
www.mysite.com/videoplayer.html?v=mymovie
www.mysite.com/videoplayer.html?v=mymovie&t=13.6 - this should jump to the player playhead to a point in time.
videoplayer.html
<script>
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}
alert('Query Variable ' + variable + ' not found');
}
var videoFile = getQueryVariable("v");
var videoElement = document.getElementById("mp4source");
videoElement.setAttribute("source", videoFile + ".mp4");
</script>
<video id="mp4" controls="controls">
<source id="mp4source" src="../videos/jude.mp4" type="video/mp4" />
</video>
Main.html
<div id="menubar1">
Play Movie
Chapter 2
</div>
I'm a beginner to javascript, please be specific in your answers.
Thanks.
IMHO DOM Manipulation on the main page would be a better solution, but here it is, at least for modern browsers, from your example code.
I changed your getQueryVariable in order to be able to use it as a
boolean.
To change the current playback time, you will have to wait for the
video's metadata to be loaded, then you can set the currentTime
property (in seconds).
In order to comply the "all browsers" support you will have
to transcode your videos to ogg vorbis format, then add a source pointing to
this video file. This will do for major modern browsers.
For older browsers, you will have to add a fallback (e.g. flash player or java applet).
For the "jumping playhead" in ios, you have some tricks to do : look at this question , personally I used this code which seems to work on my ipad ios 8. Note that it will lack of autoplay if you decide to add it in the video tag.
Now, you can't get video for all browsers (e.g text-based browsers).
Live Example
Play Movie Chapter 2
Commented videoplayer.html
<video id="video" controls="controls">
<source id="mp4source" src="" type="video/mp4" />
<source id="oggSource" src="" type="video/ogg" />
</video>
<script>
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}
//returning false will help knowing if that variable exists
return false;
}
function loadVideo() {
var videoFile = getQueryVariable("v");
//if v is not set
if (!videoFile) {
alert('please choose a video file, \n maybe you came here by accident?');
//no need to go further
return;
}
//Select the sources for the mp4 and the ogg version
var mp4source = document.getElementById("mp4source");
mp4source.setAttribute("src", videoFile + ".mp4");
var oggSource = document.getElementById("oggSource");
oggSource.setAttribute("src", videoFile + ".ogv");
//if t is set
if (getQueryVariable("t")) {
//userAgent can be overridden but it may be the best way to detect ios devices
var iOS = navigator.userAgent.match(/(iPad|iPhone|iPod)/) !== null;
if (iOS) {
iOSLoadSeek();
} else {
//wait for the video meta data to be loaded
document.getElementById('video').addEventListener('loadedmetadata', function() {
//then change the time position
this.currentTime = getQueryVariable("t");
})
}
}
}
//ios load seek workaround, edited from https://gist.github.com/millermedeiros/891886
function iOSLoadSeek() {
var vid = document.getElementById('video');
if (vid.readyState !== 4) { //HAVE_ENOUGH_DATA
vid.addEventListener('canplaythrough', iosCanPlay, false);
vid.addEventListener('load', iosCanPlay, false); //add load event as well to avoid errors, sometimes 'canplaythrough' won't dispatch.
vid.addEventListener('play', iosCanPlay, false); //Actually play event seems to be faster
vid.play();
setTimeout(function() {
vid.pause(); //block play so it buffers before playing
}, 10); //it needs to be after a delay otherwise it doesn't work properly.
}
}
//called when one of the three events fires
function iosCanPlay() {
//remove all the event listeners
this.removeEventListener('canplaythrough', iosCanPlay, false);
this.removeEventListener('load', iosCanPlay, false);
this.removeEventListener('play', iosCanPlay, false);
//finally seek the desired position
this.currentTime = getQueryVariable("t");
this.play();
}
//When the page is loaded, execute
window.onload = loadVideo();
</script>

codemirror - detect and create links inside editor

I am using codemirror, configured to display javascript.
I have code like this:
...
var ref = 'http://www.example.com/test.html';
var ref2 = 'http://www.example.com/test2.html';
...
When displaying the editor it would be great if I could click on the links that might be present in the editor. The link would open the page on a different tab obviously.
is there an easy way to achieve this ?
Not really easy, but what you'd do is:
Write an overlay mode that recognizes such links. Basically, this is a mode that spits out a custom token type when it finds something that looks like a link, and null otherwise. You can use the simple mode addon to make this easier. You can use this token type's CSS class (for example "link" becomes cm-link) to style your links.
Make your editor use your overlay by calling the addOverlay method.
Register a mousedown event handler on your editor (instance.getWrapperElement().addEventListener(...)).
In this handler, check whether the event's target has the link CSS class. If it does, the user is clicking a link.
If so, use the coordsChar method, using the coordinates from your mouse event, to find the position in the document that was clicked. Extract the actual link from the document text around that position, and follow it.
(Or, even better, instead of directly interfering with the click, which might be intended to put the cursor in the link or select it, show a widget containing a regular link whenever the cursor is inside of link text.)
Here is a solution I came up with:
demo here: plunkr
code:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.css"/>
<style>
html, body { height:100%; }
.CodeMirror .cm-url { color: blue; }
</style>
</head>
<body>
<script>
var cm = CodeMirror(document.body);
cm.setValue('hover over the links below\nlink1 https://plnkr.co/edit/5m31E14HUEhSXrXtOkNJ some text\nlink2 google.com\n');
hyperlinkOverlay(cm);
function hoverWidgetOnOverlay(cm, overlayClass, widget) {
cm.addWidget({line:0, ch:0}, widget, true);
widget.style.position = 'fixed';
widget.style.zIndex=100000;
widget.style.top=widget.style.left='-1000px'; // hide it
widget.dataset.token=null;
cm.getWrapperElement().addEventListener('mousemove', e => {
let onToken=e.target.classList.contains("cm-"+overlayClass), onWidget=(e.target===widget || widget.contains(e.target));
if (onToken && e.target.innerText!==widget.dataset.token) { // entered token, show widget
var rect = e.target.getBoundingClientRect();
widget.style.left=rect.left+'px';
widget.style.top=rect.bottom+'px';
//let charCoords=cm.charCoords(cm.coordsChar({ left: e.pageX, top:e.pageY }));
//widget.style.left=(e.pageX-5)+'px';
//widget.style.top=(cm.charCoords(cm.coordsChar({ left: e.pageX, top:e.pageY })).bottom-1)+'px';
widget.dataset.token=e.target.innerText;
if (typeof widget.onShown==='function') widget.onShown();
} else if ((e.target===widget || widget.contains(e.target))) { // entered widget, call widget.onEntered
if (widget.dataset.entered==='true' && typeof widget.onEntered==='function') widget.onEntered();
widget.dataset.entered='true';
} else if (!onToken && widget.style.left!=='-1000px') { // we stepped outside
widget.style.top=widget.style.left='-1000px'; // hide it
delete widget.dataset.token;
widget.dataset.entered='false';
if (typeof widget.onHidden==='function') widget.onHidden();
}
return true;
});
}
function hyperlinkOverlay(cm) {
if (!cm) return;
const rx_word = "\" "; // Define what separates a word
function isUrl(s) {
if (!isUrl.rx_url) {
// taken from https://gist.github.com/dperini/729294
isUrl.rx_url=/^(?:(?:https?|ftp):\/\/)?(?:\S+(?::\S*)?#)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i;
// valid prefixes
isUrl.prefixes=['http:\/\/', 'https:\/\/', 'ftp:\/\/', 'www.'];
// taken from https://w3techs.com/technologies/overview/top_level_domain/all
isUrl.domains=['com','ru','net','org','de','jp','uk','br','pl','in','it','fr','au','info','nl','ir','cn','es','cz','kr','ua','ca','eu','biz','za','gr','co','ro','se','tw','mx','vn','tr','ch','hu','at','be','dk','tv','me','ar','no','us','sk','xyz','fi','id','cl','by','nz','il','ie','pt','kz','io','my','lt','hk','cc','sg','edu','pk','su','bg','th','top','lv','hr','pe','club','rs','ae','az','si','ph','pro','ng','tk','ee','asia','mobi'];
}
if (!isUrl.rx_url.test(s)) return false;
for (let i=0; i<isUrl.prefixes.length; i++) if (s.startsWith(isUrl.prefixes[i])) return true;
for (let i=0; i<isUrl.domains.length; i++) if (s.endsWith('.'+isUrl.domains[i]) || s.includes('.'+isUrl.domains[i]+'\/') ||s.includes('.'+isUrl.domains[i]+'?')) return true;
return false;
}
cm.addOverlay({
token: function(stream) {
let ch = stream.peek();
let word = "";
if (rx_word.includes(ch) || ch==='\uE000' || ch==='\uE001') {
stream.next();
return null;
}
while ((ch = stream.peek()) && !rx_word.includes(ch)) {
word += ch;
stream.next();
}
if (isUrl(word)) return "url"; // CSS class: cm-url
}},
{ opaque : true } // opaque will remove any spelling overlay etc
);
let widget=document.createElement('button');
widget.innerHTML='→'
widget.onclick=function(e) {
if (!widget.dataset.token) return;
let link=widget.dataset.token;
if (!(new RegExp('^(?:(?:https?|ftp):\/\/)', 'i')).test(link)) link="http:\/\/"+link;
window.open(link, '_blank');
return true;
};
hoverWidgetOnOverlay(cm, 'url', widget);
}
</script>
</body>
</html>
Here is a starting point, but it need to be improved.
LIVE DEMO
function makeHyperLink(innerTextInside)
{
var all = document.getElementsByTagName("*");
for (var i=0, max=all.length; i < max; i++) {
if(all[i].innerText == innerTextInside)
{
all[i].innerHTML="<a target='_blank' href='https://google.com'>THIS IS A LINK TO GOOGLE</a>"
}
}
}

ZeroClipboard not working on mobile version of the site

I have implemented ZeroClipboard functionality on our site - http://couponvoodoo.com/rcp/Jabong.com/coupons-offers?field_offer_type_tid=All
I am using Drupal-7
It is working fine on the desktop version but not working on the mobile version of the site.
I have put the following code in the footer :
<script type="text/javascript">
copy_coupon_footer();
function copy_coupon_footer(){
var divArray = document.getElementsByClassName("unlock_best_coupon");
for (var i = 0, len = divArray.length; i < len; ++i) {
var offer_type = divArray[i].getAttribute('data-clipboard-text');
// alert('offer_type '+offer_type );
try{
var id = divArray[i].getAttribute( 'id' );
var client = new ZeroClipboard( document.getElementById(id), {moviePath:'/moviePath' } );
client.on( 'load', function(client) {
client.on( 'complete', function(client, args) {try{
var url = this.getAttribute("href");
var coupon_code = url.split('&c=')[1].split('&')[0];
this.innerHTML = coupon_code;
var classname = this.className+' copied_coupon';
this.setAttribute("class",classname);
// window.open(url,'_blank');
window.location.href = url;
}catch(e){}
} );
} );
}catch(e){alert(e.message);}
}
return false;
}
</script>
ZeroClipboard requires Adobe Flash in order to perform it's clipboard function and thus it will not work in any browser that does not have Adobe Flash installed.
So, since there are hardly any mobile devices with Adobe Flash (only a few older Android devices), it won't work on mobile devices.
When I asked this question about an alternative to ZeroClipboard that doesn't require Adobe Flash, no other solutions were offered.
This answer may be a bit late, but I have created a pure JavaScript alternative to zeroclipboard that is very easy to use. Here it is: Github repository. Here is the code:
function clip(text) {
var copyElement = document.createElement('input');
copyElement.setAttribute('type', 'text');
copyElement.setAttribute('value', text);
copyElement = document.body.appendChild(copyElement);
copyElement.select();
document.execCommand('copy');
copyElement.remove();
}

link element onload

Is there anyway to listen to the onload event for a <link> element?
F.ex:
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'styles.css';
link.onload = link.onreadystatechange = function(e) {
console.log(e);
};
This works for <script> elements, but not <link>. Is there another way?
I just need to know when the styles in the external stylesheet has applied to the DOM.
Update:
Would it be an idea to inject a hidden <iframe>, add the <link> to the head and listen for the window.onload event in the iframe? It should trigger when the css is loaded, but it might not guarantee that it's loaded in the top window...
Today, all modern browsers support the onload event on link tags. So I would guard hacks, such as creating an img element and setting the onerror:
if !('onload' in document.createElement('link')) {
imgTag = document.createElement(img);
imgTag.onerror = function() {};
imgTag.src = ...;
}
This should provide a workaround for FF-8 and earlier and old Safari & Chrome versions.
minor update:
As Michael pointed out, there are some browser exceptions for which we always want to apply the hack. In Coffeescript:
isSafari5: ->
!!navigator.userAgent.match(' Safari/') &&
!navigator.userAgent.match(' Chrom') &&
!!navigator.userAgent.match(' Version/5.')
# Webkit: 535.23 and above supports onload on link tags.
isWebkitNoOnloadSupport: ->
[supportedMajor, supportedMinor] = [535, 23]
if (match = navigator.userAgent.match(/\ AppleWebKit\/(\d+)\.(\d+)/))
match.shift()
[major, minor] = [+match[0], +match[1]]
major < supportedMajor || major == supportedMajor && minor < supportedMinor
This is kind of a hack, but if you can edit the CSS, you could add a special style (with no visible effect) that you can listen for using the technique in this post: http://www.west-wind.com/weblog/posts/478985.aspx
You would need an element in the page that has a class or an id that the CSS will affect. When your code detects that its style has changed, the CSS has been loaded.
A hack, as I said :)
The way I did it on Chrome (not tested on other browsers) is to load the CSS using an Image object and catching its onerror event. The thing is that browser does not know is this resource an image or not, so it will try fetching it anyway. However, since it is not an actual image it will trigger onerror handlers.
var css = new Image();
css.onerror = function() {
// method body
}
// Set the url of the CSS. In link case, link.href
// This will make the browser try to fetch the resource.
css.src = url_of_the_css;
Note that if the resource has already been fetched, this fetch request will hit the cache.
E.g. Android browser doesn't support "onload" / "onreadystatechange" events for element: http://pieisgood.org/test/script-link-events/
But it returns:
"onload" in link === true
So, my solution is to detect Android browser from userAgent and then wait for some special css rule in your stylesheet (e.g., reset for "body" margins).
If it's not Android browser and it supports "onload" event- we will use it:
var userAgent = navigator.userAgent,
iChromeBrowser = /CriOS|Chrome/.test(userAgent),
isAndroidBrowser = /Mozilla\/5.0/.test(userAgent) && /Android/.test(userAgent) && /AppleWebKit/.test(userAgent) && !iChromeBrowser;
addCssLink('PATH/NAME.css', function(){
console.log('css is loaded');
});
function addCssLink(href, onload) {
var css = document.createElement("link");
css.setAttribute("rel", "stylesheet");
css.setAttribute("type", "text/css");
css.setAttribute("href", href);
document.head.appendChild(css);
if (onload) {
if (isAndroidBrowser || !("onload" in css)) {
waitForCss({
success: onload
});
} else {
css.onload = onload;
}
}
}
// We will check for css reset for "body" element- if success-> than css is loaded
function waitForCss(params) {
var maxWaitTime = 1000,
stepTime = 50,
alreadyWaitedTime = 0;
function nextStep() {
var startTime = +new Date(),
endTime;
setTimeout(function () {
endTime = +new Date();
alreadyWaitedTime += (endTime - startTime);
if (alreadyWaitedTime >= maxWaitTime) {
params.fail && params.fail();
} else {
// check for style- if no- revoke timer
if (window.getComputedStyle(document.body).marginTop === '0px') {
params.success();
} else {
nextStep();
}
}
}, stepTime);
}
nextStep();
}
Demo: http://codepen.io/malyw/pen/AuCtH
Since you didn't like my hack :) I looked around for some other way and found one by brothercake.
Basically, what is suggested is to get the CSS using AJAX to make the browser cache it and then treat the link load as instantaneous, since the CSS is cached. This will probably not work every single time (since some browsers may have cache turned off, for example), but almost always.
Another way to do this is to check how many style sheets are loaded. For instance:
With "css_filename" the url or filename of the css file, and "callback" a callback function when the css is loaded:
var style_sheets_count=document.styleSheets.length;
var css = document.createElement('link');
css.setAttribute('rel', 'stylesheet');
css.setAttribute('type', 'text/css');
css.setAttribute('href', css_filename);
document.getElementsByTagName('head').item(0).appendChild(css);
include_javascript_wait_for_css(style_sheets_count, callback, new Date().getTime());
function include_javascript_wait_for_css(style_sheets_count, callback, starttime)
/* Wait some time for a style sheet to load. If the time expires or we succeed
* in loading it, call a callback function.
* Enter: style_sheet_count: the original number of style sheets in the
* document. If this changes, we think we finished
* loading the style sheet.
* callback: a function to call when we finish loading.
* starttime: epoch when we started. Used for a timeout. 12/7/11-DWM */
{
var timeout = 10000; // 10 seconds
if (document.styleSheets.length!=style_sheets_count || (new Date().getTime())-starttime>timeout)
callback();
else
window.setTimeout(function(){include_javascript_wait_for_css(style_sheets_count, callback, starttime)}, 50);
}
This trick is borrowed from the xLazyLoader jQuery plugin:
var count = 0;
(function(){
try {
link.sheet.cssRules;
} catch (e) {
if(count++ < 100)
cssTimeout = setTimeout(arguments.callee, 20);
else
console.log('load failed (FF)');
return;
};
if(link.sheet.cssRules && link.sheet.cssRules.length == 0) // fail in chrome?
console.log('load failed (Webkit)');
else
console.log('loaded');
})();
Tested and working locally in FF (3.6.3) and Chrome (linux - 6.0.408.1 dev)
Demo here (note that this won't work for cross-site css loading, as is done in the demo, under FF)
You either need a specific element which style you know, or if you control the CSS file, you can insert a dummy element for this purpose. This code will exactly make your callback run when the css file's content is applied to the DOM.
// dummy element in the html
<div id="cssloaded"></div>
// dummy element in the css
#cssloaded { height:1px; }
// event handler function
function cssOnload(id, callback) {
setTimeout(function listener(){
var el = document.getElementById(id),
comp = el.currentStyle || getComputedStyle(el, null);
if ( comp.height === "1px" )
callback();
else
setTimeout(listener, 50);
}, 50)
}
// attach an onload handler
cssOnload("cssloaded", function(){
alert("ok");
});
If you use this code in the bottom of the document, you can move the el and comp variables outside of the timer in order to get the element once. But if you want to attach the handler somewhere up in the document (like the head), you should leave the code as is.
Note: tested on FF 3+, IE 5.5+, Chrome
The xLazyLoader plugin fails since the cssRules properties are hidden for stylesheets that belong to other domains (breaks the same origin policy). So what you have to do is compare the ownerNode and owningElements.
Here is a thorough explanation of what todo:
http://yearofmoo.com/2011/03/cross-browser-stylesheet-preloading/
// this work in IE 10, 11 and Safari/Chrome/Firefox/Edge
// if you want to use Promise in an non-es6 browser, add an ES6 poly-fill (or rewrite to use a callback)
let fetchStyle = function(url) {
return new Promise((resolve, reject) => {
let link = document.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
link.onload = resolve;
link.href = url;
let headScript = document.querySelector('script');
headScript.parentNode.insertBefore(link, headScript);
});
};
This is a cross-browser solution
// Your css loader
var d = document,
css = d.head.appendChild(d.createElement('link'))
css.rel = 'stylesheet';
css.type = 'text/css';
css.href = "https://unpkg.com/tachyons#4.10.0/css/tachyons.css"
// Add this
if (typeof s.onload != 'undefined') s.onload = myFun;
} else {
var img = d.createElement("img");
img.onerror = function() {
myFun();
d.body.removeChild(img);
}
d.body.appendChild(img);
img.src = src;
}
function myFun() {
/* ..... PUT YOUR CODE HERE ..... */
}
The answer is based on this link that say:
What happens behind the scenes is that the browser tries to load the
CSS in the img element and, because a stylesheet is not a type of
image, the img element throws the onerror event and executes our
function. Thankfully, browsers load the entire CSS file before
determining its not an image and firing the onerror event.
In modern browsers you can do css.onload and add that code as a fallback to cover old browsers back to 2011 when only Opera and Internet Explorer supported the onload event and onreadystatechange respectively.
Note: I have answered here too and it is my duplicate and deserves to be punished for my honesteness :P

Categories

Resources