
/************** Implementacion del ListBox Virtual  *********************************/
 
var virtualLB_TopIndex = 0;        // indice del primer item visible
var virtualLB_SelectedIndex = -1;  // indice del item seleccionado
var bVirtualLB_Disabled = false;   // indica si el listbox esta desactivado
var virtualLB_SelectedWord = "";   // palabra seleccionada
var virtualLB_RealSelectedIndex = -1;  // indice del item selecionado real 
var bVirtualLB_ScrollDisabled = false;  // indica si el scroll esta desabilitado
var virtualLB_NumItems = 0;      // cantidad total de items en el listbox
var virtualLB_NumVisItems = 0;     // cantidad de items visibles
var virtualLB_nExtraCacheItems = 20;  // cantidad de items extra con los que se expande el rango
                                      // a pedir al servidor para hacer mas eficiente la cache

function VirtualLB_Initialize(count)
  {
  if (typeof(count) != "undefined")
    VirtualLB_SetNumItems(count);
    
  VirtualLB_ClearCache();
  }

// manejo de los resultados de los callbacks
// retorna true si manejo el resultado, false en caso contrario
function VirtualLB_OnCallBack(result, sContext)
  {
  if (result.error) // hubo un error
    {
    if (typeof(ShowError) == "undefined")
      alert(result.error);
    else
      ShowError(result.error);
      
    if (sContext == "LoadDict" || sContext == "LoadDictAndWord")
      { // hubo error al cargar un diccionario, limpiar el listbox
      VirtualLB_Clear();
      }
    }
  else if (result.session == "false") // se vencio la sesion
    { // se refresca la ventana para forzar el redireccionamiento
    window.location.reload(true);
    }
  else if (sContext == "GetWords" || sContext == "LoadDict" || sContext == "LoadDictAndWord"
    || sContext == "GetWordsFromWord" || sContext == "AddWord" || sContext == "DelWord")
    {
    if (cmmExists(result.nWordCount))
      VirtualLB_SetNumItems(parseInt(result.nWordCount));
      
    if (sContext == "LoadDict" || sContext == "LoadDictAndWord")
      VirtualLB_ClearCache();
      
    var bUpdateTxtFind = (sContext != "GetWordsFromWord" && sContext != "LoadDictAndWord");
    
    if (sContext == "AddWord" && cmmExists(result.bWordExists))
      if (result.bWordExists == "True")
        alert(S_WordExists);
      
    var idxShowStart = parseInt(result.idxStart);
    var idxShowEnd = parseInt(result.idxEnd);
    if (sContext == "GetWords" || sContext == "LoadDict")
      {
      idxShowStart = parseInt(result.idxShowStart);
      idxShowEnd = parseInt(result.idxShowEnd);
      }

    VirtualLB_OnReceiveWords(parseInt(result.idxStart), 
      parseInt(result.idxEnd), 
      idxShowStart, 
      idxShowEnd, 
      parseInt(result.idxSel), 
      result.words, sContext != "GetWords", bUpdateTxtFind);
    }
  else 
    return false;
  
  return true;
  }

// Ajusta la posicion vertical del thumb segun virtualLB_TopIndex
function VirtualLB_AdjustThumbPos()
  {
  var divThumb = getElem("divThumb");
  var cell = divThumb.parentNode;
  var thumdTop;
  var den = virtualLB_NumItems - virtualLB_NumVisItems;
  if (den <= 0) // ponerlo en el medio
    thumdTop = (cell.offsetHeight - divThumb.offsetHeight) / 2;
  else
    thumdTop = virtualLB_TopIndex * (cell.offsetHeight - divThumb.offsetHeight) / den;
  divThumb.style.top = Math.floor(thumdTop) + "px";
  }

function VirtualLB_DisableScroll(bDisable)
  {
  bVirtualLB_ScrollDisabled = bDisable;
  var imgUp = getElem("imgArrowUp");
  var imgDown = getElem("imgArrowDown");
  var tdThumb = getElem("tdThumb");
  
  var sDis = "";
  if (bVirtualLB_ScrollDisabled) sDis = "_dis";
  
  imgUp.src = "imgs/scroll_up" + sDis + ".png";
  imgDown.src = "imgs/scroll_down" + sDis + ".png";
  tdThumb.style.backgroundImage = "url(imgs/scroll_back" + sDis + ".png)";
  
  var divThumb = getElem("divThumb");
  if (bVirtualLB_ScrollDisabled)
    divThumb.style.display = "none";
  else
    divThumb.style.display = "block";
  }

function VirtualLB_SetNumItems(count)
  {
  if (count <= virtualLB_NumVisItems && !bVirtualLB_ScrollDisabled)
    // La cantidad de items se hizo menor o igual que la cantidad visible
    VirtualLB_DisableScroll(true);
    
  if (count > virtualLB_NumVisItems && bVirtualLB_ScrollDisabled)
    // La cantidad de items se hizo mayor que la cantidad visible
    VirtualLB_DisableScroll(false);
    
  if ((typeof(VirtualLB_OnNumItemsChange) != "undefined"))
    VirtualLB_OnNumItemsChange(count);
    
  virtualLB_NumItems = count;
  }
  
function VirtualLB_Clear()
  {
  VirtualLB_SetNumItems(0);
  VirtualLB_ClearItems();
  }

function VirtualLB_ClearItems()
  {
  for(var i=0; i<virtualLB_NumVisItems; i++)
    {
    var oDiv = getElem("divItem" + i);
    if (!oDiv) continue;
    oDiv.className = "";
    cmmSetText(oDiv, "");
    }
  }
  
function VirtualLB_SetDisabled(bDisable)
  {
  bVirtualLB_Disabled = bDisable;
  
  for(var i=0; i<virtualLB_NumVisItems; i++)
    {
    var oDiv = getElem("divItem" + i);
    if (!oDiv) continue;
    if (bVirtualLB_Disabled)
      oDiv.className = "ItemDisabled";
    else if (virtualLB_TopIndex + i == virtualLB_SelectedIndex)
      oDiv.className = "ItemSelected";
    else
      oDiv.className = "ItemNormal";
    }
  }
  
function virtualLB_SetTopIndex(topIndex)
  {
  virtualLB_TopIndex = topIndex;
  if (virtualLB_TopIndex > virtualLB_NumItems - virtualLB_NumVisItems)
    virtualLB_TopIndex = virtualLB_NumItems - virtualLB_NumVisItems;
  if (virtualLB_TopIndex < 0) 
    virtualLB_TopIndex = 0;
    
  return virtualLB_TopIndex;
  }
  
function VirtualLB_Fill()
  {
  // Para asegurarse que virtualLB_TopIndex tiene un valor correcto
  virtualLB_SetTopIndex(virtualLB_TopIndex);
  
  VirtualLB_AdjustThumbPos();
  
  VirtualLB_GetItems(virtualLB_TopIndex, virtualLB_TopIndex+virtualLB_NumVisItems-1);
  }

var sVirtualLB_PendingOnChangeEvent = "";
var bVirtualLB_InGetWordsCallBack = false;
var sVirtualLB_PendingGetWordsCallBack = "";
var iDebugCounter = 0;
// Busca en el servidor un rango de items, idxSel contiene el item
// seleccionado actualmente, se usa para saber, al retornar del callback
// cual era el item seleccionado en ese instante 
// bForce indica si hace el llamado aunque halla un callback pendiente
function VirtualLB_GetItems(idxStart, idxEnd, idxSel, bForce)
  {
  if (typeof(idxSel) == "undefined")
    idxSel = virtualLB_SelectedIndex;
  if (bForce != true && bVirtualLB_InGetWordsCallBack)
    {
    sVirtualLB_PendingGetWordsCallBack = "VirtualLB_GetItems(" + idxStart + "," + 
      idxEnd + "," + idxSel + ", true);";
    return;
    }

  var oNoCachedRange = VirtualLB_GetNoCachedRange(idxStart, idxEnd);
  if (oNoCachedRange == null)
    { // el rango a pedir esta en la cache
    //getElem("divDebug").innerHTML = iDebugCounter++ + " : (" + idxStart + "," + idxEnd + ") Loading from cache.";
    VirtualLB_OnReceiveWords(idxStart, idxEnd, idxStart, idxEnd, idxSel, null, false, true);
    }
  else
    { // pedir el rango al servidor
    // guardar el rango original pues este sera el que se mostrara
    var idxShowStart = idxStart;
    var idxShowEnd = idxEnd;
    
    // aumentar el rango a pedir para cachear items
    idxStart = idxStart - virtualLB_nExtraCacheItems;
    if (idxStart < 0) idxStart = 0;
    idxEnd = idxEnd + virtualLB_nExtraCacheItems;
    if (idxEnd >= virtualLB_NumItems) idxEnd = virtualLB_NumItems - 1;
    
    //getElem("divDebug").innerHTML = "<B>" + iDebugCounter++ + " : (" + idxStart + "," + idxEnd + ") Calling server.</B>";
    bVirtualLB_InGetWordsCallBack = true;
    var sParam = cmmJoin(idxStart, idxEnd, idxShowStart, idxShowEnd, idxSel);
    
    CallBack("GetWords", sParam);
    }
  }

//var virtualLB_idxCacheStart = -1;
//var virtualLB_idxCacheEnd = -1;
var virtualLB_arrCache = null;

function VirtualLB_ClearCache()
  {
  //virtualLB_idxCacheStart = -1;
  //virtualLB_idxCacheEnd = -1;
  //virtualLB_arrCache = new Array();// null;
  virtualLB_arrCache = null;
  }

function VirtualLB_NewRange(idxStart, idxEnd)
  {
  this.idxStart = idxStart;
  this.idxEnd = idxEnd;
  }
  
function VirtualLB_GetNoCachedRange(idxStart, idxEnd)
  {
  if (virtualLB_arrCache == null)
    return new VirtualLB_NewRange(idxStart, idxEnd);
    
  var idxEmptyStart = -1;
  var idxEmptyEnd = -1;
  for(var i=idxStart; i<=idxEnd; i++)
    {
    if (virtualLB_arrCache[i] == null)
      {
      idxEmptyStart = i;
      break;
      }
    }

  if (idxEmptyStart == -1)
    return null;
    
  for(var i=idxEnd; i>=idxStart; i--)
    {
    if (virtualLB_arrCache[i] == null)
      {
      idxEmptyEnd = i;
      break;
      }
    }
    
  return new VirtualLB_NewRange(idxEmptyStart, idxEmptyEnd);
  }
  
// Callback que se llama con las palabras que hay que poner en el listbox
// idxStart, idxEnd es el rango de palabras que contiene arrWords
// idxShowStart, idxShowEnd es el rango de palabras que hay que mostrar
// arrWords es el array de palabras del rango idxStart, idxEnd, si es null se toma el array de la cache
// si bForceSel == true, se busca en el servidor los datos de la palabra seleccionada
// si bUpdateTxtFind == true, se actualiza el textbox de la palabra actual
function VirtualLB_OnReceiveWords(idxStart, idxEnd, idxShowStart, idxShowEnd, idxSel, arrWords, bForceSel, bUpdateTxtFind)
  {
  var bWordChanged = false;
  
  // actualizar la cache con el nuevo rango
  if (arrWords)
    {
    if (virtualLB_arrCache == null)
      virtualLB_arrCache = new Array(virtualLB_NumItems);
      
    for(var i=idxStart; i<=idxEnd; i++)
      virtualLB_arrCache[i] = arrWords[i - idxStart];
    }

  for(var i=0; i<virtualLB_NumVisItems; i++)
    {
    var sWord = "";
    var index = idxShowStart + i;
    if (index >= 0 && index < virtualLB_arrCache.length)
      sWord = virtualLB_arrCache[index];
    
    if (index == idxSel)
      { // este es el item seleccionado
      if (virtualLB_SelectedWord != sWord)
        bWordChanged = true;
      virtualLB_SelectedWord = sWord;
      virtualLB_RealSelectedIndex = idxSel;
      
      if (typeof(bUpdateTxtFind) != "undefined" && bUpdateTxtFind == true)
        {
        if (typeof(VirtualLB_OnWordSelected) != "undefined")
          VirtualLB_OnWordSelected(virtualLB_SelectedWord);
        }
      }
    
    var oDiv = getElem("divItem" + i);
    if (!oDiv) continue;
    cmmSetText(oDiv, sWord);
    oDiv.setAttribute("Xword", sWord);
    
    if (idxShowStart + i == idxSel)
      oDiv.className = "ItemSelected";
    else
      oDiv.className = "ItemNormal";
    }
  
  if (bForceSel)
    {
    virtualLB_TopIndex = idxStart;
    VirtualLB_AdjustThumbPos();
    sVirtualLB_PendingGetWordsCallBack = "VirtualLB_SelectIndex(" + idxSel + ", false, " + bWordChanged + ")";
    }
  
  var temp = sVirtualLB_PendingGetWordsCallBack;
  // si hay un callback pendiente, ejecutarlo
  if (temp != "")
    {
    sVirtualLB_PendingGetWordsCallBack = "";
    window.setTimeout(temp, 0); // un eval da error del .NET
    return;
    }
  else if (sVirtualLB_PendingOnChangeEvent != "")
    {
    window.setTimeout(sVirtualLB_PendingOnChangeEvent, 50);
    sVirtualLB_PendingOnChangeEvent = "";
    }
    
  bVirtualLB_InGetWordsCallBack = false;
  }

function VirtualLB_GetItemFromIndex(idxItem)
  {
  var index = idxItem - virtualLB_TopIndex;
  var divElem = getElem("divItem" + index);
  return divElem;
  }
  
// selecciona un nuevo indice dado su elemento div (debe estar visible)
function VirtualLB_SelectItem(divItem, bDontAskForChange, bTakeFocus, bForceSel)
  {
  if (bVirtualLB_Disabled) return;
  
  // verifica si se puede cambiar la seleccion
  if (bDontAskForChange != true && typeof(VirtualLB_AllowSelectionChange) != "undefined")
    if (!VirtualLB_AllowSelectionChange())
      return;
      
  // darle el foco a un input para que se generen los eventos de teclado
  if (bTakeFocus)
    {
    var txtFocus = getElem("txtVirtualListFocus");
    if (txtFocus.focus)
      {
      txtFocus.focus();
      }
    }
  
  var idxNewItem = virtualLB_TopIndex + parseInt(divItem.id.substr("divItem".length));
  if (idxNewItem >= virtualLB_NumItems) return;
  if (bForceSel != true && virtualLB_SelectedIndex == idxNewItem)
    { // llamar al evento de indice cambiado
    VirtualLB_CallOnChange(false);
    return;
    }

  if (virtualLB_SelectedIndex != idxNewItem)
    {
    divItem.className = "ItemSelected";
    if (virtualLB_SelectedIndex >= 0)
      { // desselecionar la seleccion anterior
      var divOldItem = VirtualLB_GetItemFromIndex(virtualLB_SelectedIndex)
      if (divOldItem)
        divOldItem.className = "ItemNormal";
      }
    }
    
  virtualLB_SelectedIndex = idxNewItem;
  virtualLB_SelectedWord = divItem.getAttribute("Xword");
  virtualLB_RealSelectedIndex = virtualLB_SelectedIndex;
  
  if (bTakeFocus)
    {
    // actualizar el textbox de buscar palabra
    if (typeof(VirtualLB_OnWordSelected) != "undefined")
      VirtualLB_OnWordSelected(virtualLB_SelectedWord);
    }
  
  // Llamar al evento de indice cambiado
  VirtualLB_CallOnChange(true);
  }

// llamar al evento de indice cambiado
function VirtualLB_CallOnChange(bIndexChanged)
  {
  if (typeof(VirtualLB_OnChange) != "undefined")
    VirtualLB_OnChange(virtualLB_RealSelectedIndex, virtualLB_SelectedWord, bIndexChanged);
  }

// selecciona un nuevo indice
function VirtualLB_SelectIndex(newIndex, bTakeFocus, bForceSel)
  {
  if (bVirtualLB_Disabled) return;
  if (typeof(bTakeFocus) == "undefined")
    bTakeFocus = true;
  if (typeof(bForceSel) == "undefined")
    bForceSel = false;
  
  if (newIndex < 0)
    newIndex = 0;
  else if (newIndex >= virtualLB_NumItems)
    newIndex = virtualLB_NumItems - 1;
  // el indice no cambio  
  if (bForceSel == false && newIndex == virtualLB_SelectedIndex)
    { // llamar al evento de indice cambiado
    VirtualLB_CallOnChange(false);
    return;
    }

  // verifica si se puede cambiar la seleccion
  if (bForceSel == false && typeof(VirtualLB_AllowSelectionChange) != "undefined")
    if (!VirtualLB_AllowSelectionChange())
      return;

  var relIndex = newIndex - virtualLB_TopIndex;
  var oDiv = getElem("divItem" + relIndex);
  if (oDiv)
    { // el nuevo indice es visible, no hay que hacer scroll
    VirtualLB_SelectItem(oDiv, true, bTakeFocus, bForceSel);
    return;
    }

  var oldIndex = virtualLB_SelectedIndex;
  virtualLB_SelectedIndex = newIndex;
  
  // Llamar al evento de indice cambiado despues que se haga el scroll
  sVirtualLB_PendingOnChangeEvent = "VirtualLB_CallOnChange(true)";
  
  // para ver el nuevo item hay que hacer scroll
  if (newIndex > oldIndex)
    { // el nuevo item queda en el borde inferior
    VirtualLB_ScrollTo(newIndex - virtualLB_NumVisItems + 1);
    }
  else
    { // el nuevo item queda en el borde superior
    VirtualLB_ScrollTo(virtualLB_SelectedIndex);
    }
  }

function VirtualLB_ScrollDelta(delta)
  {
  var newIndex = virtualLB_TopIndex + delta;
  if (newIndex < 0 && virtualLB_TopIndex == 0)
    return; // no hacer nada
    
  VirtualLB_ScrollTo(newIndex);
  }

function VirtualLB_ScrollTo(idxTopItem)
  {
  if (bVirtualLB_Disabled || bVirtualLB_ScrollDisabled) return;
  
  virtualLB_TopIndex = idxTopItem;
  VirtualLB_Fill();
  }

function VirtualLB_OnKeyEvent(event)
  {
  if (bVirtualLB_Disabled) return;
  
  //window.status = event.keyCode + " | " + counter();
  if (event.keyCode == 38)
    VirtualLB_SelectIndex(virtualLB_SelectedIndex - 1);
  else if (event.keyCode == 40)
    VirtualLB_SelectIndex(virtualLB_SelectedIndex + 1);
  else if (event.keyCode == 33)
    VirtualLB_SelectIndex(virtualLB_SelectedIndex - (virtualLB_NumVisItems - 1));
  else if (event.keyCode == 34)
    VirtualLB_SelectIndex(virtualLB_SelectedIndex + (virtualLB_NumVisItems - 1));
  else if (event.keyCode == 36)
    VirtualLB_SelectIndex(0);
  else if (event.keyCode == 35)
    VirtualLB_SelectIndex(virtualLB_NumItems - 1);
  }
  
function VirtualLB_OnMouseWheel(event)
  {
  if (bVirtualLB_Disabled || bVirtualLB_ScrollDisabled) return;
  
  VirtualLB_ScrollDelta(-event.wheelDelta/120);
  }
  
var idTimeoutScroll = -1;  
var idIntervalScroll = -1;  

function VirtualLB_ClearScrollTimers()
  {
  if (idIntervalScroll >= 0)
    window.clearInterval(idIntervalScroll);
  if (idTimeoutScroll >= 0)
    window.clearTimeout(idTimeoutScroll);
  idIntervalScroll = -1;
  idTimeoutScroll = -1;
  }

function VirtualLB_HandleContinuosEvent(sCallFunction, phase)
  {
  var res = eval(sCallFunction);
  if (res == false)
    {
    VirtualLB_ClearScrollTimers();
    return;
    }
    
  if (typeof(phase) == "undefined" || phase == 0)
    {
    VirtualLB_ClearScrollTimers();
    idTimeoutScroll = window.setTimeout("VirtualLB_HandleContinuosEvent('" + sCallFunction + "',1)", 500);
    }
   else if (phase == 1)
    {
    VirtualLB_ClearScrollTimers();
    idIntervalScroll = window.setInterval("VirtualLB_HandleContinuosEvent('" + sCallFunction + "',2)", 100);
    }
  }

function VirtualLB_PressArrow(elem, bPress)
  {
  if (!elem.getAttribute("srcpress")) return;
  if (bPress)
    {
    if (elem.src == elem.getAttribute("srcpress")) return;
    var srcorg = elem.getAttribute("srcorg");
    if (!srcorg)
      {
      elem.setAttribute("srcorg", elem.src);
      }
    elem.src = elem.getAttribute("srcpress");
    }
  else
    {
    var srcorg = elem.getAttribute("srcorg");
    if (srcorg && srcorg != elem.src)
      elem.src = srcorg;
    }
  }
  
function VirtualLB_ArrowOnMouseDown(elem, delta)
  {
  if (bVirtualLB_Disabled || bVirtualLB_ScrollDisabled) return;
  
  VirtualLB_PressArrow(elem, true);
  VirtualLB_HandleContinuosEvent("VirtualLB_ScrollDelta(" + delta + ")");
  }

function VirtualLB_ArrowOnMouseUp(elem)
  {
  if (bVirtualLB_Disabled || bVirtualLB_ScrollDisabled) return;

  VirtualLB_PressArrow(elem, false);
  VirtualLB_ClearScrollTimers();
  }
  
function VirtualLB_ArrowOnDblClick(elem, delta)
  {
  if (bVirtualLB_Disabled || bVirtualLB_ScrollDisabled) return;
  
  // en el FireFox se ignora el dblclick pues antes genera dos 
  // onmousedown
  if (cmmbIsFireFox) return;
  VirtualLB_PressArrow(elem, true);
  
  VirtualLB_ScrollDelta(delta);
  
  setTimeout("VirtualLB_PressArrow(getElem(\"" + elem.id + "\"), false)", 100);
  }
  
var virtualLB_LastMouseX, virtualLB_LastMouseY;

function VirtualLB_PageUp()
  {
  if (virtualLB_LastMouseX && document.elementFromPoint)
    {
    var elem = document.elementFromPoint(virtualLB_LastMouseX, virtualLB_LastMouseY);
    if (elem.id == "divThumb")
      return false;
    }
  VirtualLB_ScrollDelta(-(virtualLB_NumVisItems-1));
  }
  
function VirtualLB_PageDown()
  {
  if (virtualLB_LastMouseX && document.elementFromPoint)
    {
    var elem = document.elementFromPoint(virtualLB_LastMouseX, virtualLB_LastMouseY);
    if (elem.id == "divThumb")
      return false;
    }
  VirtualLB_ScrollDelta(virtualLB_NumVisItems-1);
  }
  
function VirtualLB_ThumbCellOnMouseDown(event)
  {
  if (bVirtualLB_Disabled || bVirtualLB_ScrollDisabled) return;
  
  var divThumb = getElem("divThumb");
  var rect = cmmGetElementPosition(divThumb);

  var mouseY = document.documentElement.scrollTop + event.clientY;
  if (mouseY < rect.top + rect.height/2)
    if (event.type == "dblclick")
      {
      if (cmmbIsFireFox) return;
      VirtualLB_PageUp();
      }
    else
      VirtualLB_HandleContinuosEvent("VirtualLB_PageUp()");
  else
    if (event.type == "dblclick")
      {
      if (cmmbIsFireFox) return;
      VirtualLB_PageDown();
      }
    else
      VirtualLB_HandleContinuosEvent("VirtualLB_PageDown()");
  }

function VirtualLB_ThumbCellOnMouseMove(event)
  {
  if (bVirtualLB_Disabled || bVirtualLB_ScrollDisabled) return;
  
  if (cmmbIsFireFox) return;
  // Para el FireFox no hace falta, los demas no generan el 
  // onmouseout cuando el mouse no se mueve
  virtualLB_LastMouseX = event.clientX;
  virtualLB_LastMouseY = event.clientY;
  }

function VirtualLB_ThumbDivOnClick()
  {
  if (event.stopPropagation)
    event.stopPropagation();
  else
    event.cancelBubble = true;
  }

var bVirtualLB_Dragging = false;
var bVirtualLB_AllowCapture = false;
var virtualLB_DeltaY = 0;
function VirtualLB_ThumbDivOnMouseDown(event)
  {
  cmmCancelBubble(event);
    
  if (bVirtualLB_Disabled || bVirtualLB_ScrollDisabled) return;
  
  bVirtualLB_AllowCapture = false;

  var divThumb = getElem("divThumb");
  if (divThumb.setCapture)
    {
    divThumb.setCapture();
    bVirtualLB_AllowCapture = true;
    }
    
  if (bVirtualLB_AllowCapture == false && !window.onmousemove)
    { // si no se puede capturar el mouse entonces se interceptan
    // los eventos del window
    window.onmousemove = VirtualLB_ThumbDivOnMouseMove;
    window.onmouseup = VirtualLB_ThumbDivOnMouseUp;
    }
    
  virtualLB_DeltaY = event.clientY - cmmGetElementPosition(divThumb).top;
  bVirtualLB_Dragging = true;
  }
  
function VirtualLB_ThumbDivOnMouseMove(event)
  {
  if (bVirtualLB_Disabled || bVirtualLB_ScrollDisabled) return;
  
  var divThumb = getElem("divThumb");
    
  if (bVirtualLB_Dragging)
    {
    var oCell = divThumb.parentNode;

    var newIndex;
    var maxIndexItem = virtualLB_NumItems - virtualLB_NumVisItems;
    
    newIndex = (event.clientY - virtualLB_DeltaY - cmmGetElementPosition(oCell).top) * maxIndexItem / (oCell.offsetHeight - divThumb.offsetHeight);
    newIndex = Math.floor(newIndex);
    
    var oldTopIndex = virtualLB_TopIndex;
    if (oldTopIndex != virtualLB_SetTopIndex(newIndex))
      { // solo cuando cambia el top indice
      VirtualLB_Fill();
      }
    }
  }

function VirtualLB_ThumbDivOnMouseUp()
  {
  if (bVirtualLB_Disabled || bVirtualLB_ScrollDisabled) return;
  
  var divThumb = getElem("divThumb");
  if (divThumb.releaseCapture)
    divThumb.releaseCapture();
  bVirtualLB_Dragging = false;
  }

function VirtualLB_ItemDivOnMouseDown(event, divElem)
  {
  if (bVirtualLB_Disabled) return;
  
  VirtualLB_SelectItem(divElem, false, true);
  }
