// ==UserScript==
// @name Zoom text only
// @author Nicolas Mendoza <nicolasm@opera.com>
// @namespace http://people.opera.com/nicolasm/
// @version 1.0
// @description Let's you zoom only text elements
// @ujs:category general: enhancements
// @ujs:published 2005-08-30 22:00
// @ujs:modified 2007-05-09 11:30
// @ujs:documentation http://userjs.org/scripts/general/enhancements/zoom-text
// @ujs:download http://userjs.org/scripts/download/general/enhancements/zoom-text.js
// ==/UserScript==
  
/*
   Public Domain 
*/


// Main function - runs when window is loaded.
document.addEventListener("DOMContentLoaded",function(e){ 
  // wether it should set the size of a page to what it had last time
  var REMEMBER_SITE_SIZE = 1;

  // minimum font size to zoom down to.
  var MIN_FONT_SIZE = 8;

  // table of elements in page
  var table = new Array();
  
  // cur zoom level at any given time
  var curRelSize = 0;

  if (document.body) {
    // only run if it's html-ish

    // restore previously set size (if any)
    if (REMEMBER_SITE_SIZE) {
      if (getCookie("curRelSize")) {
        startTraversing(document,parseInt(getCookie("curRelSize")),"load");
      }
    }

    appendControls();    
    updateZoomHeader();


    function startTraversing(element,relSize) {
      table = new Array();

      // if called without argument reset current zoom 
      if (!parseInt(relSize)) {
        if (relSize == 0){
          setCookie("curRelSize",0);
        }
        relSize = 0;
        curRelSize = 0;
      } else {
        curRelSize += parseInt(relSize,10)?parseInt(relSize,10):0;
        setCookie("curRelSize",curRelSize);
      }

      index = 0;

      // recursively traverse page and fetch current font-sizes
      traverse(element);

      if (relSize) {
        // Calculate and set new font-size for every element ...
        for(var i=0; temp=table[i++];) {
          temp[0].style.fontSize = ((parseInt(temp[1],10)+parseInt(relSize))>MIN_FONT_SIZE?(parseInt(temp[1],10)+parseInt(relSize)):MIN_FONT_SIZE)+"px";
        }
      } else {
        // ... if not, set values to "" which should reset them to the page's default.
        for(var i=0; temp=table[i++];) {
        temp[0].style.fontSize = "";
        }
      }

      updateZoomHeader();
    }

    function appendControls(){
      // create the controls, basically a frame with a header, footer, zoom in and zom out, plus an icon.
      var zoomControls = document.createElement("table");
      var zoomIn = document.createElement("td");
      var zoomOut = document.createElement("td");

      zoomControls.id = "zoomControls";
      zoomControls.style.position = "fixed";
      zoomControls.style.fontSize = "1em";
      zoomControls.style.fontFamily = "sans-serif";
      zoomControls.style.bottom = 0;
      zoomControls.style.right = 0;
      zoomControls.style.width = "6em";
      zoomControls.style.height = "6em";
      zoomControls.style.margin = "0.5em";
      zoomControls.style.opacity = "0.7";
      zoomControls.style.display = "none";
      zoomControls.style.padding = "0.25em";
      zoomControls.style.zIndex = "10010";
      zoomControls.style.backgroundColor = "white";
      zoomControls.style.border = "1px solid black";

      zoomIcon = document.createElement("div");
      zoomIcon.id = "zoomIcon";
      zoomIcon.innerText = "\u25F1";
      zoomIcon.style.margin = "0.2em";
      zoomIcon.style.padding = "0";
      zoomIcon.style.zIndex = "1001";
      zoomIcon.style.lineHeight = "1em";
      zoomIcon.style.bottom = 0;
      zoomIcon.style.right = 0;
      zoomIcon.style.textAlign = "center";
      zoomIcon.style.fontSize = "1em";
      zoomIcon.style.position = "fixed";

      // when clicking icon, fire up controls (if they aren't already up (using visible attribute as lock)
      zoomIcon.addEventListener("click",function() { 
        if (zoomControls.visible) { 
          zoomControls.style.display = "none";
          zoomControls.visible = 0;
        } else {
          zoomControls.style.display = "table";
          zoomControls.visible = 1;    
        }
      },false);

      zoomHeader = document.createElement("td");
      zoomHeader.style.fontWeight = "bold";
      zoomHeader.colSpan = "2";
      zoomHeader.id = "zoomHeader";
      zoomHeader.innerText = "Zoom:";
      zoomHeader.style.textAlign = "center";
      zoomHeader.style.fontSize = "0.5em";
      zoomHeader.style.lineHeight = "1em";
      zoomHeader.style.margin = "0";
      zoomHeader.style.padding = "0";
      zoomHeader.style.marginBottom = "0.25em";

      zoomFooter = document.createElement("td");
      zoomFooter.style.fontWeight = "bold";
      zoomFooter.style.fontSize = "1em";
      zoomFooter.colSpan = "2";
      zoomFooter.innerText = "Reset";
      zoomFooter.style.textAlign = "center";
      zoomFooter.style.lineHeight = "1em";
      zoomFooter.style.margin = "0";
      zoomFooter.style.padding = "0.25em";
      zoomFooter.style.marginTop = "0.5em";
      zoomFooter.style.backgroundColor = "white";
      zoomFooter.style.border = "1px solid grey";
      // when clicking reset, set zoom level to 0, hide zoom controls box
      zoomFooter.onclick = function() { startTraversing(document,0); zoomControls.visible = 0; zoomControls.style.display = "none"; };
  
      zoomIn.innerText = "+";
      zoomIn.style.textAlign = "center";
      zoomIn.style.lineHeight = "1.3em";
      zoomIn.style.width = "50%";
      zoomIn.style.fontSize = "1.5em";
      zoomIn.style.backgroundColor = "white";
      zoomIn.style.border = "1px solid grey";
      zoomIn.onclick = function() { startTraversing(document,1); }

      zoomOut.innerText = "-";
      zoomOut.style.textAlign = "center";
      zoomOut.style.lineHeight = "1.3em";
      zoomOut.style.width = "50%";
      zoomOut.style.fontSize = "1.5em";
      zoomOut.style.backgroundColor = "white";
      zoomOut.style.border = "1px solid grey";
      zoomOut.onclick = function() { startTraversing(document,-1); }


      // using a table for layout, less implications...
      var headerRow = document.createElement("tr");
      headerRow.appendChild(zoomHeader);
      zoomControls.appendChild(headerRow);

      var zoomRow = document.createElement("tr");
      zoomRow.appendChild(zoomIn);
      zoomRow.appendChild(zoomOut);
      zoomControls.appendChild(zoomRow);

      var footerRow = document.createElement("tr");
      footerRow.appendChild(zoomFooter);
      zoomControls.appendChild(footerRow);

      document.body.appendChild(zoomControls);
      document.body.appendChild(zoomIcon);

      // force control fonts to be the initial size
      var curFontSize = getComputedStyle(zoomControls,'').getPropertyValue("font-size");
      zoomControls.style.fontSize = curFontSize;
      var curFontSize = getComputedStyle(zoomIcon,'').getPropertyValue("font-size");
      zoomIcon.style.fontSize = curFontSize;

    }

    function updateZoomHeader() {
      // update control and icon zoom level text
      if (zoomHeader = document.getElementById("zoomHeader")) {
        var curZoomFactor = ((getCookie("curRelSize") && getCookie("curRelSize").match(/\d+/))?getCookie("curRelSize"):"0");
        zoomHeader.innerText = "Zoom: " + (curZoomFactor>0?"+":"")+curZoomFactor;
        if (curZoomFactor != 0) {
          document.getElementById("zoomIcon").innerText = (curZoomFactor>0?"+":"")+curZoomFactor+"\u25F1";
        } else {
          document.getElementById("zoomIcon").innerText = "\u25F1";
        }
      }
    }

    function traverse(element) {
      var i = 0;
      while(curElem=element.childNodes[i++]) {

        // bail out if we reach our control element (at bottom of DOM anyway)
        if (curElem.id == "zoomControls") { return; }
 
        // only process (and traverse possible children) if nodeType is Element or Document 
        if (((curElem.nodeType == 1) || (curElem.nodeType == 9)) && (curElemStyle = getComputedStyle(curElem,''))) {
          if (curElemFontSize = curElemStyle.getPropertyValue("font-size")) {
            // get property value and store for later
            table[index] = [curElem,curElemFontSize];
            index++;
          }
          traverse(curElem);
        }
      }
    }

    function setCookie(cookieName, cookieValue) {
      var expires = "";
      var path = "/";
      var domain = location.hostname;
      var secure = null;
      document.cookie = escape(cookieName) + '=' + escape(cookieValue)
        + (expires ? '; EXPIRES=' + expires.toGMTString() : '')
        + (path ? '; PATH=' + path : '')
        + (domain ? '; DOMAIN=' + domain : '')
        + (secure ? '; SECURE' : '');
    }
   
    function getCookie(name){
      var dc = document.cookie;
      var prefix = name + "=";
      var begin = dc.indexOf("; " + prefix);
      if (begin == -1){
        begin = dc.indexOf(prefix);
        if (begin != 0) return null;
      } else {
        begin += 2;
      }
      var end = document.cookie.indexOf(";", begin);
      if (end == -1){
        end = dc.length;
      }
      return unescape(dc.substring(begin + prefix.length, end));
    }    // A complementary function to unwrap a cookie.




  } // only run if hmtl-ish
},false);




