Setting text property of MSXML Node object destroys its children

The Microsoft's documentation of the IXMLDOMNode.text property skips an important detail: if the node has non-text children and you set its text property, it loses all children. The node.text = string statement deletes all children and creates a single IXMLDOMText child.

Manipulating innerHtml disables event handlers set with JavaScript

If you manipulate innerHtml property of an HTML element with children and you've previously set any event handlers on those children with JavaScript (not with onxxxx attributes), they're gone (as the changing of innerHTML effectively erases all the children and recreates them). If you want to retain children event handlers, you should add new children with DOM calls (node.appendChild).

For example, if you set up onclick handler like this:
<div id="outerDiv">
<p id="para1">Click here</p>
</div>
<script>
var x = document.getElementById("para1");
x.onclick = function () { alert("Clicked"); }
</script>

... the onclick handler will stop working if you change innerHtml of outerDiv, for example to add another paragraph:
<script>
var outerDiv = document.getElementById("outerDiv") ;
outerDiv.innerHtml += "<p id='para2'>Another paragraph</p>" ;
</script>

Browser-independent Object Fading

The author of this article (courtesy of InformIT.com) did a great job documenting ways to fade an object in a wide range of incompatible browser implementations. Highly recommended.

Detecting cached CSS style sheets

Have you ever deployed an improved version of your web pages, just to find out that the visitors have to press Ctrl-R (Reload) to get them right as their browsers have cached the Cascaded Style Sheet (.css) files used in your web site. Renaming the style sheet files every time you change them definitely solves the problem, but requires changing all the related web pages as well.
It's infinitely better if you can detect that the style sheets are cached by the browser (and thus obsolete) and respond with a forced reload. In the simplest case (more about version control in another post), you can detect that the style sheets referenced by your web page are missing a class (or id) selector that you need. Include the browser-independent stylesheet library in your web page and add the following code somewhere in the body of the page:
<script>if (xHasStyleSheets() && ! xHasStyleSelector('.myClass')) location.reload(true);</script>
If you're looking for an ID selector,  replace '.myClass' with '#myID'.

Detecting out-of-date JavaScript libraries

A major challenge of writing rapid-changing AJAX applications is the asynchronous nature of browser page fetching. It's almost impossible to ensure that the browser will fetch the new version of all the components of your application (for example, JavaScript library) when it changes on the server.

You might solve this problem by renaming the JavaScript libraries (.js files) every time you make a significant change that could break the client-side application. While being bullet-proof, this approach requires republishing of all pages referencing the renamed library (which could be your entire web site).

It's way better to include the cache-checking code in your application:
  • Within your library, set a global variable (or a property of window object) to library's version number. The version number could be an increasing number, the date the change was made or (ideally) a version number from your source code control system (SCCS for Unix fans or Visual SourceSafe for Windows)
  • In every web page that relies on particular functionality of that library, check the version number and force a reload if there's a mismatch.
For example, in your JavaScript file, include a statement setting the version number ...
window.version_MyLibrary = 20060810; // library last changed on August 10th, 2006
... and at the beginning of the web pages requiring new library functionality, check the version number just after the library has been included with the <script> tag:
<script>if (window.version_MyLibrary < 20060810) location.reload(true);</script>
So, if your web page detects that the library included during the load process has an incompatible version number (due to cached version being used by the browser), it forces a hard reload, downloading all components from the web server.

Browser-independent style sheet Javascript code

In a recent project, I had to check whether the stylesheets attached to a document contain a particular class name. The X library (www.cross-browser.com) does not contain anything handling the stylesheets, so here's the necessary code (works in Internet Explorer and Firefox, Opera is broken).
 
Usage example: 
xHasStyleSelector('.menuButton') will return true if any of the stylesheets attached to the document (including the inline stylesheets) contain definition of .menuButton.

// browser-independent stylesheet handling
// Copyright 2006 Ivan Pepelnjak (
www.zaplana.net)
// Distributed under the terms of the GNU LGPL
 
//
// xGetStyleSheetFromLink - extracts style sheet object from the HTML LINK object (IE vs. DOM CSS level 2)
//
function xGetStyleSheetFromLink(cl) { return cl.styleSheet ? cl.styleSheet : cl.sheet; }
 
//
// xGetCSSRules - extracts CSS rules from the style sheet object (IE vs. DOM CSS level 2)
//
function xGetCSSRules(ss) { return ss.rules ? ss.rules : ss.cssRules; }
 
//
// xHasStyleSheets - checks browser support for stylesheet related objects (IE or DOM compliant)
//
function xHasStyleSheets() {
  return document.styleSheets ? true : false ;
}
   
//
// xTraverseStyleSheet (stylesheet, callback)
//   traverses all rules in the stylesheet, calling callback function on each rule.
//   recursively handles stylesheets imported with @import CSS directive
//   stops when the callback function returns true (it has found what it's been looking for)
//
// returns:
//   undefined - problems with CSS-related objects
//   true      - callback function returned true at least once
//   false     - callback function always returned false
//
function xTraverseStyleSheet(ss,cb) {
  if (!ss) return false;
  var rls = xGetCSSRules(ss) ; if (!rls) return undefined ;
  var result;
  
  for (var j = 0; j < rls.length; j++) {
    var cr = rls[j];
    if (cr.selectorText) { result = cb(cr); if (result) return true; }
    if (cr.type && cr.type == 3 && cr.styleSheet) xTraverseStyleSheet(cr.styleSheet,cb);
  }
  if (ss.imports) {
    for (var j = 0 ; j < ss.imports.length; j++) {
      if (xTraverseStyleSheet(ss.imports[j],cb)) return true;
    }
  }
  return false;
}
   
//
// xTraverseDocumentStyleSheets(callback)
//   traverses all stylesheets attached to a document (linked as well as internal)
//   
function xTraverseDocumentStyleSheets(cb) {
  var ssList = document.styleSheets; if (!ssList) return undefined;
     
  for (i = 0; i < ssList.length; i++) {
    var ss = ssList[i] ; if (! ss) continue;
    if (xTraverseStyleSheet(ss,cb)) return true;
  }
  return false;
}
 
//
// xHasStyleSelector(styleSelectorString)
//   checks whether any of the stylesheets attached to the document contain the definition of the specified
//   style selector (simple string matching at the moment)
//
// returns:
//   undefined  - style sheet scripting not supported by the browser
//   true/false - found/not found
//
function xHasStyleSelector(ss) {
  if (! xHasStyleSheets()) return undefined ;
 
  function testSelector(cr) {
    return cr.selectorText.indexOf(ss) >= 0;
  }
  return xTraverseDocumentStyleSheets(testSelector);
}

Improve your search engine rankings with AJAX

My article describing how to use AJAX to split navigational elements from the main page content, resulting in improve search engine ranking and reduced download time has been published on InformIT.com.