Logo
doctype [?]
[strict] [loose] [none]

Util, DOM, CSS, Event Functions



Source Type:Fully formatted code - Best for understanding and editing
Source File:util.js (Right-click and "save as")
File size:18k


PLEASE SUPPORT THIS SITE! Rather than charging money for this site, I rely on donations from users to help support the site and offset development time. If you find this code useful or if it helped on your project, please consider donating. Any amount is appreciated! Thanks!
/**
 * Copyright (c)2005-2009 Matt Kruse (javascripttoolbox.com)
 * 
 * Dual licensed under the MIT and GPL licenses. 
 * This basically means you can use this code however you want for
 * free, but don't claim to have written it yourself!
 * Donations always accepted: http://www.JavascriptToolbox.com/donate/
 * 
 * Please do not link to the .js files on javascripttoolbox.com from
 * your site. Copy the files locally to your server instead.
 * 
 */
/* ******************************************************************* */
/*   UTIL FUNCTIONS                                                    */
/* ******************************************************************* */
var Util = {'$VERSION':1.06};

// Util functions - these are GLOBAL so they
// look like built-in functions.

// Determine if an object is an array
function isArray(o) {
  return (o!=null && typeof(o)=="object" && typeof(o.length)=="number" && (o.length==0 || defined(o[0])));
};

// Determine if an object is an Object
function isObject(o) {
  return (o!=null && typeof(o)=="object" && defined(o.constructor) && o.constructor==Object && !defined(o.nodeName));
};

// Determine if a reference is defined
function defined(o) {
  return (typeof(o)!="undefined");
};

// Iterate over an array, object, or list of items and run code against each item
// Similar functionality to Perl's map() function
function map(func) {
  var i,j,o;
  var results = [];
  if (typeof(func)=="string") {
    func = new Function('$_',func);
  }
  for (i=1; i<arguments.length; i++) {
    o = arguments[i];
    if (isArray(o)) {
      for (j=0; j<o.length; j++) {
        results[results.length] = func(o[j]);
      }
    }
    else if (isObject(o)) {
      for (j in o) {
        results[results.length] = func(o[j]);
      }
    }
    else {
      results[results.length] = func(o);
    }
  }
  return results;
};

// Set default values in an object if they are undefined
function setDefaultValues(o,values) {
  if (!defined(o) || o==null) {
    o = {};
  }
  if (!defined(values) || values==null) {
    return o;
  }
  for (var val in values) {
    if (!defined(o[val])) {
      o[val] = values[val];
    }
  }
  return o;
};

/* ******************************************************************* */
/*   DEFAULT OBJECT PROTOTYPE ENHANCEMENTS                             */
/* ******************************************************************* */
// These functions add useful functionality to built-in objects
Array.prototype.contains = function(o) {
  var i,l;
  if (!(l = this.length)) { return false; }
  for (i=0; i<l; i++) {
    if (o==this[i]) {
      return true;
    }
  }
};

/* ******************************************************************* */
/*   DOM FUNCTIONS                                                     */
/* ******************************************************************* */
var DOM = (function() { 
  var dom = {};
  
  // Get a parent tag with a given nodename
  dom.getParentByTagName = function(o,tagNames) {
    if(o==null) { return null; }
    if (isArray(tagNames)) {
      tagNames = map("return $_.toUpperCase()",tagNames);
      while (o=o.parentNode) {
        if (o.nodeName && tagNames.contains(o.nodeName)) {
          return o;
        }
      }
    }
    else {
      tagNames = tagNames.toUpperCase();
      while (o=o.parentNode) {
        if (o.nodeName && tagNames==o.nodeName) {
          return o;
        }
      }
    }
    return null;
  };
  
  // Remove a node from its parent
  dom.removeNode = function(o) {
    if (o!=null && o.parentNode && o.parentNode.removeChild) {
      // First remove all attributes which are func references, to avoid memory leaks
      for (var i in o) {
        if (typeof(o[i])=="function") {
          o[i] = null;
        }
      }
      o.parentNode.removeChild(o);
      return true;
    }
    return false;
  };

  // Get the outer width in pixels of an object, including borders, padding, and margin
  dom.getOuterWidth = function(o) {
    if (defined(o.offsetWidth)) {
      return o.offsetWidth;
    }
    return null;
  };

  // Get the outer height in pixels of an object, including borders, padding, and margin
  dom.getOuterHeight = function(o) {
    if (defined(o.offsetHeight)) {
      return o.offsetHeight;
    }
    return null;
  };

  // Resolve an item, an array of items, or an object of items
  dom.resolve = function() {
    var results = new Array();
    var i,j,o;
    for (var i=0; i<arguments.length; i++) {
      var o = arguments[i];
      if (o==null) {
        if (arguments.length==1) {
          return null;
        }
        results[results.length] = null;
      }
      else if (typeof(o)=='string') {
        if (document.getElementById) {
          o = document.getElementById(o);
        }
        else if (document.all) {
          o = document.all[o];
        }
        if (arguments.length==1) {
          return o;
        }
        results[results.length] = o;
      }
      else if (isArray(o)) {
        for (j=0; j<o.length; j++) {
          results[results.length] = o[j];
        }
      }
      else if (isObject(o)) {
        for (j in o) {
          results[results.length] = o[j];
        }
      }
      else if (arguments.length==1) {
        return o;
      }
      else {
        results[results.length] = o;
      }
    }
    return results;
  };
  dom.$ = dom.resolve;
  
  return dom;
})();

/* ******************************************************************* */
/*   CSS FUNCTIONS                                                     */
/* ******************************************************************* */
var CSS = (function(){
  var css = {};

  // Convert an RGB string in the form "rgb (255, 255, 255)" to "#ffffff"
  css.rgb2hex = function(rgbString) {
    if (typeof(rgbString)!="string" || !defined(rgbString.match)) { return null; }
    var result = rgbString.match(/^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*/);
    if (result==null) { return rgbString; }
    var rgb = +result[1] << 16 | +result[2] << 8 | +result[3];
    var hex = "";
    var digits = "0123456789abcdef";
    while(rgb!=0) { 
      hex = digits.charAt(rgb&0xf)+hex; 
      rgb>>>=4; 
    } 
    while(hex.length<6) { hex='0'+hex; }
    return "#" + hex;
  };

  // Convert hyphen style names like border-width to camel case like borderWidth
  css.hyphen2camel = function(property) {
    if (!defined(property) || property==null) { return null; }
    if (property.indexOf("-")<0) { return property; }
    var str = "";
    var c = null;
    var l = property.length;
    for (var i=0; i<l; i++) {
      c = property.charAt(i);
      str += (c!="-")?c:property.charAt(++i).toUpperCase();
    }
    return str;
  };
  
  // Determine if an object or class string contains a given class.
  css.hasClass = function(obj,className) {
    if (!defined(obj) || obj==null || !RegExp) { return false; }
    var re = new RegExp("(^|\\s)" + className + "(\\s|$)");
    if (typeof(obj)=="string") {
      return re.test(obj);
    }
    else if (typeof(obj)=="object" && obj.className) {
      return re.test(obj.className);
    }
    return false;
  };
  
  // Add a class to an object
  css.addClass = function(obj,className) {
    if (typeof(obj)!="object" || obj==null || !defined(obj.className)) { return false; }
    if (obj.className==null || obj.className=='') { 
      obj.className = className; 
      return true; 
    }
    if (css.hasClass(obj,className)) { return true; }
    obj.className = obj.className + " " + className;
    return true;
  };
  
  // Remove a class from an object
  css.removeClass = function(obj,className) {
    if (typeof(obj)!="object" || obj==null || !defined(obj.className) || obj.className==null) { return false; }
    if (!css.hasClass(obj,className)) { return false; }
    var re = new RegExp("(^|\\s+)" + className + "(\\s+|$)");
    obj.className = obj.className.replace(re,' ');
    return true;
  };
  
  // Fully replace a class with a new one
  css.replaceClass = function(obj,className,newClassName) {
    if (typeof(obj)!="object" || obj==null || !defined(obj.className) || obj.className==null) { return false; }
    css.removeClass(obj,className);
    css.addClass(obj,newClassName);
    return true;
  };
  
  // Get the currently-applied style of an object
  css.getStyle = function(o, property) {
    if (o==null) { return null; }
    var val = null;
    var camelProperty = css.hyphen2camel(property);
    // Handle "float" property as a special case
    if (property=="float") {
      val = css.getStyle(o,"cssFloat");
      if (val==null) { 
        val = css.getStyle(o,"styleFloat"); 
      }
    }
    else if (o.currentStyle && defined(o.currentStyle[camelProperty])) {
      val = o.currentStyle[camelProperty];
    }
    else if (window.getComputedStyle) {
      val = window.getComputedStyle(o,null).getPropertyValue(property);
    }
    else if (o.style && defined(o.style[camelProperty])) {
      val = o.style[camelProperty];
    }
    // For color values, make the value consistent across browsers
    // Convert rgb() colors back to hex for consistency
    if (/^\s*rgb\s*\(/.test(val)) {
      val = css.rgb2hex(val);
    }
    // Lowercase all #hex values
    if (/^#/.test(val)) {
      val = val.toLowerCase();
    }
    return val;
  };
  css.get = css.getStyle;

  // Set a style on an object
  css.setStyle = function(o, property, value) {
    if (o==null || !defined(o.style) || !defined(property) || property==null || !defined(value)) { return false; }
    if (property=="float") {
      o.style["cssFloat"] = value;
      o.style["styleFloat"] = value;
    }
    else if (property=="opacity") {
      o.style['-moz-opacity'] = value;
      o.style['-khtml-opacity'] = value;
      o.style.opacity = value;
      if (defined(o.style.filter)) {
        o.style.filter = "alpha(opacity=" + value*100 + ")";
      }
    }
    else {
      o.style[css.hyphen2camel(property)] = value;
    }
    return true;
  };
  css.set = css.setStyle;
  
  // Get a unique ID which doesn't already exist on the page
  css.uniqueIdNumber=1000;
  css.createId = function(o) {
    if (defined(o) && o!=null && defined(o.id) && o.id!=null && o.id!="") { 
      return o.id;
    }
    var id = null;
    while (id==null || document.getElementById(id)!=null) {
      id = "ID_"+(css.uniqueIdNumber++);
    }
    if (defined(o) && o!=null && (!defined(o.id)||o.id=="")) {
      o.id = id;
    }
    return id;
  };
  
  return css;
})();

/* ******************************************************************* */
/*   EVENT FUNCTIONS                                                   */
/* ******************************************************************* */

var Event = (function(){
  var ev = {};
  
  // Resolve an event using IE's window.event if necessary
  // --------------------------------------------------------------------
  ev.resolve = function(e) {
    if (!defined(e) && defined(window.event)) {
      e = window.event;
    }
    return e;
  };
  
  // Add an event handler to a function
  // Note: Don't use 'this' within functions added using this method, since
  // the attachEvent and addEventListener models differ.
  // --------------------------------------------------------------------
  ev.add = function( obj, type, fn, capture ) {
    if (obj.addEventListener) {
      obj.addEventListener( type, fn, capture );
      return true;
    }
    else if (obj.attachEvent) {
      obj.attachEvent( "on"+type, fn );
      return true;
    }
    return false;
  };

  // Get the mouse position of an event
  // --------------------------------------------------------------------
  // PageX/Y, where they exist, are more reliable than ClientX/Y because 
  // of some browser bugs in Opera/Safari
  ev.getMouseX = function(e) {
    e = ev.resolve(e);
    if (defined(e.pageX)) {
      return e.pageX;
    }
    if (defined(e.clientX)) {
      return e.clientX+Screen.getScrollLeft();
    }
    return null;
  };
  ev.getMouseY = function(e) {
    e = ev.resolve(e);
    if (defined(e.pageY)) {
      return e.pageY;
    }
    if (defined(e.clientY)) {
      return e.clientY+Screen.getScrollTop();
    }
    return null;
  };

  // Stop the event from bubbling up to parent elements.
  // Two method names map to the same function
  // --------------------------------------------------------------------
  ev.cancelBubble = function(e) {
    e = ev.resolve(e);
    if (typeof(e.stopPropagation)=="function") { e.stopPropagation(); } 
    if (defined(e.cancelBubble)) { e.cancelBubble = true; }
  };
  ev.stopPropagation = ev.cancelBubble;

  // Prevent the default handling of the event to occur
  // --------------------------------------------------------------------
  ev.preventDefault = function(e) {
    e = ev.resolve(e);
    if (typeof(e.preventDefault)=="function") { e.preventDefault(); } 
    if (defined(e.returnValue)) { e.returnValue = false; }
  };
  
  return ev;
})();

/* ******************************************************************* */
/*   SCREEN FUNCTIONS                                                  */
/* ******************************************************************* */
var Screen = (function() {
  var screen = {};

  // Get a reference to the body
  // --------------------------------------------------------------------
  screen.getBody = function() {
    if (document.body) {
      return document.body;
    }
    if (document.getElementsByTagName) {
      var bodies = document.getElementsByTagName("BODY");
      if (bodies!=null && bodies.length>0) {
        return bodies[0];
      }
    }
    return null;
  };

  // Get the amount that the main document has scrolled from top
  // --------------------------------------------------------------------
  screen.getScrollTop = function() {
    if (document.documentElement && defined(document.documentElement.scrollTop) && document.documentElement.scrollTop>0) {
      return document.documentElement.scrollTop;
    }
    if (document.body && defined(document.body.scrollTop)) {
      return document.body.scrollTop;
    }
    return null;
  };
  
  // Get the amount that the main document has scrolled from left
  // --------------------------------------------------------------------
  screen.getScrollLeft = function() {
    if (document.documentElement && defined(document.documentElement.scrollLeft) && document.documentElement.scrollLeft>0) {
      return document.documentElement.scrollLeft;
    }
    if (document.body && defined(document.body.scrollLeft)) {
      return document.body.scrollLeft;
    }
    return null;
  };
  
  // Util function to default a bad number to 0
  // --------------------------------------------------------------------
  screen.zero = function(n) {
    return (!defined(n) || isNaN(n))?0:n;
  };

  // Get the width of the entire document
  // --------------------------------------------------------------------
  screen.getDocumentWidth = function() {
    var width = 0;
    var body = screen.getBody();
    if (document.documentElement && (!document.compatMode || document.compatMode=="CSS1Compat")) {
        var rightMargin = parseInt(CSS.get(body,'marginRight'),10) || 0;
        var leftMargin = parseInt(CSS.get(body,'marginLeft'), 10) || 0;
      width = Math.max(body.offsetWidth + leftMargin + rightMargin, document.documentElement.clientWidth);
    }
    else {
      width =  Math.max(body.clientWidth, body.scrollWidth);
    }
    if (isNaN(width) || width==0) {
      width = screen.zero(self.innerWidth);
    }
    return width;
  };
  
  // Get the height of the entire document
  // --------------------------------------------------------------------
  screen.getDocumentHeight = function() {
    var body = screen.getBody();
    var innerHeight = (defined(self.innerHeight)&&!isNaN(self.innerHeight))?self.innerHeight:0;
    if (document.documentElement && (!document.compatMode || document.compatMode=="CSS1Compat")) {
        var topMargin = parseInt(CSS.get(body,'marginTop'),10) || 0;
        var bottomMargin = parseInt(CSS.get(body,'marginBottom'), 10) || 0;
      return Math.max(body.offsetHeight + topMargin + bottomMargin, document.documentElement.clientHeight, document.documentElement.scrollHeight, screen.zero(self.innerHeight));
    }
    return Math.max(body.scrollHeight, body.clientHeight, screen.zero(self.innerHeight));
  };
  
  // Get the width of the viewport (viewable area) in the browser window
  // --------------------------------------------------------------------
  screen.getViewportWidth = function() {
    if (document.documentElement && (!document.compatMode || document.compatMode=="CSS1Compat")) {
      return document.documentElement.clientWidth;
    }
    else if (document.compatMode && document.body) {
      return document.body.clientWidth;
    }
    return screen.zero(self.innerWidth);
  };
  
  // Get the height of the viewport (viewable area) in the browser window
  // --------------------------------------------------------------------
  screen.getViewportHeight = function() {
    if (!window.opera && document.documentElement && (!document.compatMode || document.compatMode=="CSS1Compat")) {
      return document.documentElement.clientHeight;
    }
    else if (document.compatMode && !window.opera && document.body) {
      return document.body.clientHeight;
    }
    return screen.zero(self.innerHeight);
  };

  return screen;
})();var Sort = (function(){
  var sort = {};
  sort.AlphaNumeric = function(a,b) {
    if (a==b) { return 0; }
    if (a<b) { return -1; }
    return 1;
  };

  sort.Default = sort.AlphaNumeric;
  
  sort.NumericConversion = function(val) {
    if (typeof(val)!="number") {
      if (typeof(val)=="string") {
        val = parseFloat(val.replace(/,/g,''));
        if (isNaN(val) || val==null) { val=0; }
      }
      else {
        val = 0;
      }
    }
    return val;
  };
  
  sort.Numeric = function(a,b) {
    return sort.NumericConversion(a)-sort.NumericConversion(b);
  };

  sort.IgnoreCaseConversion = function(val) {
    if (val==null) { val=""; }
    return (""+val).toLowerCase();
  };

  sort.IgnoreCase = function(a,b) {
    return sort.AlphaNumeric(sort.IgnoreCaseConversion(a),sort.IgnoreCaseConversion(b));
  };

  sort.CurrencyConversion = function(val) {
    if (typeof(val)=="string") {
      val = val.replace(/^[^\d\.]/,'');
    }
    return sort.NumericConversion(val);
  };
  
  sort.Currency = function(a,b) {
    return sort.Numeric(sort.CurrencyConversion(a),sort.CurrencyConversion(b));
  };
  
  sort.DateConversion = function(val) {
    // inner util function to parse date formats
    function getdate(str) {
      // inner util function to convert 2-digit years to 4
      function fixYear(yr) {
        yr = +yr;
        if (yr<50) { yr += 2000; }
        else if (yr<100) { yr += 1900; }
        return yr;
      };
      var ret;
      // YYYY-MM-DD
      if (ret=str.match(/(\d{2,4})-(\d{1,2})-(\d{1,2})/)) {
        return (fixYear(ret[1])*10000) + (ret[2]*100) + (+ret[3]);
      }
      // MM/DD/YY[YY] or MM-DD-YY[YY]
      if (ret=str.match(/(\d{1,2})[\/-](\d{1,2})[\/-](\d{2,4})/)) {
        return (fixYear(ret[3])*10000) + (ret[1]*100) + (+ret[2]);
      }
      return 99999999; // So non-parsed dates will be last, not first
    };
    return getdate(val);
  };

  sort.Date = function(a,b) {
    return sort.Numeric(sort.DateConversion(a),sort.DateConversion(b));
  };

  return sort;
})();