      YAHOO.namespace("YAHOO.ajax");
      YAHOO.ajax.callback = null;
      YAHOO.ajax.change = null;
      YAHOO.ajax.blankRow = null;
/*
* Get rid of object template field.  we only want the inline row td elements
*/
      YAHOO.ajax.removeObjectTemplateElement = function(tds){
          for (i = 0; i < tds.length; i++){
            if ( tds[i].tagName.toUpperCase() != "TD" ){
              tds.splice(i, 1);
            }
          }
      }
/*
* we either add new rows or remove unwanted rows.  If fields has more than 3, we add.  If it has less, we remove.
*/
      YAHOO.ajax.fixNumberOfRows = function(tds, fields){
	  //if we don't have enough rows, we must clone and add some inline rows
          if ( tds.length < fields.length ){
            var idMatch = function(e){
              if ( e.id == null ){
                return false;
              }
              return e.id.indexOf("htmlfield_set-") != -1;
            }
            var f = function(e){
              return e.tagName.toUpperCase() == "TABLE";
            }
            table = YAHOO.util.Dom.getElementsBy(f, "TABLE")[0];
	    //we already have [tds.length] rows.  we need [fields.length] rows
            for ( i = tds.length; i < fields.length; i++ ){
              newRow = YAHOO.ajax.blankRow.cloneNode(true);
	      //we must collect the elements with id's and change them to the proper id number 
              elems = YAHOO.util.Dom.getElementsBy(idMatch, null, newRow);
              for ( j = 0; j < elems.length; j++ ){
                elems[j].name = elems[j].name.replace("htmlfield_set-0","htmlfield_set-"+i);
                elems[j].id = elems[j].id.replace("htmlfield_set-0","htmlfield_set-"+i);
              }
	      //finally, add the newRow to the table, and add the row to our tds list
              table.appendChild(newRow);
              var isClassTemplate = function(e){
                return YAHOO.util.Dom.hasClass(e,"template");
              }
              tds[i] = YAHOO.util.Dom.getFirstChildBy(newRow, isClassTemplate);
            }//end adding rows
          }//end if adding rows
      }//end YAHOO.ajax.fixNumberOfRows()

/*
*The change object page has titles on the left side of inline rows that clutter the page.  let's remove their <p> elements
*/
      YAHOO.ajax.removeInlineFieldTitles = function(tds){
          hasOrig = YAHOO.util.Dom.getElementsByClassName("has_original");
          for ( i = 0; i < hasOrig.length; i++ ){
            orig = YAHOO.util.Dom.getFirstChild(hasOrig[i]);
            if ( YAHOO.util.Dom.hasClass(orig, "original")){
              ptag = YAHOO.util.Dom.getFirstChild(orig);
              orig.removeChild(ptag);
            }
          }
      }
      YAHOO.ajax.getSelectBox = function( curTd ){
            var isSelBox = function(e){
              return e.type == "select-one";
            }
            return YAHOO.util.Dom.getFirstChildBy( curTd, isSelBox );
      }
      YAHOO.ajax.getSelectedOption = function( curTd ){
            selbox = YAHOO.ajax.getSelectBox( curTd );
            var selected = function(e){
              return e.selected;
            }
            return YAHOO.util.Dom.getFirstChildBy(selbox, selected);
      } 
      YAHOO.ajax.getOption = function(curField, curTd){
            selbox = YAHOO.ajax.getSelectBox( curTd );
            var isCurField = function(e){
              return e.value == curField['id'];
            }
            return YAHOO.util.Dom.getFirstChildBy(selbox, isCurField);
      }
/*
*sets the current row's select box to the current fieldTemplate
*/
      YAHOO.ajax.populateSelectBoxes = function(tds, fields){
        for ( i = 0; i < tds.length; i++ ){
            curTd = tds[i];
            curField = fields[i];
            selectedOption = YAHOO.ajax.getSelectedOption(curTd);
            optionToSelect = YAHOO.ajax.getOption(curField, curTd);
            selectedOption.selected = false;
            optionToSelect.selected = true;
        }
      }
      YAHOO.ajax.getSelectedField = function(curTd, fields){
            for ( i = 0; i < fields.length; i++ ){
              if (fields[i]['id'] == YAHOO.ajax.getSelectedOption( curTd ).value){
                return fields[i];
              }
            }
      }
/*
*if img tag, disable value field.  all other tags disable the file field
*/
      YAHOO.ajax.disableExtraFields = function(curTd, curField){
            var disableClass = "file";
            var enableClass = "value";
            if (curField['tag'] == "img"){
              disableClass = "value";
              enableClass = "file";
            }
            var d = function(e){
              return YAHOO.util.Dom.hasClass(e,disableClass);
            }
            var e = function(e){
              return YAHOO.util.Dom.hasClass(e,enableClass);
            }
            var disableTd = YAHOO.util.Dom.getNextSiblingBy(curTd, d);
            var disableField = YAHOO.util.Dom.getFirstChild(disableTd); 
            disableField.disabled = true;
            var enableTd = YAHOO.util.Dom.getNextSiblingBy(curTd, e);
            var enableField = YAHOO.util.Dom.getFirstChild(enableTd); 
            enableField.disabled = false;
      }
      YAHOO.ajax.setTextAreaDimensions = function(rows, cols){
          var isTextArea = function(e){
            return e.tagName.toUpperCase() == "TEXTAREA";
          }
          textareas = YAHOO.util.Dom.getElementsBy(isTextArea);
          for ( i = 0; i < textareas.length; i++ ){
            t = textareas[i];
            t.rows = rows;
            t.cols = cols;
          }
      }
/*
*Add preview functionality
*/
    YAHOO.ajax.closePreview = function(){
        var div = YAHOO.util.Dom.get("preview-div");
	YAHOO.util.Dom.setStyle(div,"visibility","hidden");
    }
    YAHOO.ajax.showPreview = function(){
        var div = YAHOO.util.Dom.get("preview-div");
	YAHOO.util.Dom.setStyle(div,"visibility","visible");
    }
    YAHOO.ajax.getPreview = function(){
	var successHandler = function(o){
	    var span = YAHOO.util.Dom.get("preview");
	    var div = YAHOO.util.Dom.get("preview-div");
            span.innerHTML = o.responseText;
	    YAHOO.util.Dom.setStyle(div,"visibility","visible");
	}
	var failureHandler = function(o){
	    alert("fail");
	}
	var previewCallback = {
	    success:successHandler,
	    failure:failureHandler,
	};
	var a = document.location.pathname.split("/");
	var id = a[a.length-2];
	var url = "/preview?id="+id;
        if (!YAHOO.ajax.loadedPreview){
            YAHOO.ajax.loadedPreview = true;
	    var transaction = YAHOO.util.Connect.asyncRequest("GET",url, previewCallback, null);
        }
        else{
            YAHOO.ajax.showPreview();
        }
    }
    YAHOO.ajax.initPreview = function(){
        var div = document.createElement("div");
        var closediv = document.createElement("div");
        var close = document.createElement("a");
        close.appendChild(document.createTextNode("close"));
        close.href = "#";
        close.style.fontSize = "1.5em";
        closediv.style.cssFloat = "right";
        closediv.appendChild(close);
        closediv.appendChild(document.createElement("hr"));
        div.appendChild(closediv);
        var span = document.createElement("span");
        span.id = "preview";
        div.id = "preview-div";
        div.appendChild(span);
        YAHOO.util.Dom.setStyle(div,"visibility","hidden");
        YAHOO.util.Dom.setStyle(div,"height","200px");
        YAHOO.util.Dom.setStyle(div,"width","500px");
        YAHOO.util.Dom.setStyle(div,"border","3px solid #aaaaaa");
        YAHOO.util.Dom.setStyle(div,"padding","5px");
        YAHOO.util.Dom.setStyle(div,"position","absolute");
        YAHOO.util.Dom.setStyle(div,"backgroundColor","white");
        YAHOO.util.Dom.setStyle(div,"right","200px");
        YAHOO.util.Dom.setStyle(div,"cssFloat","right");
	YAHOO.util.Event.addListener(close, "click", YAHOO.ajax.closePreview);
        var contentDiv = YAHOO.util.Dom.get("content");
        contentDiv.insertBefore(div, contentDiv.childNodes[0]);
        var link = document.createElement("a");
        link.appendChild(document.createTextNode("preview"));
        link.href = "#";
        link.style.fontSize = "1.5em";
        link.style.cssFloat = "right";
        link.style.marginRight = "200px";
        var contentDiv = YAHOO.util.Dom.get("content");
        contentDiv.insertBefore(link, contentDiv.childNodes[0]);
	YAHOO.util.Event.addListener(link, "click", YAHOO.ajax.getPreview);
    }
        
/*
*The meat and potatoes.  This calls all our helper functions (above)
*/
      YAHOO.ajax.getFields = function(){
/*
*call this if ajax response is successful
*/
        var successHandler = function(o){
          var r = YAHOO.lang.JSON.parse(o.responseText);
          var fields = r['fields']; 
          var tds = YAHOO.util.Dom.getElementsByClassName("template");
          YAHOO.ajax.removeObjectTemplateElement(tds);
          YAHOO.util.Dom.get("id_htmlfield_set-TOTAL_FORMS").value = fields.length;
          if ( YAHOO.ajax.change ){
            YAHOO.ajax.removeInlineFieldTitles(tds);
            YAHOO.ajax.initPreview();
          }
          else{
            YAHOO.ajax.fixNumberOfRows(tds, fields);
	    YAHOO.ajax.populateSelectBoxes(tds, fields);
          }
          for (i = 0; i < fields.length; i++){
            curTd = tds[i];
            //remove the addField buttons
            addbutton = YAHOO.util.Dom.getLastChild( curTd );
            addbutton.parentNode.removeChild(addbutton);
            var curField = YAHOO.ajax.getSelectedField(curTd, fields);
            YAHOO.ajax.disableExtraFields(curTd, curField);
          }//end for
          //make textareas smaller
          YAHOO.ajax.setTextAreaDimensions(5,40);
        }//end successHandler
        var failureHandler = function(o){
          alert(o.status + ": " + o.statusText);
        }
        YAHOO.ajax.callback = {
          success:successHandler,
          failure:failureHandler,
        }; 
        var template = YAHOO.util.Dom.get("id_template");
        var url = "/ajax?template="+template.value;
        var transaction = YAHOO.util.Connect.asyncRequest("GET",url, YAHOO.ajax.callback, null);
      }//end getFields()


/*
*initialize ajax behavior onDOMReady
*/
      YAHOO.ajax.initAjax = function(){
	  var contentdiv = YAHOO.util.Dom.get("content");
	  var h1 = YAHOO.util.Dom.getFirstChild(contentdiv);
          var title = h1.firstChild.nodeValue;
          var templateCells = YAHOO.util.Dom.getElementsByClassName("template");
          //because extra = 1 in app/models.py, the last row is guaranteed to be blank, making it a perfect clone node
          var lastRow = templateCells[templateCells.length-1].parentNode;
          YAHOO.ajax.blankRow = lastRow.cloneNode(true);
          //delete the extra row, we'll add however many we need later
          lastRow.parentNode.removeChild(lastRow);
	  if ( title.indexOf("Add") != -1 ){
            YAHOO.ajax.change = false;
	    YAHOO.util.Event.addListener("id_template", "change", YAHOO.ajax.getFields);
	  }else{
            YAHOO.ajax.change = true;
	    YAHOO.util.Event.onDOMReady(YAHOO.ajax.getFields);
	  }
      }//end initAjax()


      YAHOO.util.Event.onDOMReady(YAHOO.ajax.initAjax);





