All posts by Chris West

JavaScript Snippet – Convert Number To Column Name

Following yesterday’s post, I thought it appropriate to write a quick JavaScript function which converts an integer into the corresponding column name:

/**
 * Takes a positive integer and returns the corresponding column name.
 * @param {number} num  The positive integer to convert to a column name.
 * @return {string}  The column name.
 */
function toColumnName(num) {
  for (var ret = '', a = 1, b = 26; (num -= a) >= 0; a = b, b *= 26) {
    ret = String.fromCharCode(parseInt((num % b) / a) + 65) + ret;
  }
  return ret;
}

You can click here to enter a positive integer and see the corresponding column name. If you need this function for a project, feel free to use it as long as you give credit. 8)

JavaScript Snippet – Parse A Spreadsheet Address

Today I am starting work on a quick flashcard app that will use Google Docs to read data from a spreadsheet. I thought I had written and published a function which parses an Excel like cell address and converts it into the column number and the row number but I wasn’t able to find it. Thusly I wrote the following parseAddress function:

/**
 * Takes in a cell address and returns an array containing the corresponding
 * column number followed by the row number.
 * @param {string} strCellAddr  The address of the cell (eg. AD32).
 * @return {!Array.<number>}  An array of two numbers:  the column number and
 *     the row number.
 */
function parseAddress(strCellAddr) {
  var i = strCellAddr.search(/\d/);
  var colNum = 0;
  strCellAddr = +strCellAddr.replace(/\D/g, function(letter) {
    colNum += (parseInt(letter, 36) - 9) * Math.pow(26, --i);
    return '';
  });
  return [colNum, strCellAddr];
}

This function takes the cell address as a string (eg. AD32) and converts it to an array (eg. [30, 32]). The first value in the array will be the column number and the second will be the row number.

JavaScript – Adding Cross-browser Event Listeners

Something that I need to use every once in a while is addEventListener, but unfortunately I can’t depend on its existence in all browsers. For this reason I decided to write the following cross-browser solution for providing a function that adds an event handler:

/**
 * Cross-browser function to add an event listener.
 * @param {!HTMLElement} elem  The DOM element to attach event to.
 * @param {string} eventName  The name of the event.
 * @param {!Function} fnHandler  The function to server as one of the specified
 *     event handlers.
 * @return {Function}  Returns the function that was added as an event handler.
 */
var addEvent = function(elem, eventName, fnHandler) {
  var fnToBind = function(e) {
    return fnHandler.call(elem, e || window.event);
  };
  
  // Add the event the W3C way.
  if (elem.addEventListener) {
    elem.addEventListener(eventName, fnToBind, false);
    return fnToBind;
  }
  
  eventName = 'on' + eventName;
  
  // Add the event the Microsoft way.
  if (elem.attachEvent) {
    return elem.attachEvent(eventName, fnToBind) ? fnToBind : null;
  }
  
  // Assign the handler directly to the object's event handler property.
  if(typeof elem[eventName] == 'function') {
    // Add the event by creating a function which will run both the current
    // handler and this new one.
    var f1 = elem[eventName], f2 = fnToBind;
    fnToBind = function() {
      var ret1, ret2;

      try { ret1 = f1.apply(this, arguments); }
      catch (e1) { setTimeout(function() { throw e1; }, 0); }

      try { ret2 = f2.apply(this, arguments); }
      catch (e2) { setTimeout(function() { throw e2; }, 0); }

      // If the previous handler returned a non-undefined value, return it,
      // otherwise return the value returned from the new handler.
      return ret1 === undefined ? ret2 : ret1;
    };
  }
  elem[eventName] = fnToBind;
  return fnToBind;
};

One thing to note is that this function will wrap your function in order to allow for the event object to always be passed as the first argument regardless of the browser. Enjoy! 8)