Bob’s ultimate view navigator – categorized view

I love Bob Obringer’s solution for a view navigator. Especially you can easily improve the user’s navigation experience in existing applications.

For example I received a few days ago a request to investigate the options to improve performance on a view. After a quick investigation default a view was opened with the URL parameter &Count=1000. Happy waiting! Further the application enables you to navigate through the documents by opening a categorized view with &RestrictToCategory= parameter, again followed by the &Count=1000 parameter.

Implementing Bob’s solution for the flat was was piece of cake, just copy & paste.

Unfortunately Bob’s approach only works on a flat view and some of the functionality it is is not suitable for a categorized view:

  • the cookie function
  • the function to enter a page number directly in an input field

 Therefor I rewrote the script a bit, preserving 95% of Bob’s code. Thanks Bob!

viewnav02.jpg

URL opened:

http://server.domain.com/path/database.nsf/web_internetRegionCat?OpenView&RestrictToCategory=USA&Count=15

// initViewNav function, loaded at onLoad event of form
/************************************************/
function initViewNav(range, cache, div1, div2) {
 navRange = range;
 navCache = cache;
 navDiv1 = div1;
 navDiv2 = div2;
 startDoc = queryString(‘start’);
 startDoc = (startDoc == “”) ? 1 : parseInt(startDoc);
 docsPerPage = queryString(‘count’);
 docsPerPage = (docsPerPage == “”) ? 20 : parseInt(docsPerPage);
 waitForDocCount()
}

// QueryString function
/****************************************************/
function queryString(key){
 var page = new PageQuery(window.location.search);
 return unescape(page.getValue(key.toLowerCase()));
}

function PageQuery(q) {
 if(q.length > 1) this.q = q.substring(1, q.length);
  else this.q = null;
 this.keyValuePairs = new Array();
 if(q) {
  for(var i=0; i < this.q.split(“&”).length; i++) {
   this.keyValuePairs[i] = this.q.split(“&”)[i].toLowerCase();
  }
 }
 this.getKeyValuePairs = function() { return this.keyValuePairs; }
 this.getValue = function(s) {
  for(var j=0; j < this.keyValuePairs.length; j++) {
   if(this.keyValuePairs[j].split(“=”)[0] == s)
   return this.keyValuePairs[j].split(“=”)[1];
  }
  return “”;
 }
 this.getParameters = function() {
  var a = new Array(this.getLength());
  for(var j=0; j < this.keyValuePairs.length; j++) {
   a[j] = this.keyValuePairs[j].split(“=”)[0];
  }
  return a;
 }
 this.getLength = function() { return this.keyValuePairs.length; }
}
/****************************************************/

// Cookie functions
/****************************************************/
function getExpiryDate(minutes){
 var UTCstring;
 Today = new Date();
 nomilli = Date.parse(Today);
 // Today.setTime(nomilli + (minutes * 60000));
 // Today.setTime(nomilli + (minutes * 0)); 
 // Means Cookies disabled!
 // This done because we work with a &RestrictToCategory command in a categorized view and we switch all the time from categories…
 Today.setTime(nomilli + (minutes * 0));
 UTCstring = Today.toUTCString();
 return UTCstring;
}

function setCookie(name, value, duration){
 cookiestring = name + “=” + escape(value) + “; EXPIRES=” + getExpiryDate(duration);
 document.cookie = cookiestring;
}

function getCookie(cookiename) {
 var cookiestring = “” + document.cookie;
 var index1 = cookiestring.indexOf(cookiename);
 if (index1 == -1 || cookiename == “”) return “”;
  var index2 = cookiestring.indexOf(‘;’, index1);
 if (index2 == -1) index2 = cookiestring.length;
  return unescape(cookiestring.substring(index1 + cookiename.length + 1, index2));
}
/*****************************************************/

// Get View Navigator HTML
/*****************************************************/
var startDoc = 0;
var docsPerPage = 0;
var totalPages = 0;
var navRange = 0;
var navCache = 0;
var navDiv1 = “”;
var navDiv2 = “”;
// var checkCookie = true;
// cookies has not use with a &RestrictToCategory command in a categorized view
var checkCookie = false;
var totalDocs = “”;
function waitForDocCount() {
 if (checkCookie) {
  totalDocs = getCookie(‘totaldocs’);
  checkCookie = false;
 }
 if (totalDocs == “”) {
  getDocCount();
  setTimeout(“waitForDocCount()”, 100);
 } else {
  drawViewNav();
 }
}
/*******************************************************/

// Function to get document count using XMLHTTP
/*******************************************************/
function getDocCount () {
 var xmlHttp = getXMLHTTP();
 xmlHttp.open(“GET”, dbPath + viewAlias + “?ReadViewEntries&RestrictToCategory=”+ Categories );
 xmlHttp.onreadystatechange = function() {
  if (xmlHttp.readyState == 4 && xmlHttp.responseText) {
   var resp = xmlHttp.responseText;
   var countTag = resp.toLowerCase().indexOf(‘toplevelentries’);
   if (countTag > 0) {
    resp = resp.substr(resp.indexOf(‘”‘, countTag) + 1);
    totalDocs = resp.substring(0, resp.indexOf(‘”‘));
    setCookie(‘totaldocs’, totalDocs, navCache)
   }
  }
 };
 xmlHttp.send(null);
}
/**************************************************/

// Wrapper function to get a cross browser XMLHTTP object
/**************************************************/
function getXMLHTTP() {
 // function to create an XmlHttp object
 var xmlHttp = null
 try {
  xmlHttp = new ActiveXObject(“Msxml2.XMLHTTP”)
 } catch(e) {
  try {
   xmlHttp = new ActiveXObject(“Microsoft.XMLHTTP”)
  } catch(oc) {
   xmlHttp = null
  }
 }
 if(!xmlHttp && typeof XMLHttpRequest != “undefined”) {
  xmlHttp = new XMLHttpRequest()
 }
 return xmlHttp
}
/**************************************************/
// viewnav.js file
/**************************************************/
function drawViewNav() {
 // Do all our calculations to find out where we are in the view
 partialPages = totalDocs / docsPerPage;
 extraPage = (partialPages == Math.floor(partialPages)) ? 0 : 1;
 totalPages = Math.floor(partialPages) + extraPage;
 curPage = Math.floor(startDoc / docsPerPage) + 1
 // Figure out the number of the first and last pages to display on the navigator
 startLink = (curPage < (navRange + 1)) ? 1 : curPage – navRange;
 endLink = ((curPage + navRange) > totalPages) ? totalPages : curPage + navRange;
 // Start writing our menu 
 navHTML = “<div class=’nav’ align=’center’><table class=’navtable’ cellpadding=’0′ cellspacing=’0′><tr>”;
 // Write out the “First”, “Jump”, and “Previous” links when applicable
 if (startLink > 1) {
  navHTML = navHTML + buildLink(1, “First”);
  navHTML = navHTML + buildLink(curPage – (navRange + 1), “<<“);
 } 
 if (curPage > 1) navHTML = navHTML + buildLink(curPage – 1, “<“);
 // Generate all the page # links we want to display
 for (i = startLink; i <= endLink; i++) {
  if (i == curPage) {
   navHTML = navHTML + “<td class=’navtablecur’>” + i + “</td>”
  } else {
   navHTML = navHTML + buildLink(i, i);
  }
 } 
 // Write out the “End”, “Next”, and “Jump” links when applicable
 if (curPage < totalPages) navHTML = navHTML + buildLink(curPage + 1, “>”);
 if (endLink < totalPages) {
  navHTML = navHTML + buildLink(curPage + (navRange + 1), “>>”);
  navHTML = navHTML + buildLink(totalPages, “Last”);
 }
 // Close the list of links
 navHTML = navHTML + “</td>” 
 // Write out the “Page x of y” text and create input box
 //navHTML = navHTML + “<td class=’navpages’>Page “;
 navHTML = navHTML + “<td class=’navtablelink’>Page “;
 // input field for page number is disabled because this does not work for a categorized view
 //navHTML = navHTML + “<input title=\”Click to enter a new page number here\” onKeyUp=\”void(getPage(event, this))\” “;
 //navHTML = navHTML + “onClick=’this.select()’ onFocus=’this.select()’ type=’text’ value='” + curPage + “‘ />”;
 navHTML = navHTML + curPage ;
 navHTML = navHTML + ” of ” + totalPages + “</td>”;  
 // Close out the menu
 navHTML = navHTML + “</tr></table></div>”;
 // Write out the navigator
 document.getElementById(navDiv1).innerHTML = navHTML;
 if (typeof navDiv2 != “undefined”) document.getElementById(navDiv2).innerHTML = navHTML;
  document.getElementById(‘view’).style.display = ‘block’;
}

function buildLink(pageNum, text) {
 startLinkDoc = (((pageNum – 1) * docsPerPage) + 1);
 endDoc = (pageNum == totalPages) ? totalDocs : startLinkDoc + docsPerPage  // Check for last page when creating tooltip range
 linkHTML = “<td class=’navtablelink’ onmouseover=\”this.className=’navtablelink_on’\” onmouseout=\”this.className=’navtablelink’\” ”
 linkHTML = linkHTML + “title=’Page ” + pageNum + ” : Documents ” + startLinkDoc + ” through ” + endDoc + “‘ “;
 linkHTML = linkHTML + “onclick=document.location.href='” + viewAlias + “?OpenView&RestrictToCategory=”  + Categories + “&Start=” + startLinkDoc + “&Count=” + docsPerPage + “‘>” + text + “</td>”;
 return linkHTML;
}

function getPage(event, field) {
 var keyCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
 if (keyCode == 13) {
  newPage = field.value;
  if (newPage > totalPages || newPage < 1) {
   field.select();
   return false;
  }
   document.location.href = dbPath + viewAlias + “?OpenView&RestrictToCategory=”  + Categories + “&Start=” + (((newPage – 1) * docsPerPage) + 1) + “&count=” + docsPerPage
 }
}
/************************************************************/

The variable Categories is a value I receive from one of the dialoglists on top of the screen. The screen is a frameset with 2 frames.

In the dialoglist I have a JS OnChange event opening the url in the bottom frame:

varURL = “web_internetRegionCat?OpenView&RestrictToCategory=” + varSelect + “&Count=” + varNumPage}

In the bottom frame I open a View via a ‘$$ViewTemplate for viewname’ Form. In the HTML Head section of the Form I calculate the variable Categories, via:

varCategories:=@Right(Query_String_Decoded;”OpenView&RestrictToCategory=”);
varCategories:=@If(@Contains(varCategories;”&Start”);@Left(varCategories;”&Start”);@Left(varCategories;”&Count”));

Advertisements

12 thoughts on “Bob’s ultimate view navigator – categorized view

  1. Jan Van Puyvelde 2007-March-29 / 2:24 pm

    If I read the code correctly, the “ReadViewEntries” part will return ALL entries in the XML response. After that, what’s the point of navigating the view with pages containg 15 entries ?

  2. quintessens 2007-March-29 / 3:35 pm

    Link = updated.

    A point would be that you dont have a long list of documents for scrolling, so a steady page.

    A page numbering on a fixed place on the screen.

    Yes in ordering of writing a correct index you have to load the entire view (at least the documents underneath a category) 😕

  3. Jan Van Puyvelde 2007-March-29 / 3:44 pm

    OK, now I understand. The “ReadViewEntries” part by default returns 30 entries but includes the total count for the view or category.
    Thanks. I will make use of your code.

  4. Daniele Grillo 2007-June-19 / 3:45 pm

    I don’t find the Bob Ultimate view navigator…
    The LInk are inaccessible
    Can you send me or attach TO YOUR post?

    Tnx for all

  5. Ravi 2007-September-12 / 10:44 am

    The URL to bob’s site is not working anymore. I have searched for Bob’s Ultimate domino view navigator and have not found the same on the net.

    Can you email the same to me.

  6. Safi 2007-October-23 / 2:12 pm

    Hi!
    I am in the same position as Ravi ..
    Can you send a copy of this application ?
    Thanks in advance ..:-)

  7. Bruce Elgort 2007-November-7 / 3:55 pm

    Patrick,

    Can you please contact me regarding your code? I have some questions. Thank you.

  8. fedex79 2008-May-26 / 6:17 pm

    where i can download the Bob Obringer’s solution ??? (the NSF File) bob-obringer.com site not work

    thanks

  9. Kuldeep Singh 2009-April-10 / 11:59 pm

    Hi,

    Could you please send me the database copy for “ultimate domino view navigator” on justkuldeepsingh@gmail.com

    Thanks in advance

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s