// $Id: rendering.js,v 1.2 2006/04/04 15:18:03 kmj Exp $
// © 2004 IOP Publishing Ltd. All rights reserved.


// Perform additional page rendering in JavaScript
function fixPage(pluginPath, pluginName) {
  if (!document.getElementById) return; // DOM-capable browsers have this
  mozSearch(pluginPath, pluginName);
  cssHack();
}


// Mozilla search plugin
function mozSearch(pluginPath, pluginName) {
  if (!window.sidebar) return;                  // Mozilla has this...
  if (!window.sidebar.addSearchEngine) return;  // ...and this
  var myElem = document.getElementById('mozsearch');
  if (!myElem) return;				// plugin not enabled
  var anchor = document.createElement('a');
  anchor.setAttribute('href', 'javascript:window.sidebar.addSearchEngine(\'' + pluginPath + '.src\',\'' + pluginPath + '.png\',\'' + pluginName + '\',\'Web\');');
  anchor.appendChild(document.createTextNode('Add full-text search to your Search Bar'));
  myElem.appendChild(anchor);
}


// Work around incomplete CSS2 support in Internet Explorer
function cssHack() {
  var appVer, iePos, is_minor, is_major;

  if (!document.all) return; // MSIE and Opera have this
  if (!window.ScriptEngine) return; // Only MSIE has this AFAIK ;)

  // Browser version checking code partly borrowed from webreference.com
  // XXX This code will probably catch bit-rot. You have been warned.
  appVer = navigator.appVersion.toLowerCase();
  iePos = appVer.indexOf('msie');
  if (iePos < 0) return; // Perhaps it's not MSIE after all...
  is_minor = parseFloat(appVer.substring(iePos+5,appVer.indexOf(';',iePos)));
  is_major = parseInt(is_minor);
  // alert('Version: ' + is_minor + ' <<' + navigator.appVersion + '>>');
  if (is_minor > 7.0) return; // Don't mess with future versions of IE

  // Perform our evil hackery ;)
  window.status = 'Fixing style for Microsoft Internet Explorer...';
  fixElement(document.body); // Must be 'document.body' for IE5
  window.status = 'Done';
}


// Fix the properties of a given element
// XXX These are all hard-coded. This means that if you make changes to
// XXX the stylesheet, these changes must be reflected in this script.
function fixElement(elem) {
  var node = nodeName(elem); // Get the element's node name
  // window.status = 'Fixing style for Microsoft Internet Explorer... ' + node;

  // Remove text elements (generally whitespace) that don't belong there (sigh)
  if (node.match(eval('/^[DUO]L$/'))) {
    for (c = 0; c < elem.children.length; c = c + 1) {
      if (nodeName(elem.children[c]) == '#text') {
        elem.removeChild(c);
      }
    }
  }

  // Definition terms
  else if (isClass(elem, 'no')) {
    appendText(elem, '.');
  }

  // Definition terms
  else if ((node == 'DT') && hasClass(elem, 'key') && !hasClass(elem, 'nodd')) {
    appendText(elem, ': ');
  }

  // List items
  else if ((node == 'LI') && (elem.nextSibling)) {
    if (hasClass(elem, 'nav')) { // Navigation items
      appendText(elem, ' | ');
    } else if (hasClass(elem, 'key')) { // Definition list items
      appendText(elem, ', ');
    }
  }

  // Navigation list headings
  else if ((node == 'H2') && (hasClass(elem, 'nav'))) {
    appendText(elem, ': ');
  }

  // Process child elements
  var childElem = elem.firstChild;
  while (childElem) {
    if (nodeName(childElem) != '#text')
      fixElement(childElem);
    childElem = childElem.nextSibling;
  }
  return;
}


// Prepend text to a node
function prependText(elem, str) {
  if (nodeName(elem.firstChild) == '#text') {
    elem.replaceChild(
      document.createTextNode(str + ltrim(elem.firstChild.nodeValue)),
      elem.firstChild
    );
  }
  else {
    elem.insertBefore(document.createTextNode(str), elem.firstChild);
  }
}


// Append text to a node
function appendText(elem, str) {
  if (nodeName(elem.lastChild) == '#text') {
    elem.replaceChild(
      document.createTextNode(rtrim(elem.lastChild.nodeValue) + str),
      elem.lastChild
    );
  }
  else {
    elem.appendChild(document.createTextNode(str));
  }
}


// nodeName for element; always return a string even if no nodeName exists
function nodeName(elem) {
  return elem.nodeName || '';
}


// Does this element belong to the class I'm after?
function isClass(elem, myClass) {
  if (typeof(elem.className) != 'string') { return false; }
  if (typeof(myClass) != 'string') { return false; }
  var classList = elem.className.split(' ');
  for (var i = 0; i < classList.length; i = i + 1) {
    if (myClass == classList[i])
      return true;
  }
  return false;
}


// Does this element (or an ancestor) belong to the class I'm after?
function hasClass(elem, myClass) {
  if (isClass(elem, myClass)) {
    return true;
  }
  if (elem.parentNode) {
    return hasClass(elem.parentNode, myClass);
  }
  return false;
}


// Useful functions
function ltrim(str) { return str.replace(eval('/^\\s*/'), ''); }
function rtrim(str) { return str.replace(eval('/\\s*$/'), ''); }
function trim(str)  { return ltrim(rtrim(str)); }

