WEBDOOD.COM

Javascript

Javascript: Flatten an array containing arrays

by webdood on Sep.08, 2010, under Javascript, Software Development

This quick function takes a an array, whose elements may or may not be other arrays, and flattens it into a single array.

Extremely simple solution, but kind of fun because it’s a chance to use recursion:

<script type=text/javascript>
var a = [1,2,[5,6,7], 8, [9,10,[11,12],13], 14];

function flatten( oArray ) {
  var retVal = [];
  for (var i=0;i<oArray.length;i++) {
    if (!isArray( oArray[i]) ) {
      retVal.push( oArray[i] );
    } else {
      var tempFlatt = flatten(oArray[i]);
      for (var j=0;<tempFlatt.length;j++) {
        retVal.push( tempFlatt[j] );
      }
    }
  }
  return retVal;
}

function isArray( anElement ) {
  return (typeof anElement=="object" && anElement.constructor == Array);
}

alert(flatten(a));
</script>
2 Comments :, , more...

Detect Safari 3

by webdood on Aug.26, 2010, under Javascript, Safari-Specific, Software Development

Today I needed a quick way to detect Safari3 for some specific markup tricks, so I wrote this function.
Thought it might be helpful to someone else.

<script type="text/javascript">
  var isSafari3 = (function() {
    var retval = false;
    if (navigator.vendor && navigator.vendor.indexOf('Apple') > -1) {
      var index=navigator.appVersion.indexOf('Version');
      if (index > -1) {
        retval = (parseInt(navigator.appVersion.substring(index+8))==3);
      }
    }
  return retval;
  })();
alert(isSafari3);
</script>

Shannon Norrell

Leave a Comment :, , more...

HTML5 Showcase

by webdood on Jun.04, 2010, under CSS3, HTML5, Javascript, Software Development

The HTML5 demos we have been working on for Apple.com are now live!

http://www.apple.com/html5/

http://developer.apple.com/safaridemos/

Most of the demos use the DHTML slider we developed and all examples use our library.js code

HTML5 is here to stay!

Leave a Comment :, , , more...

Javascript HTML Tables EnsureMinimumNumberOfRows

by webdood on Apr.20, 2010, under HTML, Javascript, Software Development

Here I present a useful function called “EnsureMinimumNumberOfRows”.
This function operates on a table and effectively clones the last row in the table a given number of times to ensure that a minimum number of rows exist within the table. it does not clone the contents of the cells, but rather the nodes themselves and their classnames (by way of cloneNode(false).

///////////////////////////////////////////////////////////////////////////////
// EnsureMinimumNumberOfRows(element, params)
// ==========================================
// Ensures a table will have minimum number of visible rows.
// Supported params are:
//   numberOfRows - gives the minimum number of rows that will appear
//                          default minimumNumberOfRows is 10
//   rowHeight - height, in pixels for added rows. Default is 30px
//  *NOTE: Does not support empty tables
////////////////////////////////////////////////////////////////////////////////
function EnsureMinimumNumberOfRows(element, params) {
  var minimumNumberOfRows  = params.numberOfRows || 10,
       rowHeight            = params.rowHeight    || 30,
  // Get the first element as $(element).select returns an array
  // *Note this is a rare use of the Prototype Library on my part.
  oTable = $(element).select('div.resultList table')[0],
  numberOfRowsToInsert = minimumNumberOfRows - oTable.rows.length + 1;

  if (numberOfRowsToInsert > 0) {
    var clonedRow   = oTable.rows[ oTable.rows.length - 1 ]
    clonedCells = clonedRow.getElementsByTagName('td');
    for (var i=0;i<numberOfRowsToInsert;i++) {
      var oRow = document.createElement("TR");
      for (j=0;j<clonedCells.length;j++) {
        var oCell = clonedCells[j].cloneNode(false);
        oCell.style.height = rowHeight + "px";
        oCell.appendChild( document.createTextNode("\u00a0") );
        oRow.appendChild(oCell);
      }
      oTable.appendChild( oRow );
    }
  }
}

Shannon Norrell

Now posted on GitHub

Leave a Comment :, , , more...

Javascript addClassName, hasClassName and removeClassName

by webdood on Apr.07, 2010, under Javascript, Software Development

Useful CSS Class handling functions.

Here I present addClassName, hasClass and removeClassName and also my old implementation of Array.indexOf. Since this is built into JS these days, you probably won’t need it.

addClassName and removeClassName are useful functions because you can pass in space separated classNames and it will add/remove them all.

////////////////////////////////////////////////////////////////////////////////
//
// addClassName([object|string] oHTMLElement, string classNameToAdd)
// ===========
//  Adds classNameToAdd to an HTMLElement
//  Guaranteed not to add the same className twice.
//  - classNameToAdd can be a space separated list of classNames.
//  - You can pass in the id to an object or the actual object
//
////////////////////////////////////////////////////////////////////////////////
function addClassName(oHTMLElement, classNameToAdd) {
  if (typeof(oHTMLElement)=="string")  {
    oHTMLElement = document.getElementById(oHTMLElement);
  }
  if (oHTMLElement) {
    var theClassName = oHTMLElement.className;
    // If oHTMLElement already has a class name, some more work is needed
    if (theClassName && (theClassName.length > 0)) {
      var classNamesToAdd = classNameToAdd.split(" ");
      // If we only have one className to potentially add, take the "less work" approach
      if (classNamesToAdd.length===1 && ((" " + theClassName + " ").lastIndexOf(" " + classNameToAdd + " ") === -1) ) {
        oHTMLElement.className = oHTMLElement.className + " " + classNameToAdd;
      } else {
        var theClassNames = theClassName.split(" "),
              iEnd = classNamesToAdd.length,
              aClassName,
              theClassNamesToAddArray = [];
        for (var i=0;i<iEnd;i++) {
           aClassName = classNamesToAdd[i];
           if (theClassNames.indexOf(aClassName)===-1) {
             theClassNamesToAddArray.push( aClassName );
           }
        }
        oHTMLElement.className = oHTMLElement.className + " " +((theClassNamesToAddArray.length > 1) ? theClassNamesToAddArray.join(" ") : theClassNamesToAddArray[0]);
      }
    } else {
      // If oHTMLElement did not already have a class name, just add it
      oHTMLElement.className = classNameToAdd;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
//
// hasClassName([object|string] oHTMLElement, string classNameOfInterest)
//           Returns a boolean value of if an HTMLElement has the className of interest
//           You can pass in the id to an object or the actual object
//
////////////////////////////////////////////////////////////////////////////////
function hasClassName(oHTMLElement, classNameOfInterest) {
  return ((" " + oHTMLElement.className + " ").lastIndexOf(" " + classNameOfInterest + " ") > -1);
}
////////////////////////////////////////////////////////////////////////////////
//
// removeClassName([object|string] oHTMLElement, string classNameToRemove)
//           Removes classNameToRemove from an HTMLElement, if it exists.
//        - classNameToRemove can be a space separated list of classNames.
//        - You can pass in the id to oHTMLElement or the actual object
//
////////////////////////////////////////////////////////////////////////////////
function removeClassName(oHTMLElement, classNameToRemove) {
  if (typeof(oHTMLElement)=="string")  {
    oHTMLElement = document.getElementById(oHTMLElement);
  }
  if (oHTMLElement) {
    var theClassName = oHTMLElement.className;
    if (theClassName && (theClassName.length > 0)) {
      var theClassNameArray = theClassName.split(" "),
           classNamesToRemove = classNameToRemove.split(" "),
           iEnd = theClassNameArray.length,
           aClassName,
           theNewClassNameArray = [];
      for (var i=0;i<iEnd;i++) {
        aClassName = theClassNameArray[i];
        if (classNamesToRemove.indexOf(aClassName)===-1) {
          theNewClassNameArray.push( aClassName );
        }
      }
      switch (true) {
        case (theNewClassNameArray.length>1) :
          oHTMLElement.className = theNewClassNameArray.join(" ");
          break;
        case (theNewClassNameArray.length==1) :
          oHTMLElement.className = theNewClassNameArray[0];
          break;
        case (theNewClassNameArray.length==0) :
          oHTMLElement.className = "";
          break;
      }
    }
  }
}
////////////////////////////////////////////////////////////////////////////////
//
// Array.indexOf() - returns integer index where valueToSearchFor is in an Array
//
////////////////////////////////////////////////////////////////////////////////
if (Array.prototype.indexOf===undefined) {
  Array.prototype.indexOf = function( valueToSearchFor ) {
    var iEnd = this.length;
    var retVal = -1;
    for (var i=0;i<iEnd; i++) {
      if (this[i] == valueToSearchFor) {
        retVal = i;
        break;
      }
    }
    return retVal;
  };
}

by Shannon Norrell

Leave a Comment :, , , , , , , more...

showOrHide algorithm

by webdood on Mar.01, 2010, under Javascript, Software Development

Making it easier for me to look up my own most useful block of code for displaying/hiding elements. This is the same bit of code I wrote for Microsoft that shipped with Vista and now Windows 7 with the Sidebar gadgets.

////////////////////////////////////////////////////////////////////////////////
//
// showOrHide([object|string] oHTMLElement, boolean bShowOrHide)
//           Shows or Hides an HTMLElement.
//           You can pass in the id to an object or the actual object
//
////////////////////////////////////////////////////////////////////////////////
function showOrHide(oHTMLElement, bShowOrHide) {
  try   {
    if (typeof(oHTMLElement)=="string")  {
      oHTMLElement = document.getElementById(oHTMLElement);
    }
    if (oHTMLElement && oHTMLElement.style) {
      if (bShowOrHide == 'inherit') {
        oHTMLElement.style.visibility = 'inherit';
      } else {
        if (bShowOrHide) {
          if (oHTMLElement.nodeName == 'TR') {
            oHTMLElement.style.visibility = 'inline-table';
          } else {
            oHTMLElement.style.visibility = 'visible';
          }
        } else {
          oHTMLElement.style.visibility = 'hidden';
        }
         try {
           if (bShowOrHide) {
             oHTMLElement.style.display = 'block';
           } else {
             oHTMLElement.style.display = 'none';
           }
         }
         catch (ex) {
         }
       }
     }
  }
  catch (ex) {
  }
}

Shannon Norrell

Now on GitHub

UPDATE TO THIS POSTING 4/14/2011
I have now taken to adding and removing a special className (usually called “hidden”) to oHTMLElements to show or hide them.

For example:

Assume in your CSS, there is a declaration like this:
.hidden { display:none; }

function showOrHide( oHTMLElement, bVisible ) {
  if (typeof(oHTMLElement)=="string")  {
    oHTMLElement = document.getElementById(oHTMLElement);
  }
  if (oHTMLElement) {
    if (!bVisible) {
      addClassName( oHTMLElement, 'hidden' );
    } else {
      removeClassName( oHTMLElement, 'hidden' );
  }
}

See our link about addClassName and removeClassName for more information on this technique.

Shannon Norrell

Leave a Comment :, , , more...

Unified Javascript disableTextSelection | enableTextSelection

by webdood on Dec.08, 2009, under Javascript, Software Development

Unified Text Selection Disable/Enable Routine

If you’re doing any kind of drag and drop operation in Javascript/DHTML, you will need to temporarily disable and re-enable text selection in your document while the drag operation is going on.

I wrote this block of code today and it was such a tedious hassle, I thought it worth blogging so others wouldn’t have to endure my pain :{.

This works in all browsers except PC Opera.

It DOES work in Mac OSX Safari, Firefox, Chrome and on PC Internet Explorer, Safari, Firefox and Chrome.

////////////////////////////////////////////////////////////////////////////
// UTILITIES - Section contains general-purpose utilties
// =========
////////////////////////////////////////////////////////////////////////////
utilities : {
  // savedValueOf will hold "original" values that we override/restore as needed
  savedValueOf : new Object(),
  disableTextSelection : function() {
    switch (true) {
      case ( typeof document.onselectstart!="undefined" ) : // IE
        this.savedValueOf["onselectstart"] = document.onselectstart;
        document.onselectstart=function() { return false; };
        break;
      case ( typeof document.body.style.MozUserSelect != "undefined" ) : // Firefox
        this.savedValueOf["-moz-user-select"] = document.body.style.MozUserSelect || "text";
document.body.style.MozUserSelect="none";
        break;
      case ( document.body.style["-khtml-user-select"] != "undefined" ) : // Safari
        this.savedValueOf["-khtml-user-select"] = document.body.style["-khtml-user-select"];
        document.body.style["-khtml-user-select"] = 'none';
        break;
    }
  },
  // enableTextSelection -simply restores *whatever* the previous selection mode was
  // ===============  for the particular browser
  enableTextSelection : function() {
    switch (true) {
      case ( typeof document.onselectstart!="undefined" ) : // IE
        document.onselectstart = this.savedValueOf["onselectstart"]
        break;
      case (typeof document.body.style.MozUserSelect != "undefined") :  // Firefox
        document.body.style.MozUserSelect = this.savedValueOf["-moz-user-select"]
        break;
      case ( document.body.style["-khtml-user-select"]!="undefined" ) : // Safari
        document.body.style["-khtml-user-select"] = this.savedValueOf["-khtml-user-select"];
        break;
    }
  }
}

Shannon Norrell

This posting now also on GitHub

Leave a Comment :, , , more...

BadAss Javascript Date Validator – Useful for Rails

by webdood on Jul.18, 2009, under Javascript, Ruby on Rails, Software Development

Should make a point of posting cool routines like the one below as they are useful to many.

I have seen quite a lot of good examples of folks using (and expanding upon) routines I wrote for some of the Gadgets that ship with Vista (to be found in library.js if you have a Vista Box) and for some of AOL’s (apparently deprecated) Mac OSX Widgets.

Functions like showOrHide, getLocalizedString, getSpinner (emulates Vista-like spinner image) I have seen in use all over the place.

Here is a somewhat badass Date Validator routine I wrote today that takes in either a string date value or an <INPUT> Element Object and validates the date to be formatted as DD-MM-YYYY.

I wrote it for use by a Ruby on Rails application, but it’s pretty handy as a general library function.

var DATE_REGEX  = /^(\d{2})-(\d{2})-(\d{4})$/
////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// validateDate([object|string] oHTMLInputElement) - Validates a date value   //
// ===============================================                            //
//   You can pass in the id to an <input> Element, an actual               //
//   oHTMLInputElement or an actual date value in the form of a string        //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

function validateDate(oHTMLInputElementOrDateValue) {
  var theDateValueToValidate = "";
  var theValidatedDateValue = false;
  var bIsInputElement = false;
  if (typeof(oHTMLInputElementOrDateValue)=="string")  {
    var oHTMLInputElement = document.getElementById(oHTMLInputElementOrDateValue);
    if (oHTMLInputElement && typeof(oHTMLInputElement=="object") && (oHTMLInputElement.tagName=="INPUT")) {
      theDateValueToValidate = oHTMLInputElement.value;
      bIsInputElement = true;
    } else {
      // Presumably they just passed in a date string
      theDateValueToValidate = oHTMLInputElementOrDateValue;
      bIsInputElement = false;
    }
  } else {
    // They have passed in an Object
    if (typeof(oHTMLInputElementOrDateValue=="object") && (oHTMLInputElementOrDateValue.tagName=="INPUT")) {
      var oHTMLInputElement = oHTMLInputElementOrDateValue;
      theDateValueToValidate = oHTMLInputElement.value;
      bIsInputElement = true;
    }
  }

  // If we have a date value to actually validate, let's get started
  if (theDateValueToValidate != "") {
    var theDateValue = theDateValueToValidate.replace(/\//g,"-");  // Ruby-side only accepts hyphens
    if (DATE_REGEX.test(theDateValue)) {
      theValidatedDateValue = theDateValue;
    } else {
      if (theDateValue.indexOf('-') > -1) {
        var theMonth = theDateValue.split('-')[0];
        var theDay   = theDateValue.split('-')[1];
        var theYear  = theDateValue.split('-')[2];
        // If they've entered a single digit for either Day or Month, pad with zero accordingly
        theMonth = parseInt(theMonth).PadWithZero();
        theDay   = parseInt(theDay).PadWithZero();
        if (theYear.length==2) { theYear = "20" + theYear; }    // If they've entered a two-digit year, assume it's in the 21st century
        theDateValue = theMonth + "-" + theDay + "-" + theYear; // Rebuild the date. Hopefully this will work
        if (DATE_REGEX.test(theDateValue)) {
          theValidatedDateValue = theDateValue;
        }
      }

      // If we get to this point and none of our efforts have worked to format the date
      // as "required", throw an error (if they are using an INPUT element)
      if (!theValidatedDateValue && bIsInputElement) {
        alert("ERROR: Date must be formatted as follows:\n\n\tDD-MM-YYYY\n\nPlease correct before continuing");
        oHTMLInputElement.focus();
      }
    }
  }

  if (bIsInputElement && theValidatedDateValue) {
    oHTMLInputElement.value = theValidatedDateValue;
  }
  return theValidatedDateValue;
}

Hope you find this one useful as well.

Shannon Norrell

Now on GitHub as well

Leave a Comment :, , , more...

Fast JavaScript Max/Min on an Array Taking Arbitrary Number of Arguments

by webdood on Feb.25, 2009, under Javascript, Software Development

What's the fastest way to find the largest, or smallest, number in an array?

Array.max = function( array ){
  return Math.max.apply( Math, array );
};
Array.min = function( array ){
  return Math.min.apply( Math, array );
};

By using JavaScript's .apply() method on a built-in function you can pass in an array of unlimited arguments.

Shannon Norrell

Leave a Comment :, , more...

The dreaded “Line 0, Object Expected” Javascript error

by webdood on Sep.05, 2008, under IE-Specific, Javascript, Software Development

One of my favorite mechanisms to do IE-specific CSS is to use the so-called dynamic properties available to IE5+ browsers. Firefox and Opera ignore these tags, so if, for instance you need a div of id “foo” to be 110 pixels in IE and 100 pixels in all other browsers, you would just do this:

#foo {
  width: 100px;
  width: expression(’110px’);
}

Of course, there are easier ways of doing this in IE if you just need a fixed value to appear, using the so-called IE CSS hacks like the star harck *width:100px or _width:100px; will only be interpreted by Internet Explorer, but when you need a truly dynamic property that is based on changing conditions, using “expression” is a valid tactic.

I began to encounter a strange Line 0. Object Required Javascript bug and spent the better part of a day trying to track down the cause. The bug was so severe that, when hit, it required me to close IE using Task Manager. I could not figure this one out and finally resorted to reconstructing the entire page, line-by-line until I found the problem.

I finally determined it occurred only when I added a <textarea> tag to the page. My current project is a Ruby on Rails app, which necessarily indludes the Prototype Library, so I initially wrote off this weirdity to the vagaries of Prototype and its many tens of thousands of lines of code.

In this context, an input type=text tag would do fine, so I switched to that and moved on.

Quite by accident, I stumbled across this section in my CSS file:

.WordBubble textarea {
  overflow:hidden;
  border:solid 1px lightBlue;
  height:30px;
  width:expression(document.getElementById(‘WordBubble’).offsetWidth-66);
}

And WHALA, the answer!

Thinking to reuse a WordBalloon construct I had developed, I had modified this CSS to play off of .WordBubble the className vs the original #WordBubble the ID. Therefore, when I used the original:

<div id=”WordBubble” class=”WordBubble”>
<textarea>
</div>

things worked as expected.

However, when using:

<div id=”AnotherWordBubble” class=”WordBubble”>
<textarea>
</div>

The CSS, when evaluating the dynamic property, could not find “WordBubble” as it did not exist as an ID (see it’s now a className).

Although I realize this posting is somewhat confusing (I barely understand it myself), what I am trying to say is “When you get a Line 0, Object Expected” Javascript error and can’t figure out where it comes from, check your CSS for Expression use.

Shannon

Leave a Comment :, , more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Blogroll

A few highly recommended websites...

  • A List Apart
  • Dive into HTML5
  • Javascript: The Good Parts
  • QuirksMode.org