How to check if IE11 is in compatibility view using JS - javascript

I'd like to check if IE11 compatibility view is enabled for the current domain. Setting compatibility view is through: Tools > Compatibility View Settings.
I know this has been asked by a few a couple of years ago but looks like the answers doesn't work anymore due to recent update on IE11.
Does anyone know an alternative way to do this?

In IE versions 8-11 You can use document.documentMode. Valid values are 5, 7 (compatibility mode), 8, 9, 10, and 11 (Edge).
Setting compatibility mode in the console changes the value directly.
Loading a page with a <meta http-equiv tag changes the value
Adding a site to compatibility mode in "Tools -> Compatibility View
settings" changes the value to 7.
https://msdn.microsoft.com/en-us/library/jj676915(v=vs.85).aspx
Examples
For example if I load this page in IE11 I get documentMode of 11.
<!doctype HTML>
<body>
<p>Hello World!<p>
</body>
This page loaded in IE11 sets documentMode to 9.
<html>
<head>
<meta http-equiv="x-ua-compatible" content="IE=9"/>
</head>
<body>
<p>Hello World!<p>
</body>
</html>

If you just wanting to check if you are being run in compatibility mode you can use this script.
// Create new ieUserAgent object
var ieUserAgent = {
init: function () {
// Get the user agent string
var ua = navigator.userAgent;
this.compatibilityMode = false;
// alert (ua);
if(ua.indexOf("MSIE") == -1){
this.version = 0;
return 0;
}
if(ua.indexOf("compatible") == -1){
this.compatibilityMode = false;
return 0;
}else{
this.compatibilityMode = true;
return 0;
}
}
};
// Initialize the ieUserAgent object
ieUserAgent.init();
-OR-
/**
* Check if client is IE and in compatibility view
*
* #returns {boolean}
*/
function isIECompatibilityMode() {
var ua = navigator.userAgent;
if (ua.indexOf("MSIE") == -1) {
return false;
}
return (ua.indexOf("compatible") != -1); }

Related

Detect if IE < 11 reliably

Does a reliable method for detecting IE browser version exist? So far I have tried.
IE Conditional comments, not reliable
User Agent HTTP request header, not always set
My next option was to try out javascript with something like
var nVer = navigator.appVersion;
var nAgt = navigator.userAgent;
var browserName = navigator.appName;
var fullVersion = ''+parseFloat(navigator.appVersion);
var majorVersion = parseInt(navigator.appVersion,10);
But will javascript always have access to this information?
One of the main features (although poorly implemented) that exists in IE11 and not earlier versions is const. So you could just create a const variable in an eval and see if an error is being thrown.
function isIE11() {
try {
eval("const x = 1;");
return true;
} catch (err) {}
return false;
}
console.log(isIE11());
You can try to refer code example below which can identify IE7, IE8, IE9, IE10, IE11 versions.
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script>
function GetIEVersion() {
var sAgent = window.navigator.userAgent;
var Idx = sAgent.indexOf("MSIE");
// If IE, return version number.
if (Idx > 0)
return parseInt(sAgent.substring(Idx+ 5, sAgent.indexOf(".", Idx)));
// If IE 11 then look for Updated user agent string.
else if (!!navigator.userAgent.match(/Trident\/7\./))
return 11;
else
return 0; //It is not IE
}
if (GetIEVersion() > 0)
alert("This is IE " + GetIEVersion());
else
alert("This is not IE.");
GetIEVersion();
</script>
</head>
<body>
</body>
</html>
Further, You can try to modify this code as per your own requirement.

Why css class is not overridden for IE9?

I have piece of HTML code in which we are applying special css for IE9, IE10 & IE11.
<!doctype html>
<!--[if IE 9]><html data-placeholder-focus="false" lang="{%=user_locale_html}}" dir="ltr" class="ie9 lt-ie10 lt-ie11 lt-ie12 gt-ie8 gt-ie7 gt-ie6"><![endif]-->
<!--[if !(IE)]><!--><html lang="{%=user_locale_html}}" dir="{%=dir}}">
<script>
var ua = window.navigator.userAgent;
if (ua.indexOf("Trident/7.0") > 0)
document.documentElement.className='ie11 lt-ie12 gt-ie10 gt-ie9 gt-ie8 gt-ie7 gt-ie6';
else if (ua.indexOf("Trident/6.0") > 0)
document.documentElement.className='ie10 lt-ie11 lt-ie12 gt-ie9 gt-ie8 gt-ie7 gt-ie6';
if(/*#cc_on!#*/false){
document.documentElement.className='gt-ie11 gt-ie10 gt-ie9 gt-ie8 gt-ie7 gt-ie6';
}
</script>
<!--<![endif]-->
</html>
Note the code if(/*#cc_on!#*/false) {}
This code is overriding the css class applied in IE10 when we have userAgant=Trident/6.0. (Which causing me problem to override ie10 class.
But my question is, Why this code is not overriding the classes when the browser is IE9?
I know that #cc_on related stuff is not needed in the code, But i am curious to know how it is behaving differently.
Thanks!
Possible that your code is not identifying the IE 9 and that is why CSS class not get override.
I suggest you to try to refer code example below which can able to find the IE 8, IE 9, IE 10, IE 11.
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script>
function GetIEVersion() {
var sAgent = window.navigator.userAgent;
var Idx = sAgent.indexOf("MSIE");
// If IE, return version number.
if (Idx > 0)
return parseInt(sAgent.substring(Idx+ 5, sAgent.indexOf(".", Idx)));
// If IE 11 then look for Updated user agent string.
else if (!!navigator.userAgent.match(/Trident\/7\./))
return 11;
else
return 0; //It is not IE
}
if (GetIEVersion() > 0)
alert("This is IE " + GetIEVersion());
else
alert("This is not IE.");
</script>
</head>
<body>
</body>
</html>
Output:
Further, you can try to modify it as per your requirement may help you to solve your issue.

iOS 8 Bug - OnUpdateReady never called again when device returns from sleep

When an iOS 8 device running a Web Application (i.e. launched from a shortcut on the Home Screen) returns from it's Sleep state all asynchronous web requests made fail to trigger the OnUpdateReady callback.
The problem is quite easy to reproduce - simply put the two code files below on any web server and give it a try.
Has anyone else run into this issue? If so is there any workarounds?
I'm posting this to try to attract attention to this bug in iOS 8 that has essentially ruined all of my web applications - we've had to recommend to NOT upgrade beyond iOS 7. And yes, I've posted the problem on Apple Bug Reporter but I think no one is looking at these since it has been a long time.
app.manifest
CACHE MANIFEST
# 2014-09-24 - Test
CACHE:
default.html
default.html
<!DOCTYPE html>
<html manifest="app.manifest">
<head>
<title>Test Harness</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
<meta name="HandheldFriendly" content="true" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<script language="javascript" type="text/javascript">
var Test = new function () {
var _GetEnd = function (oResult) {
var sResult = ': ' +
((oResult.Value === true)
? 'Success'
: 'Failure<br>' + oResult.Reason) +
'<br>';
var oLog = document.getElementById('idLog');
oLog.innerHTML = (new Date()) + sResult + oLog.innerHTML
setTimeout(_GetBegin, 1000);
};
var _GetBegin = function () {
var sURL = 'app.manifest';
var hAsyncCallback = _GetEnd;
try {
var oRequest = new XMLHttpRequest();
oRequest.onreadystatechange =
function () {
if (oRequest.readyState != 4) return;
if (oRequest.status != 200) {
hAsyncCallback({ Value: false, Reason: oRequest.responseText });
} else {
hAsyncCallback({ Value: true, Reason: null });
}
};
oRequest.open('GET', sURL, true);
oRequest.send(null);
} catch (e) {
alert('Critical Error: ' + e.message );
}
};
this.Start = function () { _GetBegin(); }
};
</script>
</head>
<body onload="Test.Start();">
<ol>
<li>Put both app.manifest and default.html on a web server.</li>
<li>Make sure this page is being launched from the Home screen as a web application.</li>
<li>Press the sleep button while it is running.</li>
<li>Press the wake button and unlock the phone to get back to this screen.</li>
<li>Under iOS7x the page continues, under iOS8 the onreadystatechange never gets called again.</li>
</ol>
<div id="idLog"></div>
</body>
</html>
Installing iOS 8.1.1 fixes this.
I am also seeing the same issue, though my example is much simpler. Simply have a webclip application with
<script>
window.setInterval(function(){
console.log("Johnny Five Alive! : " + new Date());
},1000);
</script>
on the page. Inspecting the console, after the sleep wakes up, no more console output. This works fine on iOS7 (my actual application is a complicated angularJS thing, I just boiled down the issue to this). Have you had any response on your bug report?
Our workaround (for AJAX) is:
Detect iOS8 (indeed 8.0.2 still has this) (also see this for other workaround: How to resume JavaScript timer on iOS8 web app after screen unlock?)
Remove the normal eventListeners, but keep the onProgress one
...
this.onProgress = function(e)
{
var position = e.position || e.loaded;
var total = e.totalSize || e.total;
var percentage = 0.0;
if(total != 0)
{
percentage = position / total;
}
if(percentage == 1) {
if( this.isIOS8() ) {
recovery_uuid.get(uuid, _.bind(this.ios8ScriptReturn, this));
}
}
}
...
//this gets called when the script with this UUID is injected
this.ios8ScriptReturn = function(uuid, value) {
//then we create a simpler non real one
this.xhr = {};
this.xhr.readyState = 4;
this.xhr.status = 200;
this.xhr.responseText = value;
this.xhr.onreadystatechange = null;
this.xhr.isFake = true;
//fake stateChnage
this.onReadyStateChange();
}
add a UUID to each request
if( this.isIOS8() ) {
ajaxInfo.url += '&recoveryUUID='+ajaxInfo.uuid;
}
Then still perform the XHR Send (that actually works fine, server gets and send back fine).
server Side save the 'result' in database/file with the UUID as index/part of filename
//detect the need for saving the result, and save it till requested
if(isset($_GET['recoveryUUID'])) {
$uuid = $_GET['recoveryUUID'];
RecoveryUUID::post($uuid, $result_json_string);
}
On the client create a little helper global object that listens to the code injects and redirects them to the onProgress handler.
var RecoveryUUID = (function (_root) {
function RecoveryUUID() {
this.callbacks = {};
}
var proto = RecoveryUUID.prototype;
proto.onLoaded = null;
proto.set = function(uuid, value) {
console.log('RECOVERY UUID: Received DATA: '+uuid+' value: '+value);
if(typeof this.callbacks[uuid] != 'undefined') {
this.callbacks[uuid](uuid, value);
delete this.callbacks[uuid]; //auto remove
}
if(this.onLoaded != null) {
this.onLoaded(uuid, value);
}
var script = document.getElementById("recoveryScript_"+uuid);
script.parentElement.removeChild(script);
}
proto.getURL = function(uuid) {
return "http://"+window.location.hostname+":8888/recoveryuuid/index.php?uuid="+uuid;
}
proto.get = function(uuid, callback) {
var script = document.createElement("script");
script.setAttribute("id", "recoveryScript_"+uuid);
script.setAttribute("type", "text/javascript");
script.setAttribute("src", this.getURL(uuid));
if(typeof callback != 'undefined') {
this.callbacks[uuid] = callback;
}
document.getElementsByTagName("head")[0].appendChild(script);
}
return RecoveryUUID;
})();
//global - just so the injected script knows what to call
recovery_uuid = new RecoveryUUID();
The script that is loaded immediately executes (pushes, since setInterval is dead as well).
// this is: http://"+window.location.hostname+":8888/recoveryuuid/index.php?uuid=...."
<?php
header('Cache-Control: no-cache, no-store, must-revalidate, post-check=0, pre-check=0 '); // HTTP 1.1. //iOS force this file to keep fresh
header('Pragma: no-cache'); // HTTP 1.0.
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header('Content-type: application/javascript; charset=UTF-8');
if(isset($_GET['uuid'])) {
$uuid = $_GET['uuid'];
$out = 'recovery_uuid.set('.json_encode($uuid).','.json_encode(RecoveryUUID::get($uuid)).');';
echo $out;
}
?>
Below is a simple filebased results implementation.
<?php
class RecoveryUUID {
static public function getFileName($uuid) {
return SOMESTATIC LOCATION.$uuid.'.json';
}
static public function post($uuid, $stdClassOrString) {
$data = '{ "data": '.json_encode($stdClassOrString).', "uuid": '.json_encode($uuid).' }';
file_put_contents(self::getFileName($uuid), $data);
}
//might not work first time as the script tag might request this file before it was written.
//so we wait just a bit.
static public function getFull($uuid) {
$tries = 10;
$filename = self::getFileName($uuid);
while ($tries > 0) {
if(file_exists($filename)) {
if (is_readable($filename)) {
$data = #file_get_contents($filename);
if($data !== FALSE) {
unlink($filename);
return $data;
}
}
}
$tries = $tries -1;
usleep(250000);//wait 0.25 secs ...
}
$data = new stdClass();
$data->uuid = $uuid;
$data->data = 'ERROR RECOVERYUUID: timeout on reading file';
return $data;
}
static public function get($uuid) {
$decoded = json_decode(self::getFull($uuid));
if( $decoded->uuid == $uuid ) {
return $decoded->data;
}
return null;
}
}
?>
As we do not use JQuery all we needed to do was add the extra logic in our Ajax class, and of course the Saving to Database for all requests..
Downsides:
Nasty
Will keep on adding memory footprint for each call (for us not an issue as the memory is cleared between window.location.href calls (we do not use SPA) so eventually will fall over.
Extra serverside logic.
Upsides:
Works until memory runs out (removing script tags, which we do does not remove the memory associated)
Comments:
You could of course just send everything with the 'call' but we wanted to have minimal server side impact (or not much work for us anyway) + we presume this will be fixed and means our 'user' code has 0 impact.
Weird, Apple just closed my bug and referred to the same bug number. Also a web app but I found css3 transitions to stop working after screen lock see below:
Engineering has determined that your bug report (18556061) is a duplicate of another issue (18042389) and will be closed
My report:
If you add an HTML app to the home screen and open it, all CSS3 transitions work correctly. Without closing the app and pressing screen lock the transitions seem to stop and can cause the ui to appear to freeze. For example if an absolute overlay is triggered (opacity:0 to opacity:1) it remains invisible making the app appear not to work
Ajax requests, Timer functions and WebkitAnimation are broken after a lock-screen on iOS8.
For the Ajax and Timer functions, we are using this solution in our system:
How to resume JavaScript timer on iOS8 web app after screen unlock? (link to the gitHub in the comment).
It is not exactly part of the question but I would like to share our workaround with CSS3 animations and events, since it may help somebody in the future.
For the webkitAnimation, we found that redrawing the element with the animation on, or more drastically the body would restart animations and events applied to them (webkitAnimationEnd for instance, which is used heavily by jquery-mobile).
so our code gives something like:
document.body.style.display='none';
setTimeout( function() { document.body.style.display = 'block'; }, 1);
You may or may not need the setTimeout function on the second statement. Most interesting thing is, once it has been redrawn, it will never go frozen again no matter how many lock screens come up after that...
The webapp environment is so horribly broken when resuming after screen lock I don't see how (a) Apple could ignore this indefinitely and (b) how any webapp can confidently work around the crippled environment.
My solution is to detect resume after sleep using setInterval (which stops working after the resume) and then posting an alert() to the user stating that the app has to be re-launched from the home screen because iOS cannot resume it.
It just so happens that alert() is also broken after the resume--it displays the alert and then the webapp exits to the home screen when the user hits OK! So this forces the user to re-launch.
The only issue when the user re-launches is the handling of apple-mobile-web-app-status-bar-style. I have this set to black-translucent which normally sets the status bar content to black (on light backgrounds) or white (on dark backgrounds). On the first re-launch after resume, the status bar content is always black. On subsequent re-launches (not interrupted by sleep/resume) the behavior returns to normal.
What a mess. If I was responsible for this at Apple I'd be embarrassed, and here we are with 8.1 and it still hasn't been fixed.

Supporting Custom Elements in IE Compatibility mode

In Chrome and IE (non-compatibility), custom tags work fine as far as inspecting and navigating the DOM.
In IE+compatibility mode, it does not work.
Here is some sample code in jsbin: http://jsbin.com/ozajeh/1/edit
<html>
<!-- Run this in IE 8/9, possibly 10, with compatibility mode on to see the issue -->
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
if (document.createElement) {
document.createElement("myelement");
}
</script>
</head>
<body>
<script>
var div = $("<div>content</div>");
if( div.contents().length > 0 && div[0].childNodes.length > 0){
alert("found content in div");
}
var myElement = $("<myelement>content</myelement>");
if (myElement.contents().length > 0 && myElement[0].childNodes.length > 0) {
alert("found content in myelement");
}else{
alert("IE issue: cannot find content in myelement");
}
</script>
</body>
</html>
How can I get Internet Explorer in compatibility mode to deal with the tag correctly?
Current, what happens, is that myElement.nextSibling() returns the text node, which is obviously incorrect.
I can figure out a workaround based on property/value testing, but is there a more solid approach to handling this scenario?

getElementsByTagName() behaves differently in IE and FF

I am new to JavaScript, trying to figure out a tag information value. GWT Code is as follows..
public static native boolean isToolBarInstalled() /*-{
alert("Validating the toolbar installed.");
var metas = document.getElementsByTagName('head')[0].getElementsByTagName('meta');
var i;
alert ("Meta length: "+metas.length);
for (i = 0; i < metas.length; i++){
alert("Value: "+metas[i].value);
if (metas[i].getAttribute('name') == "toolbar"){
return true;
}
}
return false;
}-*/;
FF return true whereas IE returns false, for the same page? Any clue/suggestions would be helpful.
WM.
HTML is too huge to post, here is a snippet of the code..
<html>
<head>
....
<title>My App</title>
<meta name="toolbar" content="1.0">
</head>
<body>
.....
</body>
<html>
Works for me in IE7.
Check you haven't got any text content before the <meta> end-tag other than simple whitespace.
If you have any non-whitespace text in or before <html> or <head>, the browser will decide that you meant to open the <body> to contain the text. (This is actually valid in non-XHTML HTML, as the </head> end-tag and the <body> start-tag are optional.) That means closing the <head> section, so the number of <meta> tags inside <head> will be 0.
In any case you might as well say just:
var metas= document.getElementsByTagName('meta');
as the bit about checking they're in <head> is redundant for a valid document; that's the only place <meta> is allowed to appear.
alert("Value: "+metas[i].value);
There's no .value on <meta>, do you mean .content?
if (metas[i].getAttribute('name') == "toolbar"){
Use metas[i].name. There's no reason to use getAttribute/setAttribute on an HTML document and there are problems with it on IE.
Try this:
element.attributes[value].nodeAttribute;
As explained here:
The getAttribute() method will return
"null" in Internet Explorer when
trying to get the for attribute of a
label element.
Might be the same issue...
Well look:
Example
Source
In this example it is working on IE.
function isToolBarInstalled() {
alert("Validating the toolbar installed.");
var metas = document.getElementsByTagName('head')[0].getElementsByTagName('meta');
var i;
alert ("Meta length: "+metas.length);
for (i = 0; i < metas.length; i++){
alert("Value: "+metas[i].value);
var attr = metas[i].getAttribute('name');
// IE workaround
if (attr == null)
{
attr = metas[i].attributes["name"];
if (attr != null) attr = attr.nodeValue;
}
if (attr == "toolbar")
return true;
}
return false;
}
alert( "Is installed: " + isToolBarInstalled() );

Categories