// generated from config/js/yui-traction.properties on Mon Aug 24 21:49:09 EDT 2009

//------------------------------------------------------------------------
// yui-traction.AutoCompleteInSelect

YAHOO.namespace("traction");
YAHOO.traction.AutoCompleteInSelect = function(elInput,elContainer,oDataSource,oConfigs) {
    YAHOO.traction.AutoCompleteInSelect.superclass.constructor.call(this,elInput,elContainer,oDataSource,oConfigs);
};
YAHOO.lang.extend(YAHOO.traction.AutoCompleteInSelect, YAHOO.widget.AutoComplete);
YAHOO.traction.AutoCompleteInSelect.prototype._initList = function() {
    this._aListItems = [];
    while(this._oContainer._oContent._oBody.hasChildNodes()) {
        var oldListItems = this.getListItems();
        if(oldListItems) {
            for(var oldi = oldListItems.length-1; oldi >= 0; i--) {
                oldListItems[oldi] = null;
            }
        }
        this._oContainer._oContent._oBody.innerHTML = "";
    }
    var oList = document.createElement("div");
    oList.setAttribute("multiple","");
    oList = this._oContainer._oContent._oBody.appendChild(oList);
    for(var i=0; i<this.maxResultsDisplayed; i++) {
        var oItem = document.createElement("a");
        oItem = oList.appendChild(oItem);
        this._aListItems[i] = oItem;
        this._initListItem(oItem, i);
    }
    var oButton = document.createElement("input");
    oButton.setAttribute("type", "button");
    oButton.setAttribute("name", "Add");
    oButton.setAttribute("value", "Add");
    oButton = this._oContainer._oContent._oBody.appendChild(oButton);
    this._maxResultsDisplayed = this.maxResultsDisplayed;
};

//------------------------------------------------------------------------
// yui-traction.SelectorPanel

YAHOO.namespace("traction");
YAHOO.traction.SelectorPanel = function(id, title, options) {
  this.id = id;
  this.title = title;
  this.options = {
    submitButtonValue: i18n("Done", "Done"),
    style : "autocomplete"
  }.extend(options || {});
  YAHOO.traction.SelectorPanel.registry[id] = this;
};
YAHOO.traction.SelectorPanel.registry = new Array();
YAHOO.traction.SelectorPanel.get = function(id) {
  return YAHOO.traction.SelectorPanel.registry[id];
};
YAHOO.traction.SelectorPanel.prototype.submit = function() {};
YAHOO.traction.SelectorPanel.prototype.show = function(subtitle) {
  this.build();
  this.id_label.innerHTML = subtitle;
  cm.lock();
  this.panel.show();
  this.completer.focus();
};
YAHOO.traction.SelectorPanel.prototype.hide = function() {
  this.panel.hide();
};
YAHOO.traction.SelectorPanel.prototype.setProject = function(project) {
  this.completer.setProject(project);
  this.selector.setProject(project);
};
YAHOO.traction.SelectorPanel.prototype.build = function() {
  if (this.panel && this.panel != null) return;
  var div = document.createElement("div");
  if (ua("supports_ajax_label_chooser", "true") == "false" || this.options.style != "autocomplete") {
    div.style.display = "none";
  }
  div.id = this.id;
  YAHOO.util.Dom.addClass(div, "grey");  // also have black
  YAHOO.util.Dom.addClass(div, "resize");
  document.body.appendChild(div);
  this.subtitle = "";
  var html = 
  '<div class="hd"><div class="tl"></div><div class="title">'+this.title+'</div><div class="tr"></div></div>'+
  '<div class="bd"><div class="outer"><div class="inner"><div class="mid">'+
  '<form style="display: inline; margin: 0; padding: 0;" name="'+this.id+'_fm" onsubmit="return false;">'+
  '<div style="padding-top: 3px; background: transparent" id="'+this.id+'_id">'+this.subtitle+'</div>'+
  '<div class="selector" id="'+this.id+'_selector"></div>'+
  '<div style="padding-top: 3px; background: transparent">' + this.options.fieldLabelText +
  (this.options.helpBoxResourceName ? ('<a href="javascript:helpbox(\'' + this.options.helpBoxResourceName + '\')">[?]</a>') : '') + '</div>'+
  '<div style="position: relative; margin-right: 7px">'+
  '<table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td><input type="text" name="completer" tabindex="10000" id="'+this.id+'_completer" size="28" style="width: 100%; font-size: 8pt;"></td><td width="12" style="width: 14px; border-left: 1px solid #848484;"><img class="dd" id="'+this.id+'_dropdown" src="/images/dropdown.gif" style="margin-left: 0px; margin-top: 1px; padding: 6px 3px;"></td></tr></table>'+
  '</div>'+
  '<div style="position: relative; padding-top: 3px;">'+
  '<div style="height: 24px; position: relative; border-top: 1px solid #999;">'+
  this.getOtherLinksHTML() +
  '<input type="button" tabindex="10001" class="completer" onclick="YAHOO.traction.SelectorPanel.get(\''+this.id+'\').submit(); return false;" value="' + this.options.submitButtonValue + '" style="position: absolute; right: 5px; top: 4px; font-size: 8pt;">'+
  '</div>'+
  '</div>'+
  '</form>'+
  '</div></div></div></div>'+
  '<div class="ft"><div class="bl"></div><div class="ftmain"></div><div class="br"></div></div>';
  div.innerHTML = html;
  this.panel = new YAHOO.traction.TractionPanel(this.id, 
						{
						width: "260px", 
						    visible:true, 
						    draggable: true, 
						    dragOnly: true,
						    constraintoviewport:true, 
						    underlay: "none",
						    effect:{ effect:YAHOO.widget.ContainerEffect.FADE, duration:0.25 },
						    minheight: 150,
						    minwidth: 200,
						    zIndex: 500
						    } );
  this.panel.render();
  this.panel.hideEvent.subscribe(this.onhide,this,true);
  this.panel.moveEvent.subscribe(this.onmove,this,true);
  this.panel.dragEvent.subscribe(this.onmove,this,true);
  this.panel.showEvent.subscribe(this.onshow,this,true);
  var myfm = document[this.id+"_fm"];
  myfm.onsubmit = function() { return false; };
  var selector_div = document.getElementById(this.id+"_selector");
  this.selector = this.getSelector(selector_div, this);
  var completer_text = document.getElementById(this.id+"_completer");
  this.completer = this.getCompleter(completer_text, this);
  this.id_label = document.getElementById(this.id+"_id");
  this.dropdown = document.getElementById(this.id+"_dropdown");
  if (this.dropdown != null) {
    this.dropdown.style.cursor = "pointer";
    this.dropdown.onmouseover = this.hoverDropdown.bind(this);
    this.dropdown.onmouseout = this.unhoverDropdown.bind(this);
    this.dropdown.onmousedown = this.mousedownDropdown.bind(this);
    this.dropdown.onmouseup = this.mouseupDropdown.bind(this);
    this.dropdown.onclick = this.clickDropdown.bindAsEventListener(this);
  }
  this.completer.autoComplete.containerExpandEvent.subscribe(this.containerExpanded, this, true);
  this.completer.autoComplete.containerCollapseEvent.subscribe(this.containerCollapsed, this, true);
};
YAHOO.traction.SelectorPanel.prototype.hoverDropdown = function() {
  this.dropdown.className = "ddhover";
};
YAHOO.traction.SelectorPanel.prototype.__ignoreNextClick = false;
YAHOO.traction.SelectorPanel.prototype.mousedownDropdown = function() {
  if (this.completer.autoComplete.isContainerShowing()) {
    this.__ignoreNextClick = true;
  }
  this.dropdown.className = "dddown";
};
YAHOO.traction.SelectorPanel.prototype.mouseupDropdown = function() {
  this.dropdown.className = "dd";
};
YAHOO.traction.SelectorPanel.prototype.unhoverDropdown = function() {
  this.dropdown.className = "dd";  
};
YAHOO.traction.SelectorPanel.prototype.clickDropdown = function(e) {
  if (this.__ignoreNextClick) {
    this.__ignoreNextClick = false;
    return;
  }
  if (this.completer.autoComplete.isContainerShowing()) {
  } else {
    this.completer.focus();
    var self = this;
    setTimeout(function() {
		 self.completer.onInputClick(e);
	       },
	       1);
  }
};
YAHOO.traction.SelectorPanel.prototype.containerCollapsed = function(type, args, obj) {
  this.syncDropdown();
};
YAHOO.traction.SelectorPanel.prototype.containerExpanded = function(type, args, obj) {
  this.syncDropdown();
};
YAHOO.traction.SelectorPanel.prototype.syncDropdown = function() {
  if (this.completer.autoComplete.isContainerShowing()) {
    this.dropdown.src = "/images/dropup.gif";
  } else {
    this.dropdown.src = "/images/dropdown.gif";
  }
};
YAHOO.traction.SelectorPanel.prototype.labelAdded = function(selector, label, labels) {};
YAHOO.traction.SelectorPanel.prototype.labelRemoved = function(selector, label, labels) {
  this.completer.reset();
};
YAHOO.traction.SelectorPanel.prototype.labelSelected = function(label) {
  if (label == null) {
  } else {
    this.selector.add(label);
    this.selector.refresh();
    this.completer.clear();
  }
};
YAHOO.traction.SelectorPanel.prototype.selectorRefreshed = function(selector) {
  this.completer.position();
};
YAHOO.traction.SelectorPanel.prototype.moveTo = function(x,y) {
  this.panel.moveTo(x,y);  
};
YAHOO.traction.SelectorPanel.prototype.newproj = function(event) {
  this.completer.newproj();
};
YAHOO.traction.SelectorPanel.prototype.onhide = function() {
  cm.unlock();
  this.completer.blur();
};
YAHOO.traction.SelectorPanel.prototype.onshow = function() {
  this.completer.reset();
};
YAHOO.traction.SelectorPanel.prototype.onmove = function() {
  this.completer.position();
};
YAHOO.traction.SelectorPanel.prototype.getOtherLinksHTML = function() {
  return "";
};
YAHOO.traction.SelectorPanel.prototype.getCompleter = function(completer_text, panel) {
  var completer = new YAHOO.traction.LabelCompleter(completer_text, this, null, "wcR"); // perms for Internal6105 [ajm 02.Dec.2008]
  completer.onChooseLabel = panel.labelSelected.bind(panel);
  return completer;
};
YAHOO.traction.SelectorPanel.prototype.getSelector = function(selector_div, panel) {
  var selector = new YAHOO.traction.LabelSelector(selector_div);
  selector.onAdd = panel.labelAdded.bind(panel);
  selector.onRemove = panel.labelRemoved.bind(panel);
  selector.onRefresh = panel.selectorRefreshed.bind(panel);
  return selector;
};

//------------------------------------------------------------------------
// yui-traction.FastProjectFilterPanel

YAHOO.namespace("traction");

YAHOO.traction.FastProjectFilterPanel = function(list, id) {
  YAHOO.traction.FastProjectFilterPanel.superclass.constructor.call(this,
								    id,
								    i18n("projectchooser_title", "Choose Projects"),
								    { fieldLabelText: i18n("projectchooser_field_label", "Type a project"),
									helpBoxName : "projectchooser" });
  this.build();
  this.list = list;
  this.label = document.getElementById(list.prefix+"_label");
  this.button = document.getElementById(list.prefix+"_add");
  this.completer.clear();
};
YAHOO.extend(YAHOO.traction.FastProjectFilterPanel, YAHOO.traction.SelectorPanel);
YAHOO.traction.FastProjectFilterPanel.prototype.load = function() {
  this.selector.load_initial(this.list.projects);
};
YAHOO.traction.FastProjectFilterPanel.prototype.display = function() {
  this.load();
  var x=0, y=0;
  if (this.button != null) {
    var region = YAHOO.util.Dom.getRegion(this.button);
    x = region.right - 3;
    y = region.top + 25;
  }
  this.moveTo(x,y);
  this.show("");
};
YAHOO.traction.FastProjectFilterPanel.prototype.submit = function() {
  this.updateHidden();
  this.completer.clear();
  this.hide();  
  if (document.fm && document.fm.edit_title) {
    document.fm.edit_title.focus();
  }
};
YAHOO.traction.FastProjectFilterPanel.prototype.updateHidden = function() {
  this.list.update(this.selector.projects);
};
YAHOO.traction.FastProjectFilterPanel.prototype.projectSelected = function(project) {
  if (project == null) {
  } else {
    this.selector.add(new Traction.Project(project[0], project[1], project[2]));
    this.selector.refresh();
    this.completer.clear();
  }
};
YAHOO.traction.FastProjectFilterPanel.prototype.getCompleter = function(completer_text, panel) {
  var projCompleter = new YAHOO.traction.ProjectCompleter(completer_text, this, panel);
  projCompleter.initDataSource(new YAHOO.traction.ProjectDataSource(projCompleter, "a"));
  projCompleter.onChooseProject = panel.projectSelected.bind(panel);
  return projCompleter;
};
YAHOO.traction.FastProjectFilterPanel.prototype.getSelector = function(selector_div, panel) {
  var selector = new YAHOO.traction.ProjectSelector(selector_div);
  selector.onRefresh = panel.selectorRefreshed.bind(panel);
  return selector;
};

//------------------------------------------------------------------------
// yui-traction.LabelCompleter

YAHOO.namespace("traction");
YAHOO.traction.LabelCompleter = function(input, panel, dataSource, requireAnyPermission) {
  this.input = input;
  this.input.onclick = this.onInputClick.bind(this);
  this.panel = panel;
  this.pendingQuery = null;
  this.div = document.createElement("DIV");
  this.div.className = "completer-container";
  document.body.appendChild(this.div);
  this.dataSource = dataSource || new YAHOO.traction.LabelDataSource(null, this, requireAnyPermission);
  this.autoComplete = new YAHOO.traction.TractionAutoComplete(input, this.div, this.dataSource);
  this.autoComplete.typeAhead = true;
  this.autoComplete.queryDelay = 0;
  this.autoComplete.delimChar = '';
  this.autoComplete.minQueryLength = 0;
  this.autoComplete.maxQueryResults = 0;
  this.autoComplete.animSpeed = 0.2;
  this.autoComplete.formatResult = this.formatResult;
  this.autoComplete.maxResultsDisplayed = 100;
  this.autoComplete.autoHighlight = true;
  this.autoComplete.typeAhead = false;
  this.autoComplete.selectOn2ndColon = true;
  this.autoComplete.containerExpandEvent.subscribe(this.containerExpanded, this, true);
  this.autoComplete.itemSelectEvent.subscribe(this.itemSelected, this, true);
  this.autoComplete.unmatchedItemSelectEvent.subscribe(this.newItemSelected, this, true);
  this.autoComplete.textboxKeyEvent.subscribe(this.keyTyped, this, true);
  this.autoComplete.onEscWhenCollapsed = this.escWhenCollapsed.bind(this);
  this.position();
  YAHOO.traction.LabelCompleter.autoComplete = this.autoComplete;
};
YAHOO.traction.LabelCompleter.prototype.escWhenCollapsed = function() {
  this.panel.hide();
};
YAHOO.traction.LabelCompleter.prototype.setHeader = function(str) {
  this.autoComplete.setHeader(str);
};
YAHOO.traction.LabelCompleter.prototype.blur = function() {
  this.input.blur();
};
YAHOO.traction.LabelCompleter.prototype.reset = function() {
  if (this.project == null) {
    this.clear();
  } else {
  }
};
YAHOO.traction.LabelCompleter.prototype.setProject = function(project) {
  this.load(project);
};
YAHOO.traction.LabelCompleter.prototype.load = function(project) {
  this.project = project;
  this.dataSource.currentProject = project;
  if (project != null) {
    var state = { project: project };
    Traction.LabelCache.getLabels(project, this.doneGetLabels.bind(this), state);
  }
};
YAHOO.traction.LabelCompleter.prototype.onInputClick = function(event) {
  Debug.println("Event: onInputClick");
  this.autoComplete.sendQuery(this.input.value);
};
YAHOO.traction.LabelCompleter.prototype.formatResult = function(oResultItem, sQuery) {
  var text = oResultItem[0];
  var label = oResultItem[1];
  var ret = "";
  if (label == null) {
    if (sQuery.startsWith(":") || 
	sQuery.startsWith("/")) {
      sQuery = sQuery.substring(1);
    }
    var prefix = text.substring(0,sQuery.length);
    var suffix = text.substring(sQuery.length);
    ret += " ";
    ret += "<b>"+prefix+"</b>"+suffix;
  }
  else {
    if (label.icon != null) {
      ret += '<img src="'+label.icon+'">';
    } else {
      ret += '<img src="/images/modern/px.gif" width="16" height="16">';    
    }
    var lstr = label.label+""; // make sure this is a string
    var found = lstr.toLowerCase().indexOf(sQuery.toLowerCase());
    if (found != -1) {
      ret += label.label.substring(0,found);
      ret += "<b>"+label.label.substring(found,found+sQuery.length)+"</b>";
      ret += label.label.substring(found+sQuery.length);
    } else {
      ret += label.label;
    }
  }
  return ret; 
};
YAHOO.traction.LabelCompleter.prototype.clear = function() {
  this.input.value = "";
};
YAHOO.traction.LabelCompleter.prototype.doneGetLabels = function(responseText, state) {
};
YAHOO.traction.LabelCompleter.prototype.focus = function() {
  this.input.focus();
};

YAHOO.traction.LabelCompleter.prototype.onChooseLabel = null;

YAHOO.traction.LabelCompleter.prototype.itemSelected = function(type, args, obj) {
  var oData = args[2];
  var label = oData[1];
  if (label == null && oData[0] == '') {
    if (this.onChooseLabel != null) {
      this.onChooseLabel(null);
    }    
  }
  else if (label != null) {
    this.autoComplete.alwaysShowContainer = false;
    if (this.onChooseLabel != null) {
      this.onChooseLabel(label);
    }
    this.preserveProject(label);
  } else {
    var colon = Traction.Label.delim;
    var colonProjectColon = colon + oData[0] + colon;
    this.input.value = colonProjectColon;
    var end = colonProjectColon.length;
    this.selectRange(end,end);
    this.autoComplete.alwaysShowContainer = false;
    this.autoComplete.sendQuery(colonProjectColon);    
  }
};
YAHOO.traction.LabelCompleter.prototype.preserveProject = function(label) {
  var curproj = this.project;
  var labelproj = label.project;
  if (labelproj != null && labelproj != curproj) {
    var colon = Traction.Label.delim;
    var colonProjectColon = colon + labelproj + colon;
    this.input.value = colonProjectColon;
    var end = colonProjectColon.length;
    this.selectRange(end,end);
  }
};
YAHOO.traction.LabelCompleter.prototype.newproj = function() {
  var delim = Traction.Label.delim;
  this.input.value = delim;
  this.input.focus();
  var end = delim.length;
  this.selectRange(end,end);
  this.autoComplete.alwaysShowContainer = false;
  var self = this;
  setTimeout(function() {
	       self.autoComplete.sendQuery(delim);    
	     },
	     1);
};
YAHOO.traction.LabelCompleter.prototype.selectRange = function(start, end) {
  this.autoComplete._selectText(this.input,start,end);
};
YAHOO.traction.LabelCompleter.prototype._isProjectColon = function(val) {
  return ((val.startsWith(':') || val.startsWith('/')) &&
	  (val.endsWith(':')) || val.endsWith('/'));
};
YAHOO.traction.LabelCompleter.prototype.newItemSelected = function(type, args, obj) {
  var value = this.input.value.trim();
  if (value == '' || this._isProjectColon(value)) {
    this.panel.submit();
  } else {
    var arr = YAHOO.traction.LabelDataSource.splitProjectAndLabel(value);
    var label = Traction.Label.createNewLabel(arr[0], arr[1]);
    this.autoComplete.alwaysShowContainer = false;
    if (this.onChooseLabel != null) {
      this.onChooseLabel(label);
    }
    this.preserveProject(label);
  }
};
YAHOO.traction.LabelCompleter.prototype.keyTyped = function(type, args, obj) {
  this.autoComplete.alwaysShowContainer = false;
  var val = this.input.value;
  if (val.startsWith(':')) {
    Traction.Label.setDelimeter(':');
  } else if (val.startsWith('/')) {
    Traction.Label.setDelimeter('/');
  }
  Debug.println("value="+val);
};
YAHOO.traction.LabelCompleter.prototype.containerExpanded = function(type, args, obj) {
  var oSelf = args[0];
  if (this.pendingQuery != null) {
    var fireQuery = this.pendingQuery;
    this.pendingQuery = null;    
    this.autoComplete.sendQuery(fireQuery);
  }
  this.position();
};
YAHOO.traction.LabelCompleter.prototype.position = function() {


  var region = YAHOO.util.Dom.getRegion(this.input);
  YAHOO.util.Dom.setXY(this.div, new YAHOO.util.Point(region.left, region.bottom) );
  this.div.style.width = px(region.right - region.left);
};

//------------------------------------------------------------------------
// yui-traction.LabelDataSource

YAHOO.traction.LabelDataSource = function(currentProject, completer, requireAnyPermission) {
  this.currentProject = currentProject;
  this.completer = completer;
  this.requireAnyPermission = requireAnyPermission;
  this._init();
};
YAHOO.traction.LabelDataSource.prototype = new YAHOO.widget.DataSource();

YAHOO.traction.LabelDataSource.prototype.doQuery = function(oCallbackFn, sQuery, oParent) {
  var sOriginalQuery = sQuery;
  var isProjectCompletion = false;
  var proj = this.currentProject;
  Debug.println("doQuery: "+sQuery);
  if (sQuery == null) sQuery = "";
  sQuery = decodeURIComponent(sQuery);
  sQuery = sQuery.toLowerCase();
  var arr = YAHOO.traction.LabelDataSource.splitProjectAndLabel(sQuery);
  if (arr[0] != null) {
    if (arr[1] == null) {
      isProjectCompletion = true;
      sQuery = arr[0];
    } else {
      proj = arr[0];
      sQuery = arr[1];
    }
  }
  var state = { oCallbackFn: oCallbackFn, sOriginalQuery: sOriginalQuery, sQuery: sQuery, oParent: oParent, proj: proj };
  if (isProjectCompletion) {
    Traction.LabelCache.getProjects("R", this.doQuery_doneProjects.bind(this), state);  // reclassify
  } else {
    Traction.LabelCache.getLabels(proj, this.doQuery_doneLabels.bind(this), state, this.requireAnyPermission);
  }
};
YAHOO.traction.LabelDataSource.splitProjectAndLabel = function(str) {
  var proj = null;
  if (str.startsWith(":") ||
      str.startsWith("/")) {
    var nextSlash = str.indexOf("/", 1);
    var nextColon = str.indexOf(":", 1);
    var afterProject;
    if (nextColon == -1) {
      afterProject = nextSlash;
    }
    else if (nextSlash == -1) {
      afterProject = nextColon;
    }
    else {
      afterProject = (nextColon < nextSlash) ? nextColon : nextSlash;
    }
    if (afterProject == -1) {
      proj = str.substring(1);
      str = null;
    } else {
      proj = str.substring(1,afterProject);
      str = str.substring(afterProject+1);
    }  
  }
  return [ proj, str ];
};
YAHOO.traction.LabelDataSource.prototype.doQuery_doneLabels = function(labels, state) {
  var oParent = state.oParent;
  var sQuery = state.sQuery;
  var sOriginalQuery = state.sOriginalQuery;
  var aPrefixResults = new Array();
  var aInfixResults = new Array();
  if (sQuery == "") {
    aPrefixResults[aPrefixResults.length] = [ "", null ];
  }
  for (var i=0; i<labels.length; i++) {
    var cur = labels[i];
    if (sQuery == "" || cur.label.toLowerCase().startsWith(sQuery)) {
      aPrefixResults[aPrefixResults.length] = [ cur.label, cur ];
    }
    else if (cur.label.toLowerCase().indexOf(sQuery) != -1) {
      aInfixResults[aInfixResults.length] = [ cur.label, cur ];
    }
  }
  aResults = aPrefixResults.concat(aInfixResults);
  Debug.println(aResults.length + " ["+sQuery+"]");
  var proj = (labels.length > 0) ? labels[0].project : state.proj;
  var headingText = (new MessageFormat(i18n("labelchooser_label_matches_heading", "{0} label matches"))).format(proj);
  this.completer.setHeader();
  this.getResultsEvent.fire(this, oParent, sOriginalQuery, aResults);
  state.oCallbackFn(sOriginalQuery, aResults, oParent);
};
YAHOO.traction.LabelDataSource.prototype.doQuery_doneProjects = function(projects, state) {
  var oParent = state.oParent;
  var sQuery = state.sQuery;
  var sOriginalQuery = state.sOriginalQuery;
  if (sQuery == null) sQuery = "";
  sQuery = decodeURIComponent(sQuery);
  sQuery = sQuery.toLowerCase();
  var aResults = new Array();
  for (var i=0; i<projects.length; i++) {
    var cur = projects[i][0];
    if (sQuery == "" || cur.toLowerCase().startsWith(sQuery)) {
      aResults[aResults.length] = [ cur ];
    }
  }
  this.completer.setHeader(i18n("labelchooser_project_matches_heading", "project matches"));
  this.getResultsEvent.fire(this, oParent, sOriginalQuery, aResults);
  state.oCallbackFn(sOriginalQuery, aResults, oParent);
};

//------------------------------------------------------------------------
// yui-traction.LabelList

YAHOO.namespace("traction");
YAHOO.traction.LabelList = function(prefix, options, closeInsertLabelDialogBinding) {
  this.prefix = prefix;
  this.hidden = document.getElementById(prefix);
  this.setOptions(options);
  this.project = this.getCurrentProject();
  this.bindOnProjectChange();
  this.display = new YAHOO.traction.LabelListDisplay(this, this.project);
  this.display.sync();
  var self = this;
  if (typeof(closeInsertLabelDialogBinding) != "undefined") {
    closeInsertLabelDialog = closeInsertLabelDialogBinding;
  } else {
    closeInsertLabelDialog = function(labelArray) {
      ArticleEditWindow.onEditLabels(labelArray);
      self.display.sync();
    };
  }
  var addbutton = document.getElementById(prefix+"_add");
  if (addbutton != null) {
    addbutton.onclick = this.addclick.bind(this);
  }
};
YAHOO.traction.LabelList.prototype.setOptions = function(options) {
  this.options = {
    style : "autocomplete"
  }.extend(options || {});
};
YAHOO.traction.LabelList.prototype.bindOnProjectChange = function() {
  if (document.fm != null && document.fm.edit_project != null) {
    Events.attach(document.fm.edit_project, Events.Change, this, this.onProjectChange);
  }    
};
YAHOO.traction.LabelList.prototype.getCurrentProject = function() {
  var proj = null;
  if (document.fm != null && document.fm.edit_project != null) {
    proj = document.fm.edit_project.value;
    if (proj.startsWith("::")) {
      proj = proj.substring(2);
    }
  }
  return proj;
};
YAHOO.traction.LabelList.prototype.onProjectChange = function(event) {
  this.project = this.getCurrentProject();
  this.display.setProject(this.project);
  if (this.panel != null) {
    this.panel.setProject(this.project);
  }
};
YAHOO.traction.LabelList.display = function(prefix) {
};
YAHOO.traction.LabelList.prototype.sync = function() {
  this.display.sync();
};
YAHOO.traction.LabelList.prototype.updateFromHidden = function() {
};
YAHOO.traction.LabelList.prototype.setHidden = function(val) {
  this.hidden.value = val;
  this.display.sync();
};
YAHOO.traction.LabelList.prototype.addclick = function() {
  if (this.panel == null) {
    this.panel = new YAHOO.traction.LabelPanel(this, this.prefix+"_panel", this.options.style);
  }
  if (this.options.style == 'autocomplete') {
    this.panel.display();
  } else {
    this.panel.load();
    this.panel.browse();
  }
};

//------------------------------------------------------------------------
// yui-traction.LabelListDisplay

YAHOO.namespace("traction");
YAHOO.traction.LabelListDisplay = function(labellist, project) {
  this.labellist = labellist;
  this.project = project;
  this.span = document.getElementById(labellist.prefix + "_display");
  this.links = new Array();
};
YAHOO.traction.LabelListDisplay.prototype.sync = function() {
  var hiddenValue = this.labellist.hidden.value;
  hiddenValue = hiddenValue.trim();
  this.labels = Traction.Label.parselist(hiddenValue);
  this.refresh();
};
YAHOO.traction.LabelListDisplay.prototype.updateHidden = function(label) {
  var val = "";
  for (var i=0; i<this.labels.length; i++) {
    var cur = this.labels[i];
    if (val) val += ' ';
    val += cur.getRapidSelectorFormat();
  }
  this.labellist.hidden.value = val;
};

YAHOO.traction.LabelListDisplay.prototype.onRemoveLabel = null;
YAHOO.traction.LabelListDisplay.prototype.remove = function(label) {
  var i = indexOf(this.labels, label);
  if (i != -1) {
    this.labels.splice(i, 1);
    this.links.splice(i, 1);
    this.updateHidden();
  }
  if (this.onRemoveLabel != null) {
    this.onRemoveLabel(label);
  }
};

YAHOO.traction.LabelListDisplay.prototype.setProject = function(project) {
  this.project = project;
  this.refresh();
};
YAHOO.traction.LabelListDisplay.prototype.refresh = function() {
  this.span.innerHTML = "";
  for (var i=0; i<this.links.length; i++) {
    this.links[i].remove();
  }
  this.links = new Array();
  for (var i=0; i<this.labels.length; i++) {
    this.links[i] = new YAHOO.traction.LabelListLink(this.labels[i], this, this.project);
    if (i > 0) {
      this.span.appendChild(document.createTextNode(", "));
    }
    this.span.appendChild(this.links[i].element);
  }
  if (this.labels.length > 0) {
    this.span.appendChild(document.createTextNode("  "));
  }
  if (this.onRefresh != null) {
    this.onRefresh(this);
  }  
};

YAHOO.traction.LabelListDisplay.prototype.onRefresh = null;

//------------------------------------------------------------------------
// yui-traction.LabelListLink


YAHOO.namespace("traction");
YAHOO.traction.LabelListLink = function(label, list) {
  this.label = label;
  this.list = list;
  this.element = document.createElement("SPAN");
  if (this.label.isNew) { 
    this.element.innerHTML = this.label.getDisplayName(list.project) + " [new]";
  } else {
    this.element.innerHTML = this.label.getDisplayName(list.project);
  }
  this.element.onmouseout = this.unhover.bindAsEventListener(this);
  this.element.onclick = this.click.bindAsEventListener(this);
  this.element.onmousemove = this.hover.bindAsEventListener(this);
};

YAHOO.traction.LabelListLink.prototype.remove = function() {
  this.label = null;
  this.list = null;
};
YAHOO.traction.LabelListLink.prototype.click = function() {
  this.list.remove(this.label);
  this.list.refresh();
};
YAHOO.traction.LabelListLink.prototype.hover = function() {
  if (!this.locked) {
    this.element.style.textDecoration = "line-through";
    this.element.style.cursor = "pointer";
  }
};
YAHOO.traction.LabelListLink.prototype.unhover = function() {
  this.element.style.textDecoration = "none";
  this.element.style.cursor = "";
};

//------------------------------------------------------------------------
// yui-traction.LabelPanel

YAHOO.namespace("traction");
YAHOO.traction.LabelPanel = function(list, id, style) {
  YAHOO.traction.LabelPanel.superclass.constructor.call(this,
							id,
							i18n("labelchooser_title", "Choose Labels"),
							{ fieldLabelText: i18n("labelchooser_field_label", "Type a label"),
							    style: style,
							    helpBoxName : "labelchooser" });
  this.build();
  this.list = list;
  this.label = document.getElementById(list.prefix+"_label");
  this.completer.clear();
  this.setProject(list.project);
};
YAHOO.extend(YAHOO.traction.LabelPanel, YAHOO.traction.SelectorPanel);
YAHOO.traction.LabelPanel.prototype.load = function() {
  this.selector.load_hidden(this.list.project, this.list.hidden.value);
};
YAHOO.traction.LabelPanel.prototype.display = function() {
  this.load();
  var x=0, y=0;
  if (this.label != null) {
    var region = YAHOO.util.Dom.getRegion(this.label);
    x = region.right - 3;
    y = region.top - 6;
  }
  this.moveTo(x,y);
  this.show("");
};
YAHOO.traction.LabelPanel.prototype.browse = function(event) {
  this.updateHidden();
  this.completer.clear();
  this.hide();
  openInsertLabelDialogSimple(document.fm.edit_project.value, 
			      document.fm.edit_labels.value, 
			      '',
			      '&showcreate=true');
};
YAHOO.traction.LabelPanel.prototype.submit = function() {
  this.selector.addTextLeftInInput(this.completer);
  this.updateHidden();
  this.completer.clear();
  this.hide();  
  if (document.fm && document.fm.edit_title) {
    document.fm.edit_title.focus();
  }
};
YAHOO.traction.LabelPanel.prototype.updateHidden = function() {
  var labels = this.selector.labels;
  var rs = Traction.Label.arrayToRS(labels);
  this.list.setHidden(rs);  
};
YAHOO.traction.LabelPanel.prototype.getOtherLinksHTML = function() {
  return '<a href="javascript:void(0)" tabindex="10002" onclick="YAHOO.traction.SelectorPanel.get(\''+this.id+'\').newproj(event); return false;" style="line-height: 20px">' + i18n("labelchooser_change_projects_link_text", "Change project") + '</a> | <a href="javascript:void(0)" tabindex="10003" onclick="YAHOO.traction.SelectorPanel.get(\''+this.id+'\').browse(event); return false;" style="line-height: 20px">' + i18n("labelchooser_browse_labels_link_text", "Browse labels") + '</a>';
};

//------------------------------------------------------------------------
// yui-traction.LabelSelector


YAHOO.namespace("traction");
YAHOO.traction.LabelSelector = function(div) {
  this.div = div;
  this.clear();
};
YAHOO.traction.LabelSelector.prototype.refresh = function() {
  this.div.innerHTML = "";
  for (var i=0; i<this.links.length; i++) {
    this.links[i].remove();
  }
  this.links = new Array();
  for (var i=0; i<this.labels.length; i++) {
    this.links[i] = new YAHOO.traction.LabelSelectorLink(this.labels[i], this);
    this.div.appendChild(this.links[i].element);
  }
  if (this.onRefresh != null) {
    this.onRefresh(this);
  }
};
YAHOO.traction.LabelSelector.prototype.clear = function() {
  this.labels = new Array();
  this.links = new Array();
  this.adds = new Array();
  this.rems = new Array();
};

YAHOO.traction.LabelSelector.prototype.onAdd = null;
YAHOO.traction.LabelSelector.prototype.onRemove = null;

YAHOO.traction.LabelSelector.prototype.onRefresh = null;

YAHOO.traction.LabelSelector.prototype.add = function(label) {
  var rs = label.getRapidSelectorFormat();
  Debug.println("rs="+rs);
  for (var i=0; i<this.labels.length; i++) {
    Debug.println("rs0="+this.labels[i].getRapidSelectorFormat());
    if (rs == this.labels[i].getRapidSelectorFormat()) {
      return;
    }
  }
  this.labels[this.labels.length] = label;
  var wasJustRemoved = this.removeFromList(label, this.rems);
  if (!wasJustRemoved) {
    this.adds[this.adds.length] = label;
  }
  if (this.onAdd) {
    this.onAdd(this, label, this.labels);
  }
};
YAHOO.traction.LabelSelector.prototype.remove = function(label) {
  var i = indexOf(this.labels, label);
  if (i != -1) {
    this.labels.splice(i, 1);
    this.links.splice(i, 1);
  }
  var wasJustAdded = this.removeFromList(label, this.adds);
  if (!wasJustAdded) {
    this.rems[this.rems.length] = label;
  }
  if (this.onRemove) {
    this.onRemove(this, label, this.labels);
  }
};

YAHOO.traction.LabelSelector.prototype.removeFromList = function(label, list) {
  var rs = label.getRapidSelectorFormat();
  for (var i=0; i<list.length; i++) {
    if (rs == list[i].getRapidSelectorFormat()) {
      list.splice(i, 1);
      return true;
    }
  }
  return false;
};
YAHOO.traction.LabelSelector.prototype.hasAdds = function() {
  return (this.adds != null && this.adds.length > 0);
};
YAHOO.traction.LabelSelector.prototype.hasRemoves = function() {
  return (this.rems != null && this.rems.length > 0);
};
YAHOO.traction.LabelSelector.prototype.isNOOP = function() {
  return (!this.hasAdds() && !this.hasRemoves());
};
YAHOO.traction.LabelSelector.prototype.addTextLeftInInput = function(completer) {
  if (!this.hasAdds()) {
    var typedInTextbox = completer.input.value.trim();
    if (typedInTextbox == "") {
    }
    else if (typedInTextbox.endsWith(':') ||
	     typedInTextbox.endsWith('/')) {
    }
    else {
      var label = Traction.Label.createNewLabel(null, typedInTextbox);
      this.add(label);
    }
  }  
};
YAHOO.traction.LabelSelector.prototype.submitReclassification = function(tractionId) {
  if (this.rems.length == 0 && this.adds.length == 0) {
    return;
  }
  var newLabels = "";
  for (var i=0; i<this.labels.length; i++) {
    if (this.labels[i].isNew) {
      if (newLabels) {
	newLabels += "\n";
      }
      newLabels += "> "+this.labels[i].getDisplayName(tractionId.project);
    }
  }
  if (!newLabels ||
      confirm((new MessageFormat(i18n("labelchooser_new_label_confirmation_message",
				      "Are you sure you want to create the following new labels?\n{0}\n\n" +
				      "Click OK to submit and create new labels.\n" +
				      "Click Cancel to return to this page."))).format(newLabels))) {
    curItem = tractionId.toString();
    if (curItem.indexOf('.') == -1) {
      curItem += ".00";
    }
    var recat = new Traction.Reclassify(this.rems, this.adds, false, false);
    recat.execute(null, null);
    return true;
  } else {
    return false;
  }
};

YAHOO.traction.LabelSelector.prototype.load = function(tractionId) {
  this.project = tractionId.project;
  this.clear();
  this.refresh();
  var poststring = "";
  poststring = fm_append(poststring, "type=ajaxrpc");
  poststring = fm_append(poststring, "method=getItemLabels");
  poststring = fm_append(poststring, "curitem="+tractionId.toString());
  xmlpost_async(FORM_ACTION_READ_WRITE, poststring, null, true, this.load_done.bind(this), null);
};

YAHOO.traction.LabelSelector.prototype.load_none = function(project) {
  this.project = project;
  this.clear();
  this.refresh();
};

YAHOO.traction.LabelSelector.prototype.load_labels = function(project, labels) {
  this.clear();
  this.labels = labels;
  this.project = project;
  this.refresh();
};
YAHOO.traction.LabelSelector.prototype.load_hidden = function(project, val) {
  this.clear();
  this.labels = Traction.Label.parselist(val);
  this.project = project;
  this.refresh();
};

YAHOO.traction.LabelSelector.prototype.setProject = function(project) {
  this.project = project;
  this.refresh();
};

YAHOO.traction.LabelSelector.prototype.load_done = function(responseText, state) {
  if (responseText) {
    this.clear();
    var arr = eval(responseText);
    for (var i=0; i<arr.length; i++) {
      this.labels[i] = Traction.Label.fromArray(arr[i]);
    }
    this.refresh();
  }
};

//------------------------------------------------------------------------
// yui-traction.LabelSelectorLink


YAHOO.namespace("traction");
YAHOO.traction.LabelSelectorLink = function(label, selector) {
  this.label = label;
  this.selector = selector;
  this.element = document.createElement("DIV");
  if (this.label.isNew) { 
    this.element.innerHTML = this.label.getDisplayName(selector.project) + " [new]";
  } else {
    this.element.innerHTML = this.label.getDisplayName(selector.project);
  }
  this.element.onmouseout = this.unhover.bindAsEventListener(this);
  this.element.onclick = this.click.bindAsEventListener(this);
  this.element.onmousemove = this.hover.bindAsEventListener(this);
};

YAHOO.traction.LabelSelectorLink.prototype.remove = function() {
  this.label = null;
  this.selector = null;
};
YAHOO.traction.LabelSelectorLink.prototype.click = function() {
  this.selector.remove(this.label);
  this.selector.refresh();
};
YAHOO.traction.LabelSelectorLink.prototype.hover = function() {
  if (!this.locked) {
    this.element.style.textDecoration = "line-through";
    this.element.style.cursor = "pointer";
  }
};
YAHOO.traction.LabelSelectorLink.prototype.unhover = function() {
  this.element.style.textDecoration = "none";
  this.element.style.cursor = "";
};

//------------------------------------------------------------------------
// yui-traction.ProjectCompleter

YAHOO.namespace("traction");
YAHOO.traction.ProjectCompleter = function(input, formName, panel) {
  this.input = input;
  this.input.onclick = this.onInputClick.bind(this);
  this.panel = panel;
  this.pendingQuery = null;
  this.div = document.createElement("DIV");
  this.div.className = "completer-container";
  this.div.style.zIndex = 2000000;
  document.body.appendChild(this.div);
};
YAHOO.traction.ProjectCompleter.completersIntializedArray = null;
YAHOO.traction.ProjectCompleter.setup = function(input) {
  if (this.completersIntializedArray != null && this.completersIntializedArray[input.name]) return;
  if (this.completersIntializedArray == null) this.completersIntializedArray = new Array();
  var cur = new YAHOO.traction.ProjectCompleter(input, null);
  this.completersIntializedArray[input.name] = cur;
  cur.initDataSource(new YAHOO.traction.ProjectDataSource(cur, null));
};
YAHOO.traction.ProjectCompleter.prototype.initDataSource = function(projectDataSource) {
  this.dataSource = projectDataSource;
  this.autoComplete = new YAHOO.traction.TractionAutoComplete(this.input, this.div, this.dataSource);
  this.autoComplete.typeAhead = true;
  this.autoComplete.queryDelay = 0;
  this.autoComplete.delimChar = '';
  this.autoComplete.minQueryLength = 0;
  this.autoComplete.maxQueryResults = 0;
  this.autoComplete.animSpeed = 0.2;
  this.autoComplete.formatResult = this.formatResult;
  this.autoComplete.maxResultsDisplayed = 100;
  this.autoComplete.autoHighlight = true;
  this.autoComplete.allowBrowserAutocomplete = false;
  this.autoComplete.typeAhead = false;
  this.autoComplete.selectOn2ndColon = false;
  this.position();
  this.autoComplete.containerExpandEvent.subscribe(this.containerExpanded, this, true);
  this.autoComplete.itemSelectEvent.subscribe(this.itemSelected, this, true);
  this.autoComplete.unmatchedItemSelectEvent.subscribe(this.newItemSelected, this, true);
  this.autoComplete.onEscWhenCollapsed = this.escWhenCollapsed.bind(this);
};
YAHOO.traction.ProjectCompleter.prototype.itemSelected = function(type, args, obj) {
  var tProj = args[2];
  if (this.onChooseProject != null) {
    this.onChooseProject(tProj);
  }
};
YAHOO.traction.ProjectCompleter.prototype.newItemSelected = function(type, args, obj) {
  var value = this.input.value.trim();
  if (value == "") {
    this.panel.submit();
  }
};
YAHOO.traction.ProjectCompleter.prototype.selectRange = function(start, end) {
  this.autoComplete._selectText(this.input, start, end);
};
YAHOO.traction.ProjectCompleter.prototype.onInputClick = function(event) {
  this.autoComplete.sendQuery(this.input.value);
};
YAHOO.traction.ProjectCompleter.prototype.escWhenCollapsed = function() {
  this.panel.hide();
};
YAHOO.traction.ProjectCompleter.prototype.setHeader = function(str) {
  this.autoComplete.setHeader(str);
};
YAHOO.traction.ProjectCompleter.prototype.blur = function() {
  this.input.blur();
};
YAHOO.traction.ProjectCompleter.prototype.reset = function() {
  this.clear();
};
YAHOO.traction.ProjectCompleter.prototype.formatResult = function(oResultItem, sQuery) {
  var projectName        = oResultItem[0];
  var projectDisplayName = oResultItem[2];
  var displayText;
  if (projectName == projectDisplayName) {
    displayText = projectName;
  }
  else {
    displayText = projectDisplayName + " (" + projectName + ")";
  }
  var searchText = sQuery;
  var searchLen = sQuery.length;
  var finalDisplayText = "";
  if (searchLen > 0) {
    var matchText = displayText.toLowerCase();
    var lastMatch = matchText.indexOf(searchText);
    while (lastMatch != -1) {
      finalDisplayText += displayText.substring(0, lastMatch) + "<b>" +
	displayText.substring(lastMatch, lastMatch + searchLen) + "</b>";
      displayText = displayText.substring(lastMatch + searchLen);
      matchText = displayText.toLowerCase();
      lastMatch = matchText.indexOf(searchText, lastMatch+1);
    }
  }
  finalDisplayText += displayText;
  return finalDisplayText;
};
YAHOO.traction.ProjectCompleter.prototype.clear = function() {
  this.input.value = "";
};
YAHOO.traction.ProjectCompleter.prototype.focus = function() {
  this.input.focus();
};
YAHOO.traction.ProjectCompleter.prototype.position = function() {
  var region = YAHOO.util.Dom.getRegion(this.input);
  YAHOO.util.Dom.setXY(this.div, new YAHOO.util.Point(region.left, region.bottom) );
  var newWidth = region.right - region.left;
  if (newWidth < 300) newWidth = 300;
  this.div.style.width = px(newWidth);
};
YAHOO.traction.ProjectCompleter.prototype.containerExpanded = function(type, args, obj) {
  this.position();
};

//------------------------------------------------------------------------
// yui-traction.ProjectDataSource

YAHOO.traction.ProjectDataSource = function(completer, permissionChar) {
  this.completer = completer;
  this.permissionChar = ((permissionChar == null) ? "a" : permissionChar);
  this._init();
};
YAHOO.traction.ProjectDataSource.prototype = new YAHOO.widget.DataSource();

YAHOO.traction.ProjectDataSource.prototype.doQuery = function(oCallbackFn, sQuery, oParent) {
  var sOriginalQuery = sQuery;
  Debug.println("doQuery: "+sQuery);
  if (sQuery == null) sQuery = "";
  sQuery = decodeURIComponent(sQuery);
  sQuery = sQuery.toLowerCase();
  var state = { oCallbackFn: oCallbackFn, sOriginalQuery: sOriginalQuery, sQuery: sQuery, oParent: oParent };
  Traction.LabelCache.getProjects(this.permissionChar, this.doQuery_doneProjects.bind(this), state);  // access
};
YAHOO.traction.ProjectDataSource.prototype.doQuery_doneProjects = function(projects, state) {
  var oParent = state.oParent;
  var sQuery = state.sQuery;
  var sOriginalQuery = state.sOriginalQuery;
  if (sQuery == null) sQuery = "";
  sQuery = decodeURIComponent(sQuery);
  sQuery = sQuery.toLowerCase();
  var aResults = new Array();
  for (var i=0; i<projects.length; i++) {
    var cur = projects[i];
    if (sQuery == "" || cur[0].toLowerCase().startsWith(sQuery) || cur[2].toLowerCase().startsWith(sQuery)) {
      aResults[aResults.length] = cur;
    }
  }
  this.completer.setHeader(i18n("labelchooser_project_matches_heading", "project matches"));
  this.getResultsEvent.fire(this, oParent, sOriginalQuery, aResults);
  state.oCallbackFn(sOriginalQuery, aResults, oParent);
};

//------------------------------------------------------------------------
// yui-traction.ProjectList

YAHOO.namespace("traction");

YAHOO.traction.ProjectList = function(field, prefix, initialProjects, options) {
  this.prefix = prefix;
  this.hidden = field;
  this.setOptions(options);
  this.display = new YAHOO.traction.ProjectListDisplay(this, { noSelectionText: (this.options.useStarForNoProject ? i18n("All_Projects", "All Projects") : null) });
  var addbutton = this.hidden.form[prefix + "_add"];
  if (addbutton != null) {
    addbutton.onclick = this.addclick.bind(this);
  }
  this.initWithProjects(initialProjects);
};
YAHOO.traction.ProjectList.prototype.setOptions = function(options) {
  this.options = {
    useStarForNoProject: false,
    permissionChar: 'a'
  }.extend(options || {});
};
YAHOO.traction.ProjectList.display = function(prefix) {
};
YAHOO.traction.ProjectList.prototype.sync = function() {
  this.display.sync();
};
YAHOO.traction.ProjectList.prototype.updateFromHidden = function(projname2project) {
  var projNamesStr = this.hidden.value;
  this.projects = new Array();
  if (projNamesStr != null && projNamesStr.trim() != "") {
    var projectList = new Array();
    var projNameList = projNamesStr.split(",");
    for (var i = 0; i < projNameList.length; i ++) {
      var newProj = projname2project[projNameList[i]];
      if (newProj == null) {
	Traction.LabelCache.getProjects(this.options.permissionChar, this.doQuery_doneProjects.bind(this), state)
      }
      this.projects.push(new Traction.Project(newProj.getName(),
					      newProj.getID(),
					      newProj.getDisplayName()));
    }
  }
  this.display.sync(this.projects);
};
YAHOO.traction.ProjectList.prototype.initWithProjects = function(newProjects) {
  this.projects = new Array();
  var projs = "";
  for (var i = 0; i < newProjects.length; i ++) {
    this.projects.push(newProjects[i]);
    if (projs) {
      projs += ",";
    }
    projs += newProjects[i].getName();
  }
  this.display.sync(this.projects);
  return projs;
};
YAHOO.traction.ProjectList.prototype.update = function(newProjects) {
  var fieldVal = this.initWithProjects(newProjects);
  this.hidden.value = (fieldVal == "") ? (this.options.useStarForNoProject ? "*" : "") : fieldVal;
  if (typeof(this.options.onUpdate) == "function") {
    this.options.onUpdate(this.projects);
  }
};
YAHOO.traction.ProjectList.prototype.addclick = function() {
  if (this.panel == null) {
    this.panel = new YAHOO.traction.FastProjectFilterPanel(this, this.prefix + "_panel", { useStarForNoProject: this.useStarForNoProject });
  }
  this.panel.display();
};

//------------------------------------------------------------------------
// yui-traction.ProjectListDisplay

YAHOO.namespace("traction");
YAHOO.traction.ProjectListDisplay = function(projectList, options) {
  this.projectList = projectList;
  this.span = document.getElementById(projectList.prefix + "_display");
  this.links = new Array();
  this.setOptions(options);
};
YAHOO.traction.ProjectListDisplay.prototype.setOptions = function(options) {
  this.options = {
    noSelectionText: i18n("None", "None")
  }.extend(options || {});
};
YAHOO.traction.ProjectListDisplay.prototype.sync = function(projects) {
  this.refresh();
};

YAHOO.traction.ProjectListDisplay.prototype.onRemoveProject = null;
YAHOO.traction.ProjectListDisplay.prototype.remove = function(project) {
  var i = indexOf(this.projectList.projects, project);
  if (i != -1) {
    this.projectList.projects.splice(i, 1);
    this.links.splice(i, 1);
    this.projectList.update(this.projectList.projects);
  }
  if (this.onRemoveProject != null) {
    this.onRemoveProject(project);
  }
};
YAHOO.traction.ProjectListDisplay.prototype.refresh = function() {
  this.span.innerHTML = "";
  for (var i=0; i<this.links.length; i++) {
    this.links[i].remove();
  }
  this.links = new Array();
  if (this.projectList.projects.length == 0) {
    var subSpan = document.createElement("SPAN");
    var textNode = document.createTextNode(this.options.noSelectionText);
    subSpan.style.fontStyle = "italic";
    subSpan.appendChild(textNode);
    this.span.appendChild(subSpan);
  }
  else {
    for (var i = 0; i < this.projectList.projects.length; i ++) {
      this.links[i] = new YAHOO.traction.ProjectListLink(this.projectList.projects[i], this);
      if (i > 0) {
	this.span.appendChild(document.createTextNode(", "));
      }
      this.span.appendChild(this.links[i].element);
    }
  }
  if (this.onRefresh != null) {
    this.onRefresh(this);
  }  
};
YAHOO.traction.ProjectListDisplay.prototype.onRefresh = null;

//------------------------------------------------------------------------
// yui-traction.ProjectListLink


YAHOO.namespace("traction");
YAHOO.traction.ProjectListLink = function(project, list) {
  this.project = project;
  this.list = list;
  this.element = document.createElement("SPAN");
  this.element.innerHTML = this.project.getDisplayName();
  this.element.onmouseout = this.unhover.bindAsEventListener(this);
  this.element.onclick = this.click.bindAsEventListener(this);
  this.element.onmousemove = this.hover.bindAsEventListener(this);
};

YAHOO.traction.ProjectListLink.prototype.remove = function() {
  this.project = null;
  this.list = null;
};
YAHOO.traction.ProjectListLink.prototype.click = function() {
  this.list.remove(this.project);
  this.list.refresh();
};
YAHOO.traction.ProjectListLink.prototype.hover = function() {
  if (!this.locked) {
    this.element.style.textDecoration = "line-through";
    this.element.style.cursor = "pointer";
  }
};
YAHOO.traction.ProjectListLink.prototype.unhover = function() {
  this.element.style.textDecoration = "none";
  this.element.style.cursor = "";
};

//------------------------------------------------------------------------
// yui-traction.ProjectSelector


YAHOO.namespace("traction");
YAHOO.traction.ProjectSelector = function(div) {
  this.div = div;
  this.clear();
};
YAHOO.traction.ProjectSelector.prototype.refresh = function() {
  this.div.innerHTML = "";
  for (var i=0; i<this.links.length; i++) {
    this.links[i].remove();
  }
  this.links = new Array();
  for (var i=0; i<this.projects.length; i++) {
    this.links[i] = new YAHOO.traction.ProjectSelectorLink(this.projects[i], this);
    this.div.appendChild(this.links[i].element);
  }
  if (this.onRefresh != null) {
    this.onRefresh(this);
  }
};
YAHOO.traction.ProjectSelector.prototype.clear = function() {
  this.projects = new Array();
  this.links = new Array();
  this.adds = new Array();
  this.rems = new Array();
};
YAHOO.traction.ProjectSelector.prototype.onAdd = null;
YAHOO.traction.ProjectSelector.prototype.onRemove = null;
YAHOO.traction.ProjectSelector.prototype.onRefresh = null;

YAHOO.traction.ProjectSelector.prototype.add = function(project) {
  var projName = project.getName();
  for (var i = 0; i < this.projects.length; i ++) {
    Debug.println(this.projects[i].toString());
    if (projName == this.projects[i].getName()) {
      return;
    }
  }
  this.projects.push(project);
  if (this.onAdd) {
    this.onAdd(this, project, this.projects);
  }
};
YAHOO.traction.ProjectSelector.prototype.remove = function(project) {
  var i = indexOf(this.projects, project);
  if (i != -1) {
    this.projects.splice(i, 1);
    this.links.splice(i, 1);
  }
  if (this.onRemove) {
    this.onRemove(this, project, this.projects);
  }
};
YAHOO.traction.ProjectSelector.prototype.load_none = function() {
  this.clear();
  this.refresh();
};
YAHOO.traction.ProjectSelector.prototype.load_initial = function(initialProjects) {
  this.clear();
  for (var i = 0; i < initialProjects.length; i ++) {
    this.projects.push(initialProjects[i]);
  }
  this.refresh();
};

//------------------------------------------------------------------------
// yui-traction.ProjectSelectorLink


YAHOO.namespace("traction");
YAHOO.traction.ProjectSelectorLink = function(project, selector) {
  this.project = project;
  this.selector = selector;
  this.element = document.createElement("DIV");
  this.element.innerHTML = this.project.getDisplayName(selector.project);
  this.element.onmouseout = this.unhover.bindAsEventListener(this);
  this.element.onclick = this.click.bindAsEventListener(this);
  this.element.onmousemove = this.hover.bindAsEventListener(this);
};

YAHOO.traction.ProjectSelectorLink.prototype.remove = function() {
  this.project = null;
  this.selector = null;
};
YAHOO.traction.ProjectSelectorLink.prototype.click = function() {
  this.selector.remove(this.project);
  this.selector.refresh();
};
YAHOO.traction.ProjectSelectorLink.prototype.hover = function() {
  if (!this.locked) {
    this.element.style.textDecoration = "line-through";
    this.element.style.cursor = "pointer";
  }
};
YAHOO.traction.ProjectSelectorLink.prototype.unhover = function() {
  this.element.style.textDecoration = "none";
  this.element.style.cursor = "";
};

//------------------------------------------------------------------------
// yui-traction.ReclassifyPanel

YAHOO.namespace("traction");
YAHOO.traction.ReclassifyPanel = function() {
  YAHOO.traction.ReclassifyPanel.superclass.constructor.call(this,
							     "reclassify_panel",
							     i18n("labelchooser_reclassify_title", "Change Labels"),
							     { fieldLabelText: i18n("labelchooser_field_label", "Type a label"),
								 helpBoxName : "labelchooser" });
};
YAHOO.extend(YAHOO.traction.ReclassifyPanel, YAHOO.traction.SelectorPanel);
YAHOO.traction.ReclassifyPanel.addlabels = function(windowUrl, param, labels) {
  var adds = "";
  for (var i=0; i<labels.length; i++) {
    if (adds) adds += ",";
    adds += labels[i].getRapidSelectorFormat();
  }
  if (adds) {
    windowUrl += "&"+param+"="+encode_url_parameter(adds);
  }
  return windowUrl;
};
YAHOO.traction.ReclassifyPanel.display = function(tractionIdSpec, opttype) {
  if (ua("supports_ajax_label_chooser", "true") == "false") {
    return false;
  }
  if (this.skipPanel) {
    this.skipPanel = false;
    var action = "ReclassifyPopup";
    var windowUrl = "/traction/post?type=reclassifydialog&origtype="+document.fm.type.value;
    if (this.mypanel != null && this.mypanel.selector != null) {
      windowUrl = this.addlabels(windowUrl, "addlabels", this.mypanel.selector.adds)
      windowUrl = this.addlabels(windowUrl, "remlabels", this.mypanel.selector.rems)
    }
    var windowName = "";
    var windowFeatures = ua("modern_insertlabel_window_features") + getSizeAndPosition(ua("modern_insertlabel_window_width"), ua("modern_insertlabel_window_height"));
    executeNewActionUrl(action, opttype, windowUrl, windowName, windowFeatures);
    return true;
  }
  if (this.mypanel == null) {
    this.mypanel = new YAHOO.traction.ReclassifyPanel();
    this.mypanel.build();
  }
  var id = Traction.ID.parse(tractionIdSpec);
  this.mypanel.tractionId = id;
  if (opttype == "entry") {
    this.mypanel.tractionId = id = id.removeItem();
    curItem = tractionIdSpec = id.toString()+".00";
    if (!this.positionByLabels(tractionIdSpec)) {
      if (!this.positionByCommentDIV(id)) {
	this.positionByHover();
      }
    }
  } else {
    if (!this.positionByHover()) {
      if (!this.positionByLabels(tractionIdSpec)) {
	this.positionByCommentDIV(id);
      }
    }
  }
  Debug.println("ReclassifyPanel.display: "+tractionIdSpec+", "+opttype);
    this.mypanel.selector.load(id);
  this.mypanel.completer.clear();
  this.mypanel.completer.load(id.project);
  this.mypanel.show((new MessageFormat(i18n("labelchooser_reclassify_panel_heading", "Labels for {0}"))).format(id.toString()));
  return true;
};
YAHOO.traction.ReclassifyPanel.positionByLabels = function(tractionIdSpec) {
  var ltaID = tractionIdSpec.toLowerCase() + "_LTA";
  var lta = document.getElementById(ltaID);
  if (lta != null) {
    var lta_bounds = Util.getElementBounds(lta);
    var lta_xy = YAHOO.util.Dom.getXY(lta);
    var panel_bounds = Util.getElementBounds(this.mypanel.panel.element);
    var x = lta_xy[0] + lta_bounds.w - panel_bounds.w;
    var y = lta_xy[1];
    x += 20;
    y -= 7;
    this.mypanel.moveTo(x, y);
    return true;
  } else {
    return false;
  }
};
YAHOO.traction.ReclassifyPanel.positionByHover = function() {
  if (itemMenu != null) {
    var bounds = itemMenu.bounds;
    if (bounds != null) {
      var panel_bounds = Util.getElementBounds(this.mypanel.panel.element);
      var x = bounds.x + bounds.w - panel_bounds.w;
      var y = bounds.y;
      x += 18;
      this.mypanel.moveTo(x, y);
      return true;
    }
  }
  return false;
};
YAHOO.traction.ReclassifyPanel.positionByCommentDIV = function(id) {
  var commentDIV = document.getElementById(id.project.toLowerCase() + id.entry + "c");
  if (commentDIV != null) {
    var commentDIV_bounds = Util.getElementBounds(commentDIV);
    var commentDIV_xy = YAHOO.util.Dom.getXY(commentDIV);
    var panel_bounds = Util.getElementBounds(this.mypanel.panel.element);
    var x = commentDIV_xy[0] + commentDIV_bounds.w - panel_bounds.w;
    var y = commentDIV_xy[1];
    x += 20;
    y -= 7;
    this.mypanel.moveTo(x, y);
    return true;
  } else {
    return false;
  }
};

YAHOO.traction.ReclassifyPanel.prototype.browse = function(event) {
  this.hide();
  YAHOO.traction.ReclassifyPanel.skipPanel = true;
  cm.execute(event,'Reclassify',curItem);
};

YAHOO.traction.ReclassifyPanel.prototype.submit = function() {
  this.selector.addTextLeftInInput(this.completer);
  if (this.selector.submitReclassification(this.tractionId)) {
    this.completer.clear();
    this.hide();
  }
};
YAHOO.traction.ReclassifyPanel.prototype.getOtherLinksHTML = function() {
  return '<a href="javascript:void(0)" tabindex="10002" onclick="YAHOO.traction.SelectorPanel.get(\''+this.id+'\').newproj(event); return false;" style="line-height: 20px">' + i18n("labelchooser_change_projects_link_text", "Change project") + '</a> | <a href="javascript:void(0)" tabindex="10003" onclick="YAHOO.traction.SelectorPanel.get(\''+this.id+'\').browse(event); return false;" style="line-height: 20px">' + i18n("labelchooser_browse_labels_link_text", "Browse labels") + '</a>';
};

//------------------------------------------------------------------------
// yui-traction.SectionListLabelList

YAHOO.namespace("traction");
YAHOO.traction.SectionListLabelList = function(sectionListSetting, prefix, closeInsertLabelDialogBinding) {
  this.sectionListSetting = sectionListSetting;
  var self = this;
  this.sectionListSetting.onChooseLabels = function(labelArray) {
    closeInsertLabelDialog = this.__closeInsertLabelDialog;
    var set = "";
    if (labelArray != null) {
      for (var i=0; i<labelArray.length; i++) {
	set += labelArray[i] + " ";
      }
    }
    document.fm[this.fieldNamespace + "_cur_labels"].value = set;
    this.makeDirty();
    self.display.sync();
  };
  YAHOO.traction.SectionListLabelList.superclass.constructor.call(this, prefix, closeInsertLabelDialogBinding);
  this.display.onRemoveLabel = function() {
    sectionListSetting.makeDirty("labels");
  };
};
YAHOO.extend(YAHOO.traction.SectionListLabelList, YAHOO.traction.LabelList);
YAHOO.traction.SectionListLabelList.prototype.addclick = function() {
  if (this.panel == null) {
    this.panel = new YAHOO.traction.SectionListLabelPanel(this.sectionListSetting, this, this.prefix+"_panel");
  }  
  this.panel.load();
  this.panel.browse(null);
};
YAHOO.traction.SectionListLabelList.prototype.bindOnProjectChange = function() {
  if (document.fm != null && document.fm[this.sectionListSetting.fieldNamespace + "_cur_proj"] != null) {
    Events.attach(document.fm[this.sectionListSetting.fieldNamespace + "_cur_proj"], Events.Change, this, this.onProjectChange);
  }    
};
YAHOO.traction.SectionListLabelList.prototype.getCurrentProject = function() {
  return this.sectionListSetting.projectName;
};

//------------------------------------------------------------------------
// yui-traction.SectionListLabelPanel

YAHOO.namespace("traction");
YAHOO.traction.SectionListLabelPanel = function(sectionListSetting, list, id) {
  YAHOO.traction.SectionListLabelPanel.superclass.constructor.call(this, list, id);
  this.sectionListSetting = sectionListSetting;
};
YAHOO.extend(YAHOO.traction.SectionListLabelPanel, YAHOO.traction.LabelPanel);
YAHOO.traction.SectionListLabelPanel.prototype.browse = function(event) {
  this.updateHidden();
  this.completer.clear();
  this.hide();
  this.sectionListSetting.onEditLabelsClick(this.sectionListSetting.projectName);
};
YAHOO.traction.SectionListLabelPanel.prototype.submit = function() {
  YAHOO.traction.SectionListLabelPanel.superclass.submit.call(this);   
  this.sectionListSetting.makeDirty();
};

//------------------------------------------------------------------------
// yui-traction.SectionsLabelList

YAHOO.namespace("traction");
YAHOO.traction.SectionsLabelList = function(prefix) {
  YAHOO.traction.SectionsLabelList.superclass.constructor.call(this, prefix);
  var self = this;
  closeInsertLabelDialog = function(labelArray) {
    var set = "";
    if (labelArray != null) {
      for (var i=0; i<labelArray.length; i++) {
	set += labelArray[i] + " ";
      }
    }
    document.fm.cur_labels.value = set;
    makeDirty();
    ssync();
    self.display.sync();
  };
  this.display.onRemoveLabel = function(label) {
    makeDirty();
    ssync();
  };
};
YAHOO.extend(YAHOO.traction.SectionsLabelList, YAHOO.traction.LabelList);
YAHOO.traction.SectionsLabelList.prototype.addclick = function() {
  if (this.panel == null) {
    this.panel = new YAHOO.traction.SectionsLabelPanel(this, this.prefix+"_panel");
  }  
  this.panel.load();
  this.panel.browse(null);
};
YAHOO.traction.SectionsLabelList.prototype.bindOnProjectChange = function() {
  if (document.fm != null && document.fm.cur_proj != null) {
    Events.attach(document.fm.cur_proj, Events.Change, this, this.onProjectChange);
  }    
};
YAHOO.traction.SectionsLabelList.prototype.getCurrentProject = function() {
  return sectionsproj;
};

//------------------------------------------------------------------------
// yui-traction.SectionsLabelPanel

YAHOO.namespace("traction");
YAHOO.traction.SectionsLabelPanel = function(list, id) {
  YAHOO.traction.SectionsLabelPanel.superclass.constructor.call(this, list, id);
};
YAHOO.extend(YAHOO.traction.SectionsLabelPanel, YAHOO.traction.LabelPanel);
YAHOO.traction.SectionsLabelPanel.prototype.browse = function(event) {
  this.updateHidden();
  this.completer.clear();
  this.hide();
  sections_openlabels(sectionsproj);  
};
YAHOO.traction.SectionsLabelPanel.prototype.submit = function() {
  YAHOO.traction.SectionsLabelPanel.superclass.submit.call(this);   
  makeDirty();
  ssync();
};

//------------------------------------------------------------------------
// yui-traction.TabularDataAccumulator

Traction.TabularDataAccumulator = Class.create();
Traction.TabularDataAccumulator.prototype = {
  options: null,
  dataWidgets: {
    
    dataSource: null,
    
    dataTable: null
  },
  initialize: function(options) {
    this.options = options;
    if (this.options.existingTableID) {
      this.dataWidgets.dataSource = new YAHOO.util.DataSource(YAHOO.util.Dom.get(this.options.existingTableID));
      this.dataWidgets.dataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
    } else {
      this.dataWidgets.dataSource = new YAHOO.util.DataSource([]);
      this.dataWidgets.dataSource.responseType = YAHOO.util.DataSource.TYPE_JSARRAY;
    }
    this.dataWidgets.dataSource.responseSchema = { fields: this.options.fields };
    var dataTableConfigurations = {
      sortedBy: this.options.sortOptions
    };
    this.dataWidgets.dataTable = new YAHOO.widget.DataTable(this.options.containerID, this.options.columnDefs, this.dataWidgets.dataSource, dataTableConfigurations);
  }
};

//------------------------------------------------------------------------
// yui-traction.TabularDataBrowser

Traction.TabularDataBrowser = Class.create();
Traction.TabularDataBrowser.prototype = {
  
  filterString: "",
  
  historyID: null,
  
  _tableInitialized: false,
  initialize: function(options) {
    this.historyID = "TractionTabularDataBrowser" + Traction.TabularDataBrowser.getNextID();
    this.options = options;
    Traction.TabularDataBrowser._fixDataTableDisplay();
    this.initEventHandlers();
  },
  initTableDisplay: function() {
    if (this._tableInitialized) {
      return;
    }
    Debug.println(this.historyID, ": initTableDisplay");
    var History = YAHOO.util.History;
    this.initialState =
      History.getBookmarkedState(this.historyID) ||
      this.generateStateString(0,
			       this.options.defaultSortKey,
			       this.options.defaultSortOrder,
			       this.options.defaultRowsPerPage,
			       this.filterString,
			       this.options.statusFilterCheckbox.checked);
    History.register(this.historyID, this.initialState, this.handleHistoryNavigation.bind(this));
    History.onReady(this.initDataSourceAndTable.bind(this));
    History.initialize(this.options.historyFieldName, this.options.historyFrameName);
    this._tableInitialized = true;
  },
  initEventHandlers: function() {
    Debug.println(this.historyID, ": initEventHandlers");
    Events.attach(this.options.filterField,          Events.KeyUp,  this, this.onFilterEnter);
    Events.attach(this.options.searchButton,         Events.Click,  this, this.onSearchClick);
    Events.attach(this.options.statusFilterCheckbox, Events.Click,  this, this.onToggleShowInactive);
    Events.attach(this.options.resetButton,          Events.Click,  this, this.onFilterClear);
    this.options.form.onsubmit = function() { return false; };
  },
  
  generateStateString: function(start, key, dir, numResults, filter, inactive) {
    start = start || 0;
    key   = key || this.options.defaultSortKey;
    dir   = dir || this.options.defaultSortOrder;
    numResults = numResults || this.options.defaultRowsPerPage;
    inactive = inactive ? "true" : "false";
    var filterParam = "";
    if (filter != null && filter != "") {
      filterParam = "&filter=" + encode_url_parameter(filter);
    }
    return "numResults=" + numResults + "&startIndex=" + start + "&sort=" + key + "&direction=" + dir + "&inactive=" + inactive + filterParam;
  },
  
  parseStateString: function(state) {
    var parsed = {
      results    : /\bnumResults=(\d+)/.test(state) ? parseInt(RegExp.$1) : 15,
      startIndex : /\bstartIndex=(\d+)/.test(state) ? parseInt(RegExp.$1) : 0,
      filter     : /\bfilter=(\w+)/.test(state)     ? RegExp.$1 : "",
      inactive   : /\binactive=(\w+)/.test(state)   ? ((RegExp.$1 == "true") ? true : false) : false,
      sort       : /\bsort=(\w+)/.test(state)       ? RegExp.$1 : this.options.defaultSortKey,
      dir        : /\bdirection=(\w+)/.test(state)  ? RegExp.$1 : this.options.defaultSortOrder
    };
    return parsed;
  },
  resetDisplay: function() {
    var currentState = YAHOO.util.History.getCurrentState(this.historyID) ||
        this.initialState,
        parsed       = this.parseStateString(currentState);
    parsed.filter   = this.filterString;
    parsed.inactive = this.options.statusFilterCheckbox.checked;
    var newBookmark = this.generateStateString(0,
					       parsed.sort,
					       parsed.dir,
					       parsed.results,
					       parsed.filter,
					       parsed.inactive);
    Debug.println(this.historyID, ": Resetting data (filter change: ", newBookmark, ")");
    YAHOO.util.History.navigate(this.historyID, newBookmark);
  },
  
  dataWidgets: {
    
    dataSource: null,
    
    dataTable: null,
    
    paginator: null
  },
  
  handleHistoryNavigation: function(state) {
    Debug.println(this.historyID, ": handling history nav bookmark: ", state);
    var parsed = this.parseStateString(state);
    this.sendRequest(state);
    this.dataWidgets.paginator.setRowsPerPage(parsed.results, true);
    this.filterString = parsed.filter;
    this.options.filterField.value             = parsed.filter;
    this.options.statusFilterCheckbox.checked     = parsed.inactive;
  },
  
  handleResponseSuccess: function(oRequest, oParsedResponse, oPayload) {
    Debug.println("oParsedResponse.meta.totalRecords = ", oParsedResponse.meta.totalRecords,
		  " / this.dataWidgets.paginator.getRowsPerPage() = ", this.dataWidgets.paginator.getRowsPerPage());
    if (oParsedResponse.meta.totalRecords < this.dataWidgets.paginator.getRowsPerPage()) {
      Debug.println(this.historyID, ": Removing rows from ", (oParsedResponse.meta.totalRecords));
      try {
	this.dataWidgets.dataTable.deleteRows(oParsedResponse.meta.totalRecords, 10000);
      } catch (x) {
	Debug.println(this.historyID, " - Error: ", x);
      }
    }
    this.dataWidgets.dataTable.onDataReturnSetRows(oRequest, oParsedResponse, oPayload);
    this.dataWidgets.paginator.setTotalRecords(oParsedResponse.meta.totalRecords, true);
  },
  sendRequest: function(state) {
    var requestOptions = {
      success: this.handleResponseSuccess.bind(this),//this.dataWidgets.dataTable.onDataReturnSetRows,
      failure: this.dataWidgets.dataTable.onDataReturnSetRows,
      scope  : this.dataWidgets.dataTable
    };
    Debug.println(this.historyID, ": Sending request: ", state);
    this.dataWidgets.dataSource.sendRequest(state,
					    requestOptions);
  },
  initialState: null,
  initDataSourceAndTable: function() {
    Debug.println(this.historyID, ": initDataSourceAndTable");
    var initialRequest = YAHOO.util.History.getCurrentState(this.historyID) || this.initialState;
    var state          = this.parseStateString(initialRequest);
    Debug.println(this.historyID, ": initialRequest");
    this.dataWidgets.dataSource = new YAHOO.util.DataSource(FORM_ACTION_READ_ONLY + "?type=" + this.options.dataSourceViewType + "&");
    this.dataWidgets.dataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
    this.dataWidgets.dataSource.responseSchema = {
      resultsList: "records",
      fields: this.options.fields,
      metaFields: {
	totalRecords: "totalRecords",
	paginationRecordOffset : "startIndex",
	sortKey: "sort",
	sortDir: "dir"
      }
    };
    if (YAHOO.widget.DataTable) {
      YAHOO.widget.DataTable.MSG_EMPTY = this.options.emptyMsg || "No records found.";
    }
    var paginatorOptions = {
      rowsPerPage : state.results,
      recordOffset : state.startIndex,
      pageLinks: 3,
      rowsPerPageOptions : ["5", "10", "15", "20", "25", "50", "100", "250", "500", "1000", "2500", "5000"],
      containers : ["browser-page-nav"],
      template : i18n("ssetup_people_paginator_controls_template", "<strong>{CurrentPageReport}</strong> {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} Show {RowsPerPageDropdown} per page"),
      pageReportTemplate : i18n("ssetup_people_paginator_summary", "Showing items {startRecord} - {endRecord} of {totalRecords}"),
      firstPageLinkLabel: "&lt;&lt;&nbsp;" + i18n("ssetup_people_paginator_controls_first_link_text", "first"),
      previousPageLinkLabel: "&lt;&nbsp;" + i18n("ssetup_people_paginator_controls_previous_link_text", "prev"),
      nextPageLinkLabel: i18n("ssetup_people_paginator_controls_next_link_text", "next") + "&nbsp;&gt;",
      lastPageLinkLabel: i18n("ssetup_people_paginator_controls_last_link_text", "last") + "&nbsp;&gt;&gt;"
    };
    this.dataWidgets.paginator = new YAHOO.widget.Paginator(paginatorOptions);
    var myConfig = {
      paginator: this.dataWidgets.paginator,
      paginationEventHandler: this.handlePagination.bind(this),
      sortedBy: {
	key: state.sort,
	dir: state.dir
      },
      initialRequest: initialRequest
    };
    this.dataWidgets.dataTable =
      new YAHOO.widget.DataTable(this.options.containerID, // The dom element to contain the DataTable
				 this.options.columnDefs,        // What columns will display
				 this.dataWidgets.dataSource,        // The DataSource for our records
				 myConfig             // Other configurations
				 );
    this.dataWidgets.dataTable.subscribe("checkboxClickEvent", this.options.toggleStatusListener, this.dataWidgets.dataTable, true);
    this.dataWidgets.dataSource.subscribe("requestEvent",  this.options.requestListener);
    this.dataWidgets.dataSource.subscribe("responseEvent", this.options.responseListener);
    this.dataWidgets.dataTable.sortColumn = this.handleSorting.bind(this);
  },
  
  handlePagination: function(state, datatable) {
    Debug.println(this.historyID, ": handlePagination");
    var sortedBy  = datatable.get("sortedBy");
    var newState = this.generateStateString(state.recordOffset,
					    sortedBy.key,
					    sortedBy.dir,
					    state.rowsPerPage,
					    this.filterString,
					    this.options.statusFilterCheckbox.checked);
    YAHOO.util.History.navigate(this.historyID, newState);
  },
  
  handleSorting: function(oColumn) {
    Debug.println(this.historyID, ": handleSorting");
    var sDir = "asc";
    if (oColumn.key == this.dataWidgets.dataTable.get("sortedBy").key) {
      sDir = (this.dataWidgets.dataTable.get("sortedBy").dir == "asc") ? "desc" : "asc";
    }
    var newBookmark = this.generateStateString(0,
					       oColumn.key,
					       sDir,
					       this.dataWidgets.paginator.getRowsPerPage(),
					       this.filterString,
					       this.options.statusFilterCheckbox.checked);
    Debug.println(this.historyID, ": Sort Navigation ", newBookmark);
    YAHOO.util.History.navigate(this.historyID, newBookmark);
  },
  
  onFilterClear: function() {
    this.options.filterField.value = "";
    this.filterString = "";
    this.resetDisplay();
    this.options.filterField.focus();
  },
  onSearchClick: function() {
    this.filterString = this.options.filterField.value.trim();
    this.resetDisplay();
  },
  
  onToggleShowInactive: function() {
    this.resetDisplay();
  },
  
  onFilterEnter: function(event) {
    switch(keyCode2(event)) {
      case 13: // enter
      this.resetDisplay();
    }
  },
  
  filterChangeCount: 0,
  
  onFilterChange: function(event) {
    switch(keyCode2(event)) {
      case 13: // enter
      case 16: // shift
      case 17: // ctrl
      case 18: // alt
      case 37: // left
      case 38: // up
      case 39: // right
      case 40: // down
      return; // do nothing on these oddball key strokes
    }
    this.filterChangeCount ++;
    var myCount = this.filterChangeCount;
    setTimeout(function() {
		 this.onFilterChange_wakeup(myCount);
	       }, 250);
  },
  
  onFilterChange_wakeup: function(myCount) {
    if (myCount == this.filterChangeCount) {
    }
  }
};

Traction.TabularDataBrowser.__nextID = 0;
Traction.TabularDataBrowser.getNextID = function() {
  return Traction.TabularDataBrowser.__nextID ++;
};

Traction.TabularDataBrowser.__dataTableFixed = false;
Traction.TabularDataBrowser._fixDataTableDisplay = function() {
  if (Traction.TabularDataBrowser.__dataTableFixed) {
    return;
  }
  (function(){var B=YAHOO.widget.DataTable,A=YAHOO.util.Dom;B.prototype._setColumnWidth=function(I,D,J){I=this.getColumn(I);if(I){J=J||"hidden";if(!B._bStylesheetFallback){var N;if(!B._elStylesheet){N=document.createElement("style");N.type="text/css";B._elStylesheet=document.getElementsByTagName("head").item(0).appendChild(N)}if(B._elStylesheet){N=B._elStylesheet;var M=".yui-dt-col-"+I.getId();var K=B._oStylesheetRules[M];if(!K){if(N.styleSheet&&N.styleSheet.addRule){N.styleSheet.addRule(M,"overflow:"+J);N.styleSheet.addRule(M,"width:"+D);K=N.styleSheet.rules[N.styleSheet.rules.length-1]}else{if(N.sheet&&N.sheet.insertRule){N.sheet.insertRule(M+" {overflow:"+J+";width:"+D+";}",N.sheet.cssRules.length);K=N.sheet.cssRules[N.sheet.cssRules.length-1]}else{B._bStylesheetFallback=true}}B._oStylesheetRules[M]=K}else{K.style.overflow=J;K.style.width=D}return }B._bStylesheetFallback=true}if(B._bStylesheetFallback){if(D=="auto"){D=""}var C=this._elTbody?this._elTbody.rows.length:0;if(!this._aFallbackColResizer[C]){var H,G,F;var L=["var colIdx=oColumn.getKeyIndex();","oColumn.getThEl().firstChild.style.width="];for(H=C-1,G=2;H>=0;--H){L[G++]="this._elTbody.rows[";L[G++]=H;L[G++]="].cells[colIdx].firstChild.style.width=";L[G++]="this._elTbody.rows[";L[G++]=H;L[G++]="].cells[colIdx].style.width="}L[G]="sWidth;";L[G+1]="oColumn.getThEl().firstChild.style.overflow=";for(H=C-1,F=G+2;H>=0;--H){L[F++]="this._elTbody.rows[";L[F++]=H;L[F++]="].cells[colIdx].firstChild.style.overflow=";L[F++]="this._elTbody.rows[";L[F++]=H;L[F++]="].cells[colIdx].style.overflow="}L[F]="sOverflow;";this._aFallbackColResizer[C]=new Function("oColumn","sWidth","sOverflow",L.join(""))}var E=this._aFallbackColResizer[C];if(E){E.call(this,I,D,J);return }}}else{}};B.prototype._syncColWidths=function(){var J=this.get("scrollable");if(this._elTbody.rows.length>0){var M=this._oColumnSet.keys,C=this.getFirstTrEl();if(M&&C&&(C.cells.length===M.length)){var O=false;if(J&&(YAHOO.env.ua.gecko||YAHOO.env.ua.opera)){O=true;if(this.get("width")){this._elTheadContainer.style.width="";this._elTbodyContainer.style.width=""}else{this._elContainer.style.width=""}}var I,L,F=C.cells.length;for(I=0;I<F;I++){L=M[I];if(!L.width){this._setColumnWidth(L,"auto","visible")}}for(I=0;I<F;I++){L=M[I];var H=0;var E="hidden";if(!L.width){var G=L.getThEl();var K=C.cells[I];if(J){var N=(G.offsetWidth>K.offsetWidth)?G.firstChild:K.firstChild;if(G.offsetWidth!==K.offsetWidth||N.offsetWidth<L.minWidth){H=Math.max(0,L.minWidth,N.offsetWidth-(parseInt(A.getStyle(N,"paddingLeft"),10)|0)-(parseInt(A.getStyle(N,"paddingRight"),10)|0))}}else{if(K.offsetWidth<L.minWidth){E=K.offsetWidth?"visible":"hidden";H=Math.max(0,L.minWidth,K.offsetWidth-(parseInt(A.getStyle(K,"paddingLeft"),10)|0)-(parseInt(A.getStyle(K,"paddingRight"),10)|0))}}}else{H=L.width}if(L.hidden){L._nLastWidth=H;this._setColumnWidth(L,"1px","hidden")}else{if(H){this._setColumnWidth(L,H+"px",E)}}}if(O){var D=this.get("width");this._elTheadContainer.style.width=D;this._elTbodyContainer.style.width=D}}}this._syncScrollPadding()}})();
  (function(){var A=YAHOO.util,B=YAHOO.env.ua,E=A.Event,C=A.Dom,D=YAHOO.widget.DataTable;D.prototype._initTheadEls=function(){var X,V,T,Z,I,M;if(!this._elThead){Z=this._elThead=document.createElement("thead");I=this._elA11yThead=document.createElement("thead");M=[Z,I];E.addListener(Z,"focus",this._onTheadFocus,this);E.addListener(Z,"keydown",this._onTheadKeydown,this);E.addListener(Z,"mouseover",this._onTableMouseover,this);E.addListener(Z,"mouseout",this._onTableMouseout,this);E.addListener(Z,"mousedown",this._onTableMousedown,this);E.addListener(Z,"mouseup",this._onTableMouseup,this);E.addListener(Z,"click",this._onTheadClick,this);E.addListener(Z.parentNode,"dblclick",this._onTableDblclick,this);this._elTheadContainer.firstChild.appendChild(I);this._elTbodyContainer.firstChild.appendChild(Z)}else{Z=this._elThead;I=this._elA11yThead;M=[Z,I];for(X=0;X<M.length;X++){for(V=M[X].rows.length-1;V>-1;V--){E.purgeElement(M[X].rows[V],true);M[X].removeChild(M[X].rows[V])}}}var N,d=this._oColumnSet;var H=d.tree;var L,P;for(T=0;T<M.length;T++){for(X=0;X<H.length;X++){var U=M[T].appendChild(document.createElement("tr"));P=(T===1)?this._sId+"-hdrow"+X+"-a11y":this._sId+"-hdrow"+X;U.id=P;for(V=0;V<H[X].length;V++){N=H[X][V];L=U.appendChild(document.createElement("th"));if(T===0){N._elTh=L}P=(T===1)?this._sId+"-th"+N.getId()+"-a11y":this._sId+"-th"+N.getId();L.id=P;L.yuiCellIndex=V;this._initThEl(L,N,X,V,(T===1))}if(T===0){if(X===0){C.addClass(U,D.CLASS_FIRST)}if(X===(H.length-1)){C.addClass(U,D.CLASS_LAST)}}}if(T===0){var R=d.headers[0];var J=d.headers[d.headers.length-1];for(X=0;X<R.length;X++){C.addClass(C.get(this._sId+"-th"+R[X]),D.CLASS_FIRST)}for(X=0;X<J.length;X++){C.addClass(C.get(this._sId+"-th"+J[X]),D.CLASS_LAST)}var Q=(A.DD)?true:false;var c=false;if(this._oConfigs.draggableColumns){for(X=0;X<this._oColumnSet.tree[0].length;X++){N=this._oColumnSet.tree[0][X];if(Q){L=N.getThEl();C.addClass(L,D.CLASS_DRAGGABLE);var O=D._initColumnDragTargetEl();N._dd=new YAHOO.widget.ColumnDD(this,N,L,O)}else{c=true}}}for(X=0;X<this._oColumnSet.keys.length;X++){N=this._oColumnSet.keys[X];if(N.resizeable){if(Q){L=N.getThEl();C.addClass(L,D.CLASS_RESIZEABLE);var G=L.firstChild;var F=G.appendChild(document.createElement("div"));F.id=this._sId+"-colresizer"+N.getId();N._elResizer=F;C.addClass(F,D.CLASS_RESIZER);var e=D._initColumnResizerProxyEl();N._ddResizer=new YAHOO.util.ColumnResizer(this,N,L,F.id,e);var W=function(f){E.stopPropagation(f)};E.addListener(F,"click",W)}else{c=true}}}if(c){}}else{}}for(var a=0,Y=this._oColumnSet.keys.length;a<Y;a++){if(this._oColumnSet.keys[a].hidden){var b=this._oColumnSet.keys[a];var S=b.getThEl();b._nLastWidth=S.offsetWidth-(parseInt(C.getStyle(S,"paddingLeft"),10)|0)-(parseInt(C.getStyle(S,"paddingRight"),10)|0);this._setColumnWidth(b.getKeyIndex(),"1px")}}if(B.webkit&&B.webkit<420){var K=this;setTimeout(function(){K._elThead.style.display=""},0);this._elThead.style.display="none"}}})();
};

//------------------------------------------------------------------------
// yui-traction.TractionAutoComplete


YAHOO.namespace("traction");
YAHOO.traction.TractionAutoComplete = function(elInput, elContainer, oDataSource, oConfigs) {
  YAHOO.traction.TractionAutoComplete.superclass.constructor.call(this, elInput, elContainer, oDataSource, oConfigs);
};
YAHOO.extend(YAHOO.traction.TractionAutoComplete, YAHOO.widget.AutoComplete);

YAHOO.traction.TractionAutoComplete.prototype._onTextboxKeyDown = function(v,oSelf) {
    var nKeyCode = v.keyCode;
    switch (nKeyCode) {
    case 13: // enter
      if(oSelf._nKeyCode != nKeyCode) {
	if(oSelf._bContainerOpen) {
	  YAHOO.util.Event.stopEvent(v);
	}
      }
      if(oSelf._oCurItem) {
	oSelf._selectItem(oSelf._oCurItem);
      }
      else {
	oSelf.unmatchedItemSelectEvent.fire(oSelf, oSelf._sCurQuery);
      }
      break;
    case 191: // slash
    case 0: // colon
      if (oSelf.selectOn2ndColon) {
	var value = oSelf._elTextbox.value;
	if ((value.startsWith(":") && value.indexOf(":",1) == -1) ||
	    (value.startsWith("/") && value.indexOf("/",1) == -1)) {
	  if (oSelf._oCurItem) {
	    YAHOO.util.Event.stopEvent(v);
	    oSelf._selectItem(oSelf._oCurItem);
	    break;
	  }
	}
      }
    case 27: // esc
      if (nKeyCode == 27) {
	if (!oSelf.isContainerShowing()) {
	  if (oSelf.onEscWhenCollapsed != null) {
	    YAHOO.util.Event.stopEvent(v);
	    oSelf.onEscWhenCollapsed();
	    return;
	  }
	}
      }
    case 8: // backspace
    default:
      Debug.println("nKeyCode="+nKeyCode);
      YAHOO.traction.TractionAutoComplete.superclass._onTextboxKeyDown.call(this, v, oSelf);      
      break;
    } 
};
YAHOO.traction.TractionAutoComplete.prototype.onEscWhenCollapsed = null;

YAHOO.traction.TractionAutoComplete.prototype.isContainerShowing = function() {
  return this.isContainerOpen() || this._elContainer.style.display == "block";
};

YAHOO.traction.TractionAutoComplete.prototype._onTextboxBlur = function (v,oSelf) {
    if(!oSelf._bOverContainer || (oSelf._nKeyCode == 9)) {
        if(oSelf._bContainerOpen) {
            oSelf._toggleContainer(false);
        }
        oSelf._cancelIntervalDetection(oSelf);
        oSelf._bFocused = false;
        oSelf.textboxBlurEvent.fire(oSelf);
    }
};

//------------------------------------------------------------------------
// yui-traction.TractionPanel

YAHOO.namespace("traction");
YAHOO.traction.TractionPanel = function(el, userConfig) {
  if (arguments.length > 0) {
    YAHOO.traction.TractionPanel.superclass.constructor.call(this, el, userConfig);
  }
}
YAHOO.extend(YAHOO.traction.TractionPanel, YAHOO.widget.Panel);
YAHOO.traction.TractionPanel.prototype.initDefaultConfig = function() {
  YAHOO.traction.TractionPanel.superclass.initDefaultConfig.call(this); 
  this.cfg.addProperty("minheight", { value: 100 });
  this.cfg.addProperty("minwidth", { value: 100 });
}

YAHOO.traction.TractionPanel.prototype.configWidth = function(type, args, obj) {
  YAHOO.traction.TractionPanel.superclass.configWidth.call(this, type, args, obj); 
  this.body.firstChild.style.width = args[0];
};
YAHOO.traction.TractionPanel.prototype.configHeight = function(type, args, obj) {
  YAHOO.traction.TractionPanel.superclass.configHeight.call(this, type, args, obj); 
  var newHeight = Util.nopx(args[0]);
  var bodyHeight = (newHeight - this.footer.offsetHeight - this.header.offsetHeight); 
  if (bodyHeight < 0) { 
    bodyHeight = 0; 
  } 
  this.body.style.height = bodyHeight + "px";
  this.body.firstChild.style.height = bodyHeight + "px";
  this.body.firstChild.firstChild.style.height = bodyHeight + "px";
  this.body.firstChild.firstChild.firstChild.style.height = bodyHeight + "px";
};
YAHOO.traction.TractionPanel.prototype.fixTransparencyInIE = function() {
  var startWidth = this.innerElement.offsetWidth; 
  var startHeight = this.innerElement.offsetHeight; 
  this.cfg.setProperty("width", startWidth + "px"); 
  this.cfg.setProperty("height", startHeight + "px");   
};
YAHOO.traction.TractionPanel.prototype.init = function(el, userConfig) { 
  YAHOO.traction.TractionPanel.superclass.init.call(this, el); 
  this.beforeInitEvent.fire(YAHOO.traction.TractionPanel); 
  var brElements = YAHOO.util.Dom.getElementsByClassName("br", "div", this.footer);
  if (brElements.length == 0) return;
  this.resizeHandle = brElements[0];
  this.resizeHandle.id = this.id + "_r"; 
  this.renderEvent.subscribe(function() { 
			       var me = this; 
			       this.ddResize = new YAHOO.util.DragDrop(this.resizeHandle.id, this.id); 
			       this.ddResize.setHandleElId(this.resizeHandle.id); 
			       var headerHeight = me.header.offsetHeight; 
			       this.ddResize.onMouseDown = function(e) { 
				 this.startWidth = me.innerElement.offsetWidth; 
				 this.startHeight = me.innerElement.offsetHeight; 
				 me.cfg.setProperty("width", this.startWidth + "px"); 
				 me.cfg.setProperty("height", this.startHeight + "px"); 
				 this.startPos = [YAHOO.util.Event.getPageX(e), 
						  YAHOO.util.Event.getPageY(e)]; 
				 me.innerElement.style.overflow = "hidden"; 
				 me.body.style.overflow = "auto"; 
			       } 
			       this.ddResize.onDrag = function(e) { 
				 var newPos = [YAHOO.util.Event.getPageX(e), 
					       YAHOO.util.Event.getPageY(e)]; 
				 var offsetX = newPos[0] - this.startPos[0]; 
				 var offsetY = newPos[1] - this.startPos[1]; 
				 var newWidth = Math.max(this.startWidth + offsetX, 10); 
				 var newHeight = Math.max(this.startHeight + offsetY, 10); 
				 var minResizeHeight = me.cfg.getProperty("minheight");
				 var minResizeWidth = me.cfg.getProperty("minwidth");
				 if (newWidth < minResizeWidth) {
				   newWidth = minResizeWidth;
				 }
				 if (newHeight < minResizeHeight) {
				   newHeight = minResizeHeight;
				 }
				 me.cfg.setProperty("width", newWidth + "px"); 
				 me.cfg.setProperty("height", newHeight + "px"); 
			       } 
			     }, this, true); 
  if (userConfig) { 
    this.cfg.applyConfig(userConfig, true); 
  } 
  this.initEvent.fire(YAHOO.traction.TractionPanel); 
}; 

//------------------------------------------------------------------------
// yui-traction.ui.Highlighter


YAHOO.traction.Highlighter = function(el, options) {
  this.el = el;
  this.setOptions(options);
};
YAHOO.traction.Highlighter.prototype = {
  
  setOptions: function(options) {
    this.options = {
      highlightColor: "#ffc",
      targetColor: "#fff",
      fadeDuration: 2.5,
      fadeDelay: 2000,
      onFadeComplete: null
    }.extend(options || {});
  },
  glow: function(fade) {
    this.el.style.backgroundColor = this.options.highlightColor;
    if (fade) this.fade(this.options.fadeDelay);
  },
  fade: function(afterDelay) {
    var me = this;
    setTimeout(function() {
		 var fade = new YAHOO.util.ColorAnim(me.el, {backgroundColor: { to: me.options.targetColor } }, me.options.fadeDuration, YAHOO.util.Easing.easeIn); 
		 fade.onComplete.subscribe(me.fade_done, me, true);
		 fade.duration = me.options.fadeDuration;
		 fade.animate(); 
	       }, afterDelay || 1);
  },
  fade_done: function() {
    this.el.style.backgroundColor = "";
    if (this.options.onFadeComplete) {
      this.options.onFadeComplete();
    }
  },
  off: function() {
    this.el.style.backgroundColor = "";
  }
};

//------------------------------------------------------------------------
// yui-traction.UserCompleter

YAHOO.namespace("traction");
YAHOO.traction.UserCompleter = function(input, formName) {
  this.input = input;
  this.formName = formName;
  this.div = document.createElement("DIV");
  this.div.className = "completer-container";
  document.body.appendChild(this.div);
  this.dataSource = new YAHOO.traction.UserDataSource(this);
  this.autoComplete = new YAHOO.traction.TractionAutoComplete(input, this.div, this.dataSource);
  this.autoComplete.typeAhead = true;
  this.autoComplete.queryDelay = 0;
  this.autoComplete.delimChar = '';
  this.autoComplete.minQueryLength = 1;
  this.autoComplete.maxQueryResults = 0;
  this.autoComplete.animSpeed = 0.2;
  this.autoComplete.formatResult = this.formatResult;
  this.autoComplete.maxResultsDisplayed = 100;
  this.autoComplete.autoHighlight = true;
  this.autoComplete.allowBrowserAutocomplete = false;
  this.autoComplete.typeAhead = false;
  this.autoComplete.selectOn2ndColon = false;
  this.position();
  this.autoComplete.containerExpandEvent.subscribe(this.containerExpanded, this, true);
  this.autoComplete.itemSelectEvent.subscribe(this.itemSelected, this, true);
  this.autoComplete.unmatchedItemSelectEvent.subscribe(this.newItemSelected, this, true);
};
YAHOO.traction.UserCompleter.completersIntializedArray = null;
YAHOO.traction.UserCompleter.setup = function(input) {
  if (this.completersIntializedArray != null && this.completersIntializedArray[input]) return;
  if (this.completersIntializedArray == null) this.completersIntializedArray = new Array();
  this.completersIntializedArray[input] = new YAHOO.traction.UserCompleter(input, null);
};

YAHOO.traction.UserCompleter.prototype.itemSelected = function(type, args, obj) {
  var oData = args[2];
  var user = oData[1];
  var userid = user[3];
  var form = this.input.parentNode;
  form.submit();
};
YAHOO.traction.UserCompleter.prototype.newItemSelected = function(type, args, obj) {
  document.forms[this.formName].submit();  
};
YAHOO.traction.UserCompleter.prototype.formatResult = function(oResultItem, sQuery) {
  var value = oResultItem[0];
  var match = oResultItem[1][0];
  var displayText = oResultItem[1][2];
  var searchText = sQuery;
  var searchLen = sQuery.length;
  var finalDisplayText = "";
  var matchText = displayText.toLowerCase();
  var lastMatch = matchText.indexOf(searchText);
  while (lastMatch != -1) {
    finalDisplayText += displayText.substring(0, lastMatch) + "<b>" +
      displayText.substring(lastMatch, lastMatch + searchLen) + "</b>";
    displayText = displayText.substring(lastMatch + searchLen);
    matchText = displayText.toLowerCase();
    lastMatch = matchText.indexOf(searchText, lastMatch+1);
  }
  finalDisplayText += displayText;
  return finalDisplayText;
};
YAHOO.traction.UserCompleter.prototype.clear = function() {
  this.input.value = "";
};
YAHOO.traction.UserCompleter.prototype.position = function() {
  var region = YAHOO.util.Dom.getRegion(this.input);
  YAHOO.util.Dom.setXY(this.div, new YAHOO.util.Point(region.left, region.bottom) );
  var newWidth = region.right - region.left;
  if (newWidth < 300) newWidth = 300;
  this.div.style.width = px(newWidth);
};
YAHOO.traction.UserCompleter.prototype.containerExpanded = function(type, args, obj) {
  this.position();
};

//------------------------------------------------------------------------
// yui-traction.UserDataSource

YAHOO.traction.UserDataSource = function(completer) {
  this.completer = completer;
  this._init();
};
YAHOO.traction.UserDataSource.prototype = new YAHOO.widget.DataSource();

YAHOO.traction.UserDataSource.prototype.doQuery = function(oCallbackFn, sQuery, oParent) {
  var sOriginalQuery = sQuery;
  if (sQuery == null) sQuery = "";
  sQuery = decodeURIComponent(sQuery);
  sQuery = sQuery.toLowerCase();
  var state = { oCallbackFn: oCallbackFn, sOriginalQuery: sOriginalQuery, sQuery: sQuery, oParent: oParent };
  var poststring = "";
  poststring = fm_append(poststring, "type=usercompleter");
  poststring = fm_append(poststring, "q="+encode_url_parameter(sQuery));
  xmlpost_async(FORM_ACTION_READ_ONLY, poststring, null, false, this.doQuery_done.bind(this), state, -1);    
};
YAHOO.traction.UserDataSource.prototype.doQuery_done = function(responseText, state) {
  var responseArray = eval(responseText);
  var aResults = new Array();
  for (var i=0; i<responseArray.length; i++) {
    aResults[aResults.length] = [ responseArray[i][1], responseArray[i] ];
  }
  var oParent = state.oParent;
  var sQuery = state.sQuery;
  var sOriginalQuery = state.sOriginalQuery;
  this.getResultsEvent.fire(this, oParent, sOriginalQuery, aResults);
  state.oCallbackFn(sOriginalQuery, aResults, oParent);
};

