Posts Tagged ‘msie’

META Tag ‘MSThemeCompatible’

Wednesday, March 31st, 2010

Okay, so this one’s a little old, and I just found it while looking at some of Microsoft Update’s HTML source, it appears to be relevant for MSIE6 and newer and may be responsible for some interesting styling and behaviour of form components.

A quick search for it turns up lots of discussions about other browers such as Firefox being effected if the value is not defined… as such it’s likely a good idea to define it in your pages to be sure.

An old MSDN entry reads…

When running on Windows XP, Internet Explorer 6 and the content displayed in it sports a look and feel that matches the Windows XP platform. You can opt to have your HTML content not take on the same look as the operating system for elements such as buttons and scroll bars, by adding the following META tag:
<meta http-equiv=”MSThemeCompatible” content=”no” />

Cheers

MSIE browser testing

Thursday, March 18th, 2010

Testing web applications with various versions of MSIE (Internet Explorer) often proves problematic as it’s generally not possible to have more than one version installed on a single Windows installation. There are various approaches, such as:

  • Having an entire test lab with different browser configurations.
  • More often, it’s also possible to run a set of virtual machines on a single desktop.
  • Another option is to find a package that ‘hacks’ around some of the Windows limitations and installs (at least partially) the browser rendering capabilities.

NOTE: the final method above has some quirks, but you can generally use it for preliminary testing by developers as it’s obviously easier to maintain.

Here are a few common packages that I’m aware of:

Happy testing!

JavaScript StringBuffer

Sunday, November 29th, 2009

Eventually, you come to a point where the performance of JavaScript becomes an issue.  Most modern browsers have made significant improvements  in their javascript engines, unfortunately Microsoft has yet to do the same.  MSIE’s (at least up to and including MSIE8)  javascript performance lags far behind Mozilla/Firefox, Safari, Chrome and Opera.

String concatenation is extremely slow in MSIE,  but arrays are generally fast… as such it’s often beneficial to implement an object similar to the Java StringBuffer (or StringBuilder) for JavaScript.

The StringBuffer implementation… you can customize to make it more functional, but this is the core:

function StringBuffer(){
this.buffer = [];
}
StringBuffer.prototype.append = function append(string){
this.buffer.push(string);
return this;
};
StringBuffer.prototype.toString = function toString(){
return this.buffer.join(”");
};

Example:

function example_slow(x1,x2,x3){
var rc = x1;
rc+=x2;
rc+=x3;
return rc;
}

function example_fast(x1,x2,x3){
var sb = new StringBuffer();
sb.append(x1);
sb.append(x2);
sb.append(x3);
return sb.toString();
}

References:

Cheers

Browser Rendering Engines

Friday, February 15th, 2008

This is knowledge that is generally “tribal” by nature, reserved to only the nerdiest web developers, recently I was asked to name these and failed. Here’s the bounty of my research.

Gecko is generally considered to be the second most-popular layout engine on the Web, after Trident (used by Internet Explorer for Windows since version 4), and followed by WebCore (used by Safari) and Presto (used by Opera).

Gecko is the open source, free software web browser layout engine used in all Mozilla-branded software and its derivatives, including later Netscape browser releases. Written in C++ and licensed under MPL/GPL/LGPL triple license, Gecko is designed to support open Internet standards. Originally created by Netscape Communications Corporation, its development is now overseen by the Mozilla Foundation.

Trident (also known as MSHTML) is the name of the layout engine for the Microsoft Windows version of Internet Explorer. It was first introduced with the release of Internet Explorer version 4 in October 1997, has been steadily upgraded and remains in use today. For version 7 of Internet Explorer, Microsoft made significant changes to the Trident layout engine to improve compliance with web standards and add support for new technologies. Despite these changes, Trident remains significantly less compliant than competing layout engines Gecko, Presto and WebCore.

Presto is the name of the current (Opera 9 series) layout engine for the Opera web browser developed by Opera Software. It was first released (following several public betas and technical previews) on January 28, 2003 in Opera 7.0 for Windows. Presto replaced the Elektra engine used in versions 4–6 of Opera. Presto differs from Elektra in that it is dynamic: the page or parts of it can be re-rendered in response to DOM and script events. The Presto layout engine is only available as a part of Opera browser or related products. The source or binary (DLL) forms of the engine are not publicly available. Subsequent releases have seen a number of bugs fixed and optimizations to improve the speed of the ECMAScript (”JavaScript“) engine.

Tasman is the name of the layout engine introduced with version 5 of Internet Explorer for Mac. Tasman was an attempt to improve support for web standards, as defined by the World Wide Web Consortium. At the time of its release, Tasman was seen as the layout engine with the best support for web standards such as HTML and CSS. Unfortunately, MSIE for Mac is no longer supported, but newer versions of Tasman are incorporated in some other current Microsoft products.

Cheers!

MSIE PNG Alpha Transparency

Wednesday, October 10th, 2007

In usual form, MSIE doesn’t directly implement Alpha-Transparency on PNG images. Typically this feature is used to allow for anti-aliased gradients on images so that they can be used to support a variety of backgrounds.

There are a variety of solutions online for this problem, however I take issue with most, here’s why:

  • .htc files – this is a proprietary Microsoft solution, to add support on most web servers the MIME type must also be added.
  • filter: progid: – this too is utilizing a standard in Microsoft’s own particular way.

While neither of these is perfect, the ‘filter:’ is obviously the best of two evils. Surround it with the “Conditional If” comments (previously documented) and you’re at least safe for most other browsers.

Here’s my example code:

<!–[if gte IE 5.5000]>
<script type=”text/javascript”>
function correctPNG() // correctly handle PNG transparency in Win IE 5.5 or higher.
{
for(var i=0; i<document.images.length; i++)
{
var img = document.images[i]
var imgName = img.src.toUpperCase()
if (imgName.substring(imgName.length-3, imgName.length) == “PNG”)
{
var imgID = (img.id) ? “id=’” + img.id + “‘ ” : “”;
var imgClass = (img.className) ? “class=’” + img.className + “‘ ” : “”;
var imgTitle = (img.title) ? “title=’” + img.title + “‘ ” : “title=’” + img.alt + “‘ “;
var imgStyle = “display:inline-block;” + img.style.cssText;
if (img.align == “left”) imgStyle = “float:left;” + imgStyle;
if (img.align == “right”) imgStyle = “float:right;” + imgStyle;
if (img.parentElement.href) imgStyle = “cursor:hand;” + imgStyle;
var strNewHTML = “<span ” + imgID + imgClass + imgTitle
+ ” style=\”" + “width:” + img.width + “px;height:” + img.height + “px;” + imgStyle + “;”
+ “filter:progid:DXImageTransform.Microsoft.AlphaImageLoader”
+ “(src=\’” + img.src + “\’, sizingMethod=’scale’);\”></span>”;
img.outerHTML = strNewHTML;
i = i-1;
}
}
}
window.attachEvent(”onload”, correctPNG);
</script>
<![endif]–>

References:

Good luck out there!

A Flexible AJAX Framework

Monday, July 23rd, 2007

AJAX = Asyncronous (but not always), JavaScript, XML (Text or JSON). These technologies have been around almost as long as the Internet itself, but have only recently been used together to change the way that web applications are built.

XMLHTTPRequest is an API used mainly by browser-based Javascript applications to send and retrieve data from servers. It was developed originally by Microsoft for Exchange Server’s Outlook Web Access, but it has since been widely supported in browsers and is the heart of AJAX dynamic Web applications.

I’ve messed with many of the frameworks available online, and while they are very good, I’ve routinely found issues or features that they lack. Over time I’ve cobbled together my own framework, I fully expect this to change over time, but publish it here for your consideration!

The XSS methods (and “otherHost” variable) are provided as MSIE6 allows for Cross-site Scripting here. MSIE7 and Mozilla will indicate errors if connections are attempted to a ‘non-originating host’. I’ve exploited this vulnerability in a few applications, as such I provide the test for you too!

NOTE: The example response program is written in PHP, but should be easily ported to any other language.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html>

<head>

<title>AJAX Example</title>

<script type=”text/javascript”>

var xbusy = true;

var otherHost = ‘http://www.giantgeek.com’; // DO NOT USE the ending slash!

var xhr = null;

/**

* Check for existance on DOM browsers (Mozilla, etc.)

* @return xhr

*/

function ajaxCheckDOM(){

var myxhr = null;

if(window.XMLHttpRequest) {

try {

myxhr = new XMLHttpRequest();

}

catch(e) {}

}

return myxhr;

}

/**

* Check for existance on Windows/MSIE (prior to MSIE7 which is now DOM)

* Evaluate using – new ActiveXObject(”Microsoft.XMLDOM”);

* @return xhr

*/

function ajaxCheckActiveX(){

var myxhr = null;

//if(window.ActiveXObject){

try {

myxhr = new ActiveXObject(”Msxml2.XMLHTTP”);

}

catch(e) {

try {

myxhr = new ActiveXObject(”Microsoft.XMLHTTP”);

}

catch(e) {}

}

//}

return myxhr;

}

/**

* This is a default response hook for AJAX, you SHOULD create your own as it’s only for DEMO

* @param obj – the clicked item

* @param customObj – user defined

*/

function ajaxResponseHook(obj,customObj){

var txt = xhr.responseText;// NOTE: xhr.responseXML is also valid

popStatus(’AJAX Response value [' + txt + '|' + customObj +']‘,”);

}

/**

* This is a common Response handler AJAX, you SHOULD NOT need to modify, use a ‘custom’ ajaxhook function to process the responses.

* @param obj – the clicked item

* @param ajaxhook Function (default will be used if undefined)

* @param customObj (optional – left for developer implementation, passed to the ajaxhook)

*/

function ajaxResponse(obj,ajaxhook,customObj){

var status=”;

if(xhr!=undefined){

var state=xhr.readyState;

if(state!=undefined){

if(state==4){

var code = xhr.status;

status = xhr.statusText;

if(code==200){

popStatus(’AJAX Response Received.’,”);

if(ajaxhook==undefined){

ajaxhook = function(){ ajaxResponseHook(obj,customObj); }

}

ajaxhook(obj,customObj);

ajaxBusy(obj,false);

} else {

popStatus(’AJAX Error ‘ + code + ‘ ‘ + status + ‘.’,”);

}

ajaxBusy(obj,false);

xhr=null; /* MSIE6 leak fix */

}

}

}

}

/**

* NOTE: MSIE6-7 supports XSS url’s (be careful!)

* @param obj – the clicked item

* @param url – the GET url params (FQDN)

* @param async (true or false) – false will LOCK browser until response – use cautiously!

* @param callback Function – allows for customized response handling

*/

function ajaxObj(obj,url,async,callback){

if(xbusy == true){

popStatus(’AJAX BUSY, Please Retry.’,”);

} else {

if(callback==undefined){

callback = function(){ ajaxResponse(obj,hook,”); }

}

ajaxInit(obj,url,async,callback);

}

}

/**

* This is a Non-Caching implementation of ajaxObj() to show how you can avoid the MSIE caching issue.

* NOTE: You can use similar approaches to cache per page or session.

* @param obj – the clicked item

* @param url – the GET url params (FQDN)

* @param async (true or false) – false will LOCK browser until response – use cautiously!

* @param callback Function – allows for customized response handling

*/

function ajaxObjNoCache(obj,url,async,callback){

var cacheBuster=uniqueUrl(url);// damn MSIE!

ajaxObj(obj,cacheBuster,async,callback)

}

/**

* Initializes the AJAX operation

* @param obj – item clicked

* @param url – FQDN

* @param async (true/false) – for locking

* @param callback Function – provided for customization.

*/

function ajaxInit(obj,url,async,callback){

xhr=ajaxCheckDOM();

if(!xhr){

xhr=ajaxCheckActiveX();

}

if(xhr){

ajaxBusy(obj,true);

popStatus(’AJAX Start.’,”);

xhr.onreadystatechange = callback; // method call

try {

xhr.open(’GET’,url,async); /* POST */

//xhr.setRequestHeader(’Content-Type’,'application/x-www-form-urlencoded’);

xhr.send(”); /* null */

}

catch(e)

{

if(xhr){

var code = xhr.status;

var status = xhr.statusText;

popStatus(’AJAX Client SECURITY ‘ + navigator.appName +’ ‘+ navigator.appVersion + ‘ ‘ + code + ‘ ‘ + status + ‘.’,”);

}

}

ajaxBusy(obj,false);

} else {

popStatus(’AJAX Client ERROR.’,”);

}

}

function ajaxBusy(obj,yn){

if(yn){

swapStyleObj(obj,’idle’,'busy’);

} else {

swapStyleObj(obj,’busy’,'idle’);

}

xbusyInd(yn,”);

}

function xmillis(){

return new Date().getTime();

}

function swapStyleObj(obj,oldCSS,newCSS){

if(obj!=undefined) {

var current=obj.className;

if(current!=undefined){

var txtOld = current.replace(newCSS,’ ‘);//no doubles

var txtMid = txtOld.replace(oldCSS, ‘ ‘);

var txtNew = (txtMid + ‘ ‘ + newCSS);

obj.className = txtNew;

} else {

obj.className = newCSS;

}

}

}

function xbusyInd(valnew, msg){

xbusy = valnew;

if(xbusy==true){

document.body.style.cursor=’wait’;

if(msg != ”){

top.window.defaultStatus=msg;

popStatus(msg,”);

}

showDiv(’throbber’);

//blockScreen();

} else {

document.body.style.cursor=’default’;

hideDiv(’throbber’);

//unBlockScreen();

}

}

function showDiv(id) { //show a div

var obj=xgetHelper(id);

if(obj!=null){ obj.style.display=”block”;}

//xrestart();

}

function hideDiv(id) { //hide a div

var obj=xgetHelper(id);

if(obj!=null){ obj.style.display=”none”;}

//xrestart();

}

function popStatus(txt,title){

popit(’statusdyn’,’statusarrow’,’statusul’,’statusdiv’,txt,false,title,”);

}

function popit(dynId,arrowId,ulId,divId,txt,expand,title,cssCls){

popText(ulId,txt,title,cssCls);

showDiv(divId);

if(expand == true){

var arrowObj=xgetHelper(arrowId); if(arrowObj!=null){ arrowObj.style.backgroundPosition=’2px -106px’; }

showDiv(dynId);

}

}

function popText(id,txt,title,cssCls){

var obj = xgetHelper(id);

if(obj != null){

var oldHTML = obj.innerHTML;

var cls=”; if(cssCls!=”){ cls=’ class=”‘ + cls +’”‘; }

var htm = ‘<’+'li’+ cls +’>’ + txt + ‘<’+'/’+'li’+'>’ + oldHTML;

obj.innerHTML = htm;

}

}

function xgetHelper(id){

var obj = null;

try {

obj = document.getElementById(id);

} catch(z) {

var dummy=alert(”Error:” + z);

}

return obj;

}

function arrowTog(objectID,arrow) {

var obj = xgetHelper(objectID);

if(obj!=null){

if (obj.style.display ==’block’) {

arrow.style.backgroundPosition = ‘2px -21px’;}

else {arrow.style.backgroundPosition = ‘2px -106px’;}

objTog(objectID);

}

return false;

}

function objTog(objectID) {

var obj = xgetHelper(objectID);

if(obj!=null){

if (obj.style.display ==’block’) obj.style.display=’none’;

else {obj.style.display=’block’;}

}

return false;

}

function headTog(objectID,arrow) {

var obj = xgetHelper(objectID);

if(obj!=null){

if (obj.style.display ==’block’) {

arrow.style.borderBottomWidth = ‘1px’;}

else {arrow.style.borderBottomWidth = ‘0px’;}

arrowTog(objectID,arrow);

}

return false;

}

/*

* adds timestamp to URLs to make them unique

* @param URL String

*/

function uniqueUrl(x){

return urlAppender(x,’.cache’,xmillis());

}

/*

* helps to add parms to the url

* @param URL String

* @param aname String

* @param avalue String

*/

function urlAppender(x,aname,avalue){

var delim = “?”;

if(x.indexOf(”?”) >=0) { delim = “&”; }

return x + delim + aname + ‘=’ + avalue;

}

function xload(){

hideDiv(’throbber’);

xbusy=false;

}

function testAjax(obj){

var callback=function(){ ajaxResponse(obj,null,’testAjax’); }

var x = ajaxObjNoCache(obj,’/ajax.php’,true,callback);

}

function testAjaxParms(obj){

var callback=function(){ ajaxResponse(obj,null,’testAjaxParms’); }

var x = ajaxObjNoCache(obj,’/ajax.php?testing=Y’,true,callback);

}

function testAjaxXSS(obj){

var callback=function(){ ajaxResponse(obj,null,’testAjaxXSS’); }

var x = ajaxObjNoCache(obj,otherHost+’/ajax.php’,true,callback,otherHost);

}

function testAjaxHook(obj){

var hook=function(){ customAjaxHook(obj,’ajaxhookTestMessageObect’); }

var callback=function(){ ajaxResponse(obj,hook,’testAjaxHook’); }

var x = ajaxObjNoCache(obj,’/ajax.php’,true,callback);

}

function testAjaxHookXSS(obj){

var hook=function(){ customAjaxHook(obj,’ajaxhookXSSMessageObect’); }

var callback=function(){ ajaxResponse(obj,hook,’testAjaxHookXSS’); }

var x = ajaxObjNoCache(obj,otherHost+’/ajax.php’,true,callback);

}

/**

* This is a custom implemenation, the customObj COULD be used for anything (perhaps delay measurement!)

* @param obj – the clicked item

* @param customObj – user defined

*/

function customAjaxHook(obj,customObj){

var xml = xhr.responseXML;// NOTE: xhr.responseText is also valid

var tmp = ‘DEMO customAjaxHook [' + customObj + ']\n’ + xml;

alert(tmp);

}

</script>

<style type=”text/css”>

.busy { color:red; }

.idle { color:black; }

</style>

</head>

<body onload=”xload();”><!– onbeforeunload=”alert(’before’);” onunload=”alert(’after’);” –>

<div id=”throbber”>WORKING!</div>

<div id=”statusdiv” class=”dyn” style=”display:none;”>

<h3><a id=”statusarrow” onclick=”headTog(’statusdyn’,this);” href=”javascript:void(0);”>Status</a></h3>

<fieldset id=”statusdyn” style=”display:block;background-color:#ffffcc;”>

<div id=”statusBox” class=”box”>

<ul id=”statusul” class=”error”>

<li id=”ajaxStatus” style=”list-style:none;display:none;”>FILLER</li>

</ul>

</div>

</fieldset>

</div>

<h3><a href=”javascript:void(0);” onclick=”testAjax(this);”>TEST</a></h3>

<h3><a href=”javascript:void(0);” onclick=”testAjaxParms(this);”>TESTPARMS</a></h3>

<h3><a href=”javascript:void(0);” onclick=”testAjaxXSS(this);”>TESTXSS</a></h3>

<h3><a href=”javascript:void(0);” onclick=”testAjaxHook(this);”>TESTHOOK</a></h3>

<h3><a href=”javascript:void(0);” onclick=”testAjaxHookXSS(this);”>TESTHOOKXSS</a></h3>

<p><a href=”index.php”>RELOAD</a></p>

</body>

</html>

Response program (ajax.php)

<?php

header(”Cache-Control: no-store”);

header(”Charset: UTF-8″);

header(”Content-Type: text/xml”);

echo(”<?xml version=\”1.0\” encoding=\”UTF-8\”?>\n”);

?>

<test><?php echo( gmdate(”D, d M Y H:i:s”) ) ?> </test>

What are the MSIE Bugs you might ask… these are all in the ActiveX implementation of XmlHttpRequest, they are:

  1. Caching – for some reason, unless you define a ‘unique’ URL for each request, MSIE6 will respond from the cache, even if the server is unreachable!
  2. XSS – I discussed this above, MSIE6 will allow you to connect to ANY HOST with AJAX!
  3. Memory leak – if you don’t nullify the XHR object (for MSIE6), the application will leak memory.

Cheers!

MSIE’s flawed SSL implementation

Tuesday, July 10th, 2007

This has been quite frustrating. It seems that Microsoft has again ventured from complying with the industry web standards in this space too!

The comments from the Apache HTTP 2.x ‘http-ssl.conf’ files say it all:

#   SSL Protocol Adjustments:
#   The safe and default but still SSL/TLS standard compliant shutdown
#   approach is that mod_ssl sends the close notify alert but doesn't wait for
#   the close notify alert from client. When you need a different shutdown
#   approach you can use one of the following variables:
#   o ssl-unclean-shutdown:
#     This forces an unclean shutdown when the connection is closed, i.e. no
#     SSL close notify alert is send or allowed to received.  This violates
#     the SSL/TLS standard but is needed for some brain-dead browsers. Use
#     this when you receive I/O errors because of the standard approach where
#     mod_ssl sends the close notify alert.
#   o ssl-accurate-shutdown:
#     This forces an accurate shutdown when the connection is closed, i.e. a
#     SSL close notify alert is send and mod_ssl waits for the close notify
#     alert of the client. This is 100% SSL/TLS standard compliant, but in
#     practice often causes hanging connections with brain-dead browsers. Use
#     this only for browsers where you know that their SSL implementation
#     works correctly.
#   Notice: Most problems of broken clients are also related to the HTTP
#   keep-alive facility, so you usually additionally want to disable
#   keep-alive for those clients, too. Use variable "nokeepalive" for this.
#   Similarly, one has to force some clients to use HTTP/1.0 to workaround
#   their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
#   "force-response-1.0" for this.

SetEnvIf User-Agent ".*MSIE.*" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0

A little further research indicates that MSIE6 has (probably) partially fixed this (the HTTP/1.0 & KeepAlive issues), so the updated config should use a Regular Expression to look like…

SetEnvIf User-Agent ".*MSIE [1-5].*"
 nokeepalive ssl-unclean-shutdown
 downgrade-1.0 force-response-1.0
SetEnvIf User-Agent ".*MSIE [6-9].*"
 ssl-unclean-shutdown

Related Information:

Cheers!

MSIE6 CSS issue ‘dotted’ behaves like ‘dashed’

Monday, July 9th, 2007

Another fix in MSIE7 (broken before), ‘dotted’ is now implemented, in MSIE6 dotted had the same visual representation as ‘dashed’.

This explains why you might expect to see a line of “……” that appear to be “——”, even when you’re absolutely positive that you’re CSS is correct!
CSS:

border:1px dotted #fff;

HTML Example:

<html>
<head>
<title>dotted-dashed Example</title>
<style type=”text/css”>
fieldset {background-color:#fcfcfc;
width:95%;
padding:15px 10px 0 10px;margin:0 0 20px 0;
border:1px solid #999;
border-top-width:2px;
overflow:hidden;}
fieldset div.buttons {clear:both; padding-top:10px;padding-bottom:10px;margin:3px 0 0 0;border-top:1px dotted #b5b5b5;text-align:left;}
</style>
</head>
<body>
<fieldset>
Some form fields go here…
<div class=”buttons”>
Some buttons go here…
</div>
</fieldset>
</body>
</html>

Cheers!

Adding Support for ‘disabled’ OPTION tags in MSIE

Friday, June 22nd, 2007

This is a very annoying bug/oversight in MSIE (including the recently released MSIE7!).

For some reason, Microsoft didn’t implement the ‘disabled’ attribute on <option> tags.
All other modern (even the old Netscape 4.x) browsers support this, why would they not do the same.
This is probably for the same reason that all versions of MSIE (prior to MSIE7) left the rendering of the SELECT tag to the operating system itself, above the browser HTML.
Thankfully, you can still access the attribute on the DOM element with javascript!

My solution has evolved over time, here’s the current release code.

To emulate this behavior in MSIE, you’ve got several different challenges to overcome.

  1. You must ‘persist’ the current value of the SELECT so that you can ‘restore’ it when the user chooses a disabled field, I do this during the onload event.
  2. When the ‘onchange’ event for the SELECT tag is invoked, the currently selected OPTION’s attributes must be read and checked.
  3. If the selected OPTION is ‘disabled’, then the previous value must be restored.
  • As this solution only stores one value per SELECT, the ‘multiple’ SELECT is not currently supported.
  • In the future I’ll probably do some ‘event injection’ so that the HTML itself is cleaner. Problem is that in more complex solutions like ‘dependent dropdowns’ this becomes tricky.
  • The [if IE] ‘comment’ is critical as it is conditional logic supported only in MSIE and simplifies what was previously done via various ‘browser-sniffing’ tricks.
  • The example code in this example excludes the CDATA escapes and several tags required for valid XHTML for brevity.
  • FYI, the example also contains the MSIE background-image cache fix discussed in a previous post.

<!DOCTYPE >
<html>
<head>
<script type=”text/javascript”>
var isMSIE=false;
<!–[if IE]>
<script type=”text/javascript”>
isMSIE=true;
</script>
<script src=”/js/grv-msie-hacks.js” type=”text/javascript”></script>
<![endif]–>

<script type=”text/javascript”>
function xload(){
if(isMSIE){
grvMsieInitHacks();
}
}
function xchange(obj){
// note: javascript emulation of <option disabled…> (for MSIE)
if(isMSIE){
grvMsieSelectFix_restore(obj);
}
}
</script>
</head>

<body onload=”xload();”>

<form action=”#” method=”GET”>
<select name=”s” id=”s” size=”1″ onchange=”xchange(this);”>
<option value=”n1″>Normal1</option>
<option value=”di” disabled=”disabled”>Dis</option>
<option value=”n1″>Normal2</option>
</select>
</form>
</body>
</html>

JavaScript file (grv-msie-hacks.js):

/*
* Code library to add several ‘broken’ features in MSIE 6 and 7
* @version $Id: $
*/
function grvMsieInitHacks(){
grvMsieCacheFix();
grvMsieSelectFix_init()
}
function grvMsieCacheFix(){
try{
document.execCommand(”BackgroundImageCache”,false,true);
}catch(e)
{}
}
/* Added new functions to support <option disabled…> emulation
*
* First part, necessary for <body onLoad…>
* builds array of all initial selections for <select>s on page (for LT or EQ MSIE7)
* WAS: disabledOptionEmulation();
*/
function grvMsieSelectFix_init() {
if (document.getElementsByTagName) {
var allSelects = document.getElementsByTagName(”select”); // build array of all <select> tags
if (allSelects.length > 0) { // if array has values…
window.allSelectsCurrentIndex = new Array(); // new array to hold initial selections
for (var i=0, individualSelect; individualSelect = allSelects[i]; i++) { // crawl through all <select> tags
individualSelect.onfocus = function(){ window.allSelectsCurrentIndex[this.id] = this.selectedIndex; } // fill array with selectedIndex values
}
}
}
}

/* companion code for grvMsieSelectFix_init()
* resets <option> selection if disabled to last good selection (for LT or EQ MSIE7)
* WAS: restoreSelection(inOptionChoice)
*/
function grvMsieSelectFix_restore(inOptionChoice) {
if (inOptionChoice.options[inOptionChoice.selectedIndex].disabled){
// if new choice is disabled…
inOptionChoice.selectedIndex = window.allSelectsCurrentIndex[inOptionChoice.id]; // deny selection, revert back to last ‘known good’ choice (typically, the initial selection at page load)
} else { // if new choice isn’t disabled…
window.allSelectsCurrentIndex[inOptionChoice.id] = inOptionChoice.selectedIndex; // update array so last ‘known good’ choice is now the latest user selection
}
}

Hopefully, Microsoft will get around to fixing this correctly some day… maybe for MSIE8!

MSIE Conditional code

Wednesday, May 16th, 2007

This is not so much as a MSIE bug, but rather a non-standard “feature” (added in MSIE 5.5) that is often helpful when constructing websites that you try to build with valid XHTML and CSS. As all non-Microsoft browsers will see these as simple
HTML markup comments, it gives you the flexibility to deal with the inconsistencies and quicks in the various versions of MSIE. This is particularly important for the numerous changes introduced with MSIE7.

I’ve tested this with <style />, <script /> and <meta /> tags, but wouldn’t doubt that it works anywhere (but don’t see any typical situations for that!)

Some simple instructions:

  1. Start with an HTML comment
  2. Add the opening brackets, so it resembles <!–[if ...]>
  3. Add the closing brackets too… <![endif]–> (don’t forget that extra less than and bang/exclamation point!)
  4. Add the versioning info, this should be pretty obvious, but i’ll list the most common ones.
    IE 7 = MSIE7
    IE 6 = MSIE6
    IE 5.5000 = MSIE 5.5
  5. Some modifiers, (should you want a range of versions):
    lt = Less Than
    gt = Greater Than
  6. Make sure that the body content of the tag (which now resembles an HTML comment) is coded.
  7. That’s it, now be sure to test for expected behaviors!

Some Examples:

<!–[if IE 6]>
<style type=”text/css”>
/* <![CDATA[ */
html {
overflow-y: scroll;
}
/* ]]> */
</style>
<![endif]–><!–[if lt IE 5.5000]><style type=”text/css”>@import “/css/IE50Fixes.css”;</style><![endif]–>
<!–[if IE 5.5000]><style type=”text/css”>@import “/css/IE55Fixes.css”;</style><![endif]–>
<!–[if IE 6]><style type=”text/css”>@import “/css/IE60Fixes.css”;</style><![endif]–>
<!–[if IE 7]><style type=”text/css”>@import “/css/IE70Fixes.css”;</style><![endif]–>
<!–[if lt IE 7]><script type=”text/javascript” src=”/js/IEFixes.js”></script>
<meta http-equiv=”imagetoolbar” content=”no” /><![endif]–>

Cheers!