/* $Id: module-eadeac-basket.js 12373 2008-10-15 14:41:34Z jcwiklinski $ */
/**
Copyright (C) 2003-2008 AJLSM, Anaphore
Voir le fichier LICENCE
**/
/* Ce fichier de configuration fait partie de la distribution standard
de Pleade. Vous pouvez le modifier à votre guise. */
var tbls = new Array();// Les YUI DataTable
/**
 * Fonction gerant l'ajout de documents dans le porte-documents
 *
 * @param params {String} Les parametres qui seront passes avec l'URL.
 * @param target {String} L'objet HTML/DOM sur lequel on agira pour suivre le
 *                        processus.
 * @param base {String} L'identifiant de la base de documents. (optionel).
 */
function addToBasket( params, target, base, disables ) {
  if ( !params || !target ) return false;
  Element.extend( target );
  if (disables==null){
    disables = new Array();
    disables[0] = target;
  }
  var oInnerHTML = target.innerHTML;
  var url = 'functions/' + ((!base)?"ead/":base+"/") + 'addToBasket.json?';
  var ajax = new Ajax.Request( url, {
                               parameters: params,
                               onCreate: function(){
                                 target.innerHTML = "Ajout en cours..."; // TODO (MP) : i18n
                                 target.addClassName('pl-bskt-bttn-loading');
                               },
                               onFailure: function(){
                                 target.innerHTML = "Echec..."; // TODO (MP) : i18n
                                 target.removeClassName('pl-bskt-bttn-loading');
                               },
                               onSuccess: function(xhr){
                                 target.innerHTML = oInnerHTML;
                                 target.removeClassName('pl-bskt-bttn-loading');
                                 var success=false;
                                 var msgCode = "";
                                 if(xhr.responseText){
                                   var oJson = xhr.responseText.evalJSON();
                                   success = oJson.success;
                                   if(oJson.msgCode){
                                     msgCode = oJson.msgCode;
                                   }
                                 }
                                 if(success){
                                   if(disables){
                                     disables.each(function(o){
                                       if(o){
                                         o.disabled = true;
                                         o.addClassName("disabled");
                                         // o.style.visibility="hidden";
                                       }
                                     });
                                   }
                                 }
                                 else{
                                   if(!msgCode) msgCode = "basket_msg_addToBasket_ko";
                                 }

                                 var msg = eval( "_usersMessagesBasket."+msgCode );
                                 if(msg) {
                                  alert(msg);
                                 }
                                 else if(msg){
                                   alert(msg);
                                 }

                               }
                            });
}
/**
 * Fonction gerant l'ajout d'une page complete de documents dans le porte-
 * documents.
 *
 * @param params {String} Les parametres qui seront passes avec l'URL.
 * @param target {String} L'objet HTML/DOM sur lequel on agira pour suivre le
 *                        processus.
 * @param base {String} L'identifiant de la base de documents. (optionel).
 */
function addPageToBasket(params, target, base){
  return addToBasket(params, target, base);
  // TODO (MP) : Trouver moyen de desactiver les boutons d'une page de resultat.
}
/**
 * Fonction gerant l'ajout d'un resultat de recherche dans le porte-
 * documents.
 *
 * @param params {String} Les parametres qui seront passes avec l'URL.
 * @param target {String} L'objet HTML/DOM sur lequel on agira pour suivre le
 *                        processus.
 * @param base {String} L'identifiant de la base de documents. (optionel).
 */
function addResultsToBasket(params, target, base){
  return addToBasket(params, target, base/* , $$('button.pl-bskt-bttn') */);
  // TODO (MP) : Trouver moyen de desactiver les boutons d'un resultat.
}
/**
 * Fonction gerant l'ajout d'un document dans le porte-documents.
 *
 * @param params {String} Les parametres qui seront passes avec l'URL.
 * @param target {String} L'objet HTML/DOM sur lequel on agira pour suivre le
 *                        processus.
 * @param base {String} L'identifiant de la base de documents. (optionel).
 */
function addDocToBasket(params, target, base){
  return addToBasket(params, target, base);
}

/**
 * Fonction pour retirer des documents du panier
 *
 * @param params {String} Parametres d'URL a passer.
 * @param target {Node} L'objet XHTML/DOM a mettre a jour pour suivre
 *                      l'evolution du processus.
 * @param base {String} L'identifiant de la base de document (optionel)
 * @param fct {function()} La fonction utilisee en fin de processus. Si null, on
 *                         recharge la page.
 */
function deleteFromBasket( params, target, base, fct ) {
  if ( !params || !target ) return false;
  Element.extend( target );
  var oInnerHTML = target.innerHTML;
  var url = 'functions/' + ((!base)?"ead/":base+"/") + 'deleteFromBasket.json?';
  var ajax = new Ajax.Request( url, {
                               parameters: params,
                               onCreate: function(){
                                 target.innerHTML = "Traitement en cours...";
                               },
                               onFailure: function(){
                                 target.innerHTML = "Echec...";
                               },
                               onSuccess: function(xhr){
                                 target.innerHTML = oInnerHTML;
                                 var success=false;
                                 var msg = "Echec...";
                                 if(xhr.responseText){
                                   var oJson = xhr.responseText.evalJSON();
                                   success = oJson.success;
                                   msg = oJson.description;
                                 }
                                 if(success){
                                   if(msg) alert(msg);
                                 }
                                 else if(msg) alert(msg);
                                 if(fct) fct();
                                 else window.location.reload();
                               }
                            });
}

/**
 * Fonction de vidange complete du panier
 * @param target {Node} L'objet XHTML/DOM a mettre a jour pour suivre
 *                      l'evolution du processus.
 * @param base {String} L'identifiant de la base de document (optionel)
 */
function flushBasket(target, base){
  try{
    refreshDataTB = function(){
      try{
        var url = ((!base)?"ead/":base+"/") + 'basket.ajax?';
        var refresh = new Ajax.Updater($$('.rslts-cnt')[0],url);
      } catch(e){
        window.location.reload();
      }
    };
    deleteFromBasket('id=all', target, base, refreshDataTB);
  } catch(e){}
}

/**
 * Fonction pour retirer des documents du panier
 *
 * @param ids {String[]} Liste des identifiants des documents a retirer
 * @param target {Node} L'objet XHTML/DOM a mettre a jour pour suivre
 *                      l'evolution du processus.
 * @param base {String} L'identifiant de la base de document (optionel)
 */
function deleteSelectedFromBasket(ids, target, base){
  if(!ids || !target) return false;
  var slcts = $A(ids);
  var params = "";
  slcts.each(function(o){
    if(o && !o.blank())
    params += "&id=" + o;
  });
  refreshDataTB = function(){
    if(tbls!=null){
      try{
        if(base && !base.blank() && tbls[base]){
          // on connait precisemment la dataTable que l'on veut rafraichir
          refreshDataTable(tlbs["pl-bskt-cnt-"+base]);
        }
        else if(selectedBases!=null && selectedBases.length>0){
          // on connait precisemment la/les dataTable(s) que l'on veut rafraichir
          var dt=null;
          $A(selectedBases).each(function(o,i){
            dt = tbls["pl-bskt-cnt-"+o];
            if(dt!=null && dt.Sortable!=null){
              refreshDataTable(dt);
            }
          });
        }
        else if(tbls!=null){
          /* On ne connait pas precisemment la/les dataTable(s) que l'on veut
           * rafraichir. On les rafraichit toutes.*/
           var dt=null;
           $A(tbls).each(function(o,i){
             dt = o;
             if(o!=null && o.Sortable!=null){
              refreshDataTable(o);
             }
          });
        }
      } catch(e){
        window.location.reload();
      }
    }
    else
        window.location.reload();
  };
  try{
    deleteFromBasket(params, target, base, refreshDataTB/*null*/);
  } catch(e){}
}

/**
 * Fonction de rafraichissement d'une DataTable YUI
 *
 * @param dt {YAHOO.widget.DataTable} La DataTable YUI a rafraichir.
 */
function refreshDataTable(dt){
  if (dt!=null){
    var dtb = dt.getDataTable();
    var dsr = dt.getDataSource();
    dsr.sendRequest("page=1", dtb.onDataReturnInitializeTable, dtb);
  }
}
/**
 * Fonction d'initialisation de la TabView YUI
 * @param tabSelector {String} La classe CSS utilisee pour selectionner les onglets
 * @param tabsSelector {String} L'identifiant ou l'objet HTML contenant la TabView
 */
function initBasketTabs(tabSelector, tabsSelector){
  if(tabSelector==null || tabSelector.blank()){
    tabSelector = "div.tab";
  }
  if(tabsSelector==null || tabsSelector.blank()){
    tabsSelector = "pl-pg-tabs";
  }
  $$(tabSelector).each( function(el, i) {
    el.style.display="block";
  });
  var mTabs = new YAHOO.widget.TabView(tabsSelector);
  initBasketTab();
  mTabs.on('activeTabChange', function(ev) {
    return initBasketTab();
  });
}
/**
 * Fonction d'initialisation d'un onglet du porte-documents
 * @param tabSelector {String} La classe CSS utilisee pour selectionner les onglets
 */
function initBasketTab(tabSelector){
  if(tabSelector==null || tabSelector.blank()){
    tabSelector = "div.tab";
  }
  $$(tabSelector).each(function(o,i){
    if(o!=null && o.id!=null & o.visible()){
      initBasketTable("pl-bskt-cnt-"+o.id, o.id);
    }
  });
}
/**
 * Fonction initialisant la DataTable du panier
 *
 * @param tbdId {String} L'identifiant de l'objet HTML/DOM qui contiendra la
 *                       DataTable YUI
 * @param base {String} L'identifiant de la base de documents (optionel).
 * @param isSortable {String} Chaine indiquant que la DataTable est triable ou
 *                            non (optinel, defaut : non).
 * Travail un JSON correspondant au schema suivant :
 * {"resultSet":
      {"returned":{nombre de resultats courant},
        "total":{nombre total de resultats},
        "page":{page courante},
        "pages":{nombre total de pages},
        "start":{index du premier resultat dans la page courante},
        "end":{index du dernier resultat dans la page courante},
        "sort":{nom du champ sur lequel s'effectue le tri, peut etre nul},
        "dir":{ordre du tri, peut etre nul},
        "results":[
          {"id":"{sdxdocid}","rootId":{root-id},"ancestors":{ctitle > ctitle > [...]},"fucomptitle":{fucomptitle},"udate":{udate},"uunitid":{uunitid}},
          [...]
        ]
      }
    }
 */
function initBasketTable (tblId, base, isSortable) {

  if ( !tblId ) return false;
  if (!base ||base.blank()) base = "ead";

  /*TODO (MP) : trouver le moyen de definir une fonction formatTitle_{base} utilisable dans le porte-documents.
                La solution est-elle d'importer systematiquement un fichier theme/js/local/module-eadeac-basket.js ?
                Ou de definir un columndDefs propre a chaque base, un columnDefs
                serait ecrit dans la page HTML, recupere via un template cocoon
                interne ?
  */
  /* initXHR_JSON_DataTable = new function() { */
  tbls[tblId] = new function() {

    var initXHR_JSON_DataTable = this;

    this.currentPage = 0;
    this.totalPages = 0;

    // Definition des colonnes de la DataTable
    this.Sortable = (isSortable=="true") ? true:false;
    this.myColumnDefs = [
			{key:"sdxdocid",
						label:"",
						formatter: formatDocid,
						sortable:this.sortable,
						resizeable:true,
						className:"pl-tbl-th"},
      {key:"fucomptitle",
            label:_usersMessagesBasket.basket_results_col_title_intitule,
            formatter: function(elCell, oRecord, oColumn, sData){
              var _t=false;
              try{ if(eval("formatTitle_"+base)) _t=true;  } catch(e){}
              if(_t){
                return (eval("formatTitle_"+base))(elCell, oRecord, oColumn, sData);
              }
              else{
                return YAHOO.widget.DataTable.formatText(elCell, oRecord, oColumn, sData);
              }
            },
            sortable:this.sortable,
            resizeable:true,
						className:"pl-tbl-th"},
      {key:"udate",
						label:_usersMessagesBasket.basket_results_col_title_date,
						sortable:this.sortable,
						resizeable:true,
						className:"pl-tbl-th"},
      {key:"uunitid",
						label:_usersMessagesBasket.basket_results_col_title_cote,
						sortable:this.sortable,
						resizeable:true,
						className:"pl-tbl-th"}
    ];

    // Initialisation de la DataSource
    this.myDataSource = new YAHOO.util.DataSource("functions/"+((base)?base+"/":"")+"getBasket.json?");
    this.myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
    this.myDataSource.maxCacheEntries = 6;
    this.myDataSource.responseSchema = {
        resultsList: "resultSet.results",
        fields: ["time", "sdxdbid","sdxdocid","rootId","ancestors","fucomptitle","udate","uunitid"]
    };

    this.myDataTable = new YAHOO.widget.DataTable( tblId, this.myColumnDefs,
                              this.myDataSource,
                              {initialRequest:"", // ici on pourrait definir le nombre de resultats par page, etc.
                                sortedBy:{key:"sdxdocid",dir:"desc"},
                                summary:"Contenu du porte-document", // FIXME (MP) : i18n
                                scrollable:true
                              }
                        );

    // Fonction de mise a jour de la navigation.
    this.myDataSource.doBeforeCallback = function(oRequest, oRawResponse, oParsedResponse)
    {
        var oSelf = initXHR_JSON_DataTable;
        var oDataTable = oSelf.myDataTable;

        // Retourne les valeurs courantes de navigation
        var recordsReturned = 0;
        var startIndex = 0;
        var endIndex = 0;
        var currentPage = 0;
        var totalPages = 0;
        var totalRecords = 0;
        var sortCol = "";
        var sortDir = "";
        var oRawResponse = oRawResponse.evalJSON(); // Prototype.js
        var resultSet = oRawResponse.resultSet;
        if ( resultSet ) {
          recordsReturned = oRawResponse.resultSet.returned;
          startIndex = oRawResponse.resultSet.start;
          endIndex = oRawResponse.resultSet.end;
          currentPage = oRawResponse.resultSet.page;
          totalPages = oRawResponse.resultSet.pages;
          totalRecords = oRawResponse.resultSet.total;
          sortCol =  oRawResponse.resultSet.sort;
          sortDir =  oRawResponse.resultSet.dir;
        }

        // Retenir la page courante et le nombre totale de pages.
        // On s'en servira pour les fonctions page precedente / suivante (cf. plus bas)
        oSelf.totalPages = totalPages;
        oSelf.currentPage = currentPage;

        var first = $('firstLink_'+base);
        var last = $('lastLink_'+base);
        var prev = $('prevLink_'+base);
        var next = $('nextLink_'+base);

        // Mise a jour des boutons
        if( currentPage === 1 || currentPage === 0 ){
          if ( prev ) {
            prev.disabled=true;
            prev.addClassName("pl-nvbbtn-dsbld");
          }
          if ( first ) {
            first.disabled=true;
            first.addClassName("pl-nvbbtn-dsbld");
          }
        }
        else {
          if ( prev ) {
            prev.disabled=false;
            prev.removeClassName("pl-nvbbtn-dsbld");
            prev.href = "?p=" + (currentPage - 1);
          }
          if ( first ){
            first.disabled=false;
            first.removeClassName("pl-nvbbtn-dsbld");
            first.href = "?p=1";
          }
        }

        if( currentPage === totalPages ){
          if (next){
            next.disabled=true;
            next.addClassName("pl-nvbbtn-dsbld");
          }
          if (last){
            last.disabled=true;
            last.addClassName("pl-nvbbtn-dsbld");
          }
        }
        else {
          if (next){
            next.disabled=false;
            next.removeClassName("pl-nvbbtn-dsbld");
            next.href = "?p=" + (currentPage + 1);
          }
          if (last){
            last.disabled=false;
            last.removeClassName("pl-nvbbtn-dsbld");
            last.href = "?p=" + totalPages;
          }
        }

        // Mise a jour du texte
        $('total_'+base).innerHTML = totalRecords;
        $('currentPage_'+base).innerHTML = currentPage;
        $('totalPages_'+base).innerHTML = totalPages;

        // getNavigationButtons($('dt-pag-nav'), oSelf.currentPage, 1, 10, oSelf.totalPages );

        // Les valeurs courantes de tri
        var newSortedBy = {
            key: sortCol,
            dir: sortDir
        }
        oDataTable.set("sortedBy", newSortedBy);

         if ( !resultSet ) {
          /* Le panier a ete vide : mise a jour du texte d'erreur pour indiquer
           * que le panier a ete vide et suppression de l'ensemble des enregistrements. */
          YAHOO.widget.DataTable.MSG_ERROR=_usersMessagesBasket.basket_msg_empty;
          oDataTable.deleteRows(0, oDataTable._oRecordSet._length);
        }

        // Let the DataSource parse the rest of the response
        return oParsedResponse;
    };

    // Override function for custom sorting
    this.myDataTable.sortColumn = function(oColumn) {
      var oSelf = initXHR_JSON_DataTable;
      if( oSelf.sortable != true ) {
        /*alert(_usersMessagesBasket.basket_unauthorized_sort)*/;
      }
      else {
        // Which direction
        var sDir = "asc";
        // Already sorted?
        if(oColumn.key === this.get("sortedBy").key) {
            sDir = (this.get("sortedBy").dir === "asc") ? "desc" : "asc";
        }
        var newRequest = "sf=" + oColumn.key + "&so=" + sDir;
        this.getDataSource().sendRequest(newRequest,
                                         this.onDataReturnInitializeTable, this);
      }
    };

    this.getDataTable = function(){
      return this.myDataTable;
    };
    this.getDataSource = function(){
      return this.myDataSource;
    };
    this.getDomContainer = function(){
      return $(tblId);
    };
    this.getCurrentPage = function(){
      return this.currentPage;
    };
    this.getTotalPages = function(){
      return this.totalPages;
    };

    // Fonction reinitialisant le dataTable sur la page demandee
    this.getPage = function(nPage, nResults) {
        // Invalid value
        if(!YAHOO.lang.isValue(nPage)) return;
        var newRequest = "page=" + nPage;
        this.myDataSource.sendRequest(newRequest,
                                      this.myDataTable.onDataReturnInitializeTable,
                                      this.myDataTable);
    };
    // Fonction page precedente
    this.getPreviousPage = function(e) {
        YAHOO.util.Event.stopEvent(e);
        var cp;
        try{ cp = YAHOO.util.Event.getTarget(e).href.toQueryParams().p; } catch(e){}
        if(!cp || cp <=0){
          cp = this.currentPage;
        }
        if ( cp === 1 ) return;
        this.getPage( cp - 1 );
    };
    // Fonction page suivante
    this.getNextPage = function(e) {
        YAHOO.util.Event.stopEvent(e);
        var next;
        try{ next = YAHOO.util.Event.getTarget(e).href.toQueryParams().p; } catch(e){}
        if(!next || next<=0){
          next = this.currentPage + 1 ;
        }
        if (!next) return;
        this.getPage( next );
    };
    // Fonction premiere page
    this.getFirstPage = function(e) {
        YAHOO.util.Event.stopEvent(e);
        this.getPage( 1 );
    };
    // Fonction derniere page
    this.getLastPage = function(e) {
        YAHOO.util.Event.stopEvent(e);
        var tp;
        try{ tp = YAHOO.util.Event.getTarget(e).href.toQueryParams().p; } catch(e){}
        if (!tp || tp<=0){
          tp = this.totalPages;
        }
        if ( !tp ) return;
        this.getPage( tp );
    };

    // Observe le click sur les deux boutons
    YAHOO.util.Event.addListener(YAHOO.util.Dom.get("prevLink_"+base),
                                 "click", this.getPreviousPage, this, true);
    YAHOO.util.Event.addListener(YAHOO.util.Dom.get("nextLink_"+base),
                                 "click", this.getNextPage, this, true);
    YAHOO.util.Event.addListener(YAHOO.util.Dom.get("firstLink_"+base),
                                 "click", this.getFirstPage, this, true);
    YAHOO.util.Event.addListener(YAHOO.util.Dom.get("lastLink_"+base),
                                 "click", this.getLastPage, this, true);
  };
}

/**
 * Fonction construisant le titre des documents EAD dans le panier
 * Le titre du document dans un lien hypertexte vers la visionneuse EAD
 * eventuellement precede de la liste des ancetres (au sens Pleade du terme).
 */
formatTitle_ead = function(elCell, oRecord, oColumn, sData) {

  // construction du lien vers la visionneuse EAD
  var rootId = oRecord.getData("rootId");
  var docId = oRecord.getData("sdxdocid");
  var href = "ead.html?id=" + rootId;
  if ( rootId!= docId )
      href += "&c=" + docId;

  // construction du titre
  var title = sData;
  if ( !title || title.blank() ) title = _usersMessagesBasket.basket_results_untitle_doc; // pas de titre

  // construction de la liste des ancetres
  var ancestors = oRecord.getData("ancestors");

  if ( ancestors && !ancestors.blank() ) {

    elCell.innerHTML = "<a href=\""+href+"\" onclick=\"return winFocus(this.href, 'docead');\">"+title+"</a>" +
		"<div class=\"pl-ancestors\"><a class=\"pl-ancestors\" style=\"display:inline;\" id=\""+docId+"\" onclick=\"$('"+docId+"c', '"+docId+"m1', '"+docId+"m2').invoke('toggle')\" style=\"cursor:pointer;\"><span class=\"pl-ancestors-on\" id=\""+docId+"m1\">"+_usersMessagesBasket.basket_results_context_show+"</span><span id=\""+docId+"m2\" class=\"pl-ancestors-off\" style=\"display:none;\">"+_usersMessagesBasket.basket_results_context_hide+"</span>&#160;</a>" +
                    "<span id=\""+docId+"c\" class=\"pl-ancestors-txt\" onclick =\"this.toggle();$('"+docId+"m1', '"+docId+"m2').invoke('toggle');\" style=\"display:none;\">"+ancestors+"</span></div>";
  }
  else {
    elCell.innerHTML = "<a href=\""+href+"\" onclick=\"return winFocus(this.href, 'docead');\">"+title+"</a>";
  }
};

/**
 * Fonction constuisant le case a cocher permettant de selectionner la notice
 * dans le panier.
 */
formatDocid = function(elCell, oRecord, oColumn, sData) {

  // construction du lien vers la visionneuse EAD
  var docId = oRecord.getData("sdxdocid");
  var fn = "entryChecked(this, '"+oRecord.getData("sdxdbid")+"');"; // la fonction activee lorsqu'on selectionne le document courant
  var onclick = " onclick=\""+fn+"\"";
  var onkeypress = " onkeypress=\""+fn+"\"";
  elCell.innerHTML = "<input type=\"checkbox\" value=\"" + docId +"\""+ onclick + onkeypress +
                      "class=\"" + YAHOO.widget.DataTable.CLASS_CHECKBOX + " pl-form-chckbx\">";

};

/**
 * Formatage de la liste des ancetres Pleade
 */
plAncestorsFormatter = function(elCell, oRecord, oColumn, oData) {
  if ( !elCell || !oRecord ) return "";
  var cellId = oRecord.getId();
  var id1 = cellId + "l";
  var id2 = cellId + "c";
  elCell.innerHTML = "<div id=\""+id1+"\" style=\"display:block;\" onclick=\"$('"+id1+"').hide; $('"+id2+"').show\">[...]</div>" +
                     "<div id=\""+id2+"\" style=\"display:none;\" onclick=\"$('"+id2+"').hide; $('"+id1+"').show\">" + oData + "</div>";
}

/*
 * Gestion de la selection / deselection de notice dans le DataTable
 * Tenir a jour le tableau des identifiants de document selectionnes
 */
function entryChecked(o,b){
  if (o){
    var slct = $A(selecteds);
    var bs = $A(selectedBases);
    if (o){
      if ( o.value==null || o.value.blank() || !slct );
      else{
        if(o.checked==false){
          if ( slct.indexOf(o.value) != -1 ){
            selecteds = slct.without(o.value);
          }
          // TODO: Comment faire pour savoir si on doit supprimer la base courante de la liste des bases touchees ?
        }
        else{
          if(slct.indexOf(o.value)==-1){
            selecteds.push(o.value);
          }
          if(bs && b && bs.indexOf(b)==-1){
            selectedBases.push(b);
          }
        }
      }
    }
  }
}

/*
 * Fonction pour formater les boutons de navigation page par page.
 * Pas termine, on ne s'en sert pas pour le moment.
 */
getNavigationButtons = function(elContainer, nCurrentPage, nPageLinksStart, nPageLinksLength, nTotalPages){
  // Start with first and previous
  var sMarkup = sFirstLinkMarkup + sPrevLinkMarkup;

  // Ok to show all links
  var nMaxLinks = nTotalPages;
  var nFirstLink = 1;
  var nLastLink = nTotalPages;

  if(nPageLinksLength > 0) {
  // Calculate how many links to show
      nMaxLinks = (nPageLinksStart+nPageLinksLength < nTotalPages) ?
              nPageLinksStart+nPageLinksLength-1 : nTotalPages;

      // Try to keep the current page in the middle
      nFirstLink = (nCurrentPage - Math.floor(nMaxLinks/2) > 0) ? nCurrentPage - Math.floor(nMaxLinks/2) : 1;
      nLastLink = (nCurrentPage + Math.floor(nMaxLinks/2) <= nTotalPages) ? nCurrentPage + Math.floor(nMaxLinks/2) : nTotalPages;

      // Keep the last link in range
      if(nFirstLink === 1) {
          nLastLink = nMaxLinks;
      }
      // Keep the first link in range
      else if(nLastLink === nTotalPages) {
          nFirstLink = nTotalPages - nMaxLinks + 1;
      }

      // An even number of links can get funky
      if(nLastLink - nFirstLink === nMaxLinks) {
          nLastLink--;
      }
}

  // Generate markup for each page
  for(var i=nFirstLink; i<=nLastLink; i++) {
      if(i != nCurrentPage) {
          sMarkup += " <a href=\"#\" class=\"" + YAHOO.widget.DataTable.CLASS_PAGE + "\">" + i + "</a> ";
      }
      else {
          sMarkup += " <span class=\"" + YAHOO.widget.DataTable.CLASS_SELECTED + "\">" + i + "</span>";
      }
  }
  sMarkup += sNextLinkMarkup + sLastLinkMarkup;
  elContainer.innerHTML = sMarkup;
};

