Wikipedia:WikiProject User scripts/Scripts/TwoColumns.js

/* TwoColumns, version [0.0.5]
Documentation: Wikipedia:WikiProject User scripts/Scripts/TwoColumns
*/

if (mw.config.get('wgAction') == 'view' && mw.config.get('wgCanonicalNamespace')=='')  addOnloadHook(fr_format)

var fr_columns;
var imgRegExp= /(thumb|frame)/i;
var trashNodes;
function fr_format() {
     fr_addButton();
     fr_columns=fr_getCookie ('fr_columns'); if (! (0<1*fr_columns)) fr_columns=1;
     trashNodes=new Array;
     if (fr_columns==1) return;
     var bodyContent= document.getElementById('bodyContent');
     if (! bodyContent || ! bodyContent.innerHTML || bodyContent.innerHTML=='') return;

     var allNodes=bodyContent.childNodes;
     var group=new Array, node, groupArea=0;
     for (var i = allNodes.length-1; 0 <= i; i--) {
       node=allNodes[i];
       var pre= node.tagName=="PRE" || (node.tagName=="DIV" && node.childNodes[1] && node.childNodes[1].tagName=='PRE') 
       if (node.nodeValue && node.nodeValue.substr(0,1)=="\n") {

//       } else if (node.tagName=="p" || node.tagName=="P" || node.tagName=="ul" || node.tagName=="UL" ) {
       } else if (node.tagName && node.tagName.substr(0,1) !="H" && node.tagName.substr(0,5) !="TABLE" && node.tagName.substr(0,5) !="SCRIPT" && node.style.MozColumnCount<=0 && ! pre) { //everything but H
         group.push(node);
         groupArea += node.clientHeight * node.clientWidth;
       } else {
          if (node.tagName && node.tagName.substr(0,1) =="H") {
            var prevNode=node;
            var count=0;
            do {
              do {
                prevNode=prevNode.previousSibling;count++;
              } while (prevNode && (prevNode.clientHeight==0 || prevNode.clientHeight=== undefined));
              if (prevNode && prevNode.className && imgRegExp.test(prevNode.className)) {
                group.push(prevNode); i=i-count;count=0;
                groupArea += prevNode.clientHeight * prevNode.clientWidth;
              }
            } while (prevNode && prevNode.className && imgRegExp.test(prevNode.className))
         }
         if (0<group.length) fr_layoutDiv (group, groupArea);
         group=new Array; groupArea=0;
       }
     }
     
     for (var i=trashNodes.length-1; 0<=i;i--) {
      trashNodes[i].parentNode.removeChild(trashNodes[i]);
     }
}

function fr_layoutDiv (aGroup, groupArea) {
  var contentWidth=aGroup[0].parentNode.clientWidth;
  if (groupArea < 100 * contentWidth) return;
  var start=0, stop=aGroup.length-1;
  var pieces=Math.round(groupArea / (window.innerHeight * contentWidth)+0.5);
  var targetArea=groupArea/ pieces; 
  var targetHeight= (pieces==1) ? window.innerHeight : targetArea / contentWidth;
  var divArea=0, first=true, imgHeight=0;
  for (var i = stop; 0 <= i; i--) {
     if (aGroup[i].className && imgRegExp.test(aGroup[i].className)) {
       imgHeight +=aGroup[i].clientHeight;
     }
    divArea += aGroup[i].clientHeight * aGroup[i].clientWidth;
    if (targetArea < divArea || targetHeight < imgHeight) { 
      fr_createDiv(aGroup, i+1,stop,fr_columns,first); 
      first=false;
      stop=i; 
       if (aGroup[i].className && imgRegExp.test(aGroup[i].className)) {
         imgHeight =aGroup[i].clientHeight;
       } else {
         imgHeight =0;
       }
      divArea = aGroup[i].clientHeight * aGroup[i].clientWidth;
    }
  }
  if (0<=stop) {
    divArea=0;
    for (i=stop; 0<=i;i--) {
      divArea += aGroup[i].clientHeight * aGroup[i].clientWidth;
    }
    if (100 * contentWidth < divArea) fr_createDiv(aGroup,0,stop,fr_columns,first);
  }
}


function fr_createDiv(aGroup, start, stop, columns, noHR) { // start, stop: inclusive, (counting in the Group !), e.g. 0..3
  if (stop<start) return;
  var newDiv = document.createElement('div');
  newDiv.style.MozColumnCount=columns;
  newDiv.style.MozColumnGap='2em';
  newDiv.style.textAlign='justify';
  var tooBig=false;
  for (var i = stop; start <= i; i--) { // first append the thumb
      if (imgRegExp.test(aGroup[i].className)) {
        newNode=aGroup[i].cloneNode(true);
        newDiv.appendChild(newNode);
        if (imgRegExp.test(aGroup[i].className) && aGroup[i].parentNode.clientWidth / columns < newNode.clientWidth) {
          tooBig=true;
        }
      }
  }
  for (var i = stop; start <= i; i--) {
      if (!imgRegExp.test(aGroup[i].className)) {
        newNode=aGroup[i].cloneNode(true);
        newDiv.appendChild(newNode)
      }
  }
  if (window.innerHeight < newDiv.clientHeight || tooBig /* window.innerHeight-10 < imgHeight */) { // safety valve: too big 
     return;
  }
  aGroup[start].parentNode.insertBefore(newDiv,aGroup[start]);
  if (!noHR) {
      var HR=document.createElement('HR');
      newDiv.parentNode.insertBefore(HR,newDiv);
  }
  for (var i = stop; start <= i; i--) { 
      trashNodes.push(aGroup[i]); //newDiv.parentNode.removeChild(aGroup[i])
  }
}

// Button to increment the number of columns

function fr_addButton () {
    var node = document.getElementById('p-personal');
    if ( !node ) return null;
    node = node.getElementsByTagName( "ul" )[0];
    if ( !node ) return null;

    var link = document.createElement( "img" );
  link.src= 'http://upload.wikimedia.org/wikipedia/commons/f/f5/FastReader_logo.PNG';
    link.appendChild( document.createTextNode( "FastReader" ) );
    link.onclick = function() {fr_next()};

    var item = document.createElement( "li" );
    item.appendChild( link );

    link.setAttribute( "title", 'FastReader' );

    node.appendChild( item );  // IE compatibility (?)
}

function fr_next() {
  fr_columns= fr_columns % 2 +1;
  fr_setCookie('fr_columns', fr_columns);
  document.location.reload();
};

// Cookie routines to save the number of columns

function fr_getCookie (cookieName) {

    var cookie = ' ' + document.cookie;
    var search = ' ' + cookieName + '=';
    var cookieValue = '';
    var offset = 0;
    var end = 0;
    offset = cookie.indexOf(search);
    if (offset != -1) {
        offset += search.length;
        end = cookie.indexOf(';', offset)
        if (end == -1) {
            end = cookie.length;
        }
        cookieValue = cookie.substring(offset, end);
        cookieValue = cookieValue.replace(/\\+/g, ' ');
        cookieValue = decodeURIComponent(cookieValue);
    }
    return(cookieValue);
}

function fr_setCookie (name, value) {
    var cookie = name + '=' + encodeURIComponent(value);
    var cookieExpire = new Date();
    expires = cookieExpire.setTime(cookieExpire.getTime() + 30 * 24 * 60 * 60 * 1000);
    expires = cookieExpire.toUTCString();
    cookie += '; expires=' + expires;
    document.cookie = cookie;
    return;
}