Reminder - Digital Publishing Suite (DPS) will End of Life on August 31st, 2019. 

by Brian Hinkelman

Brian Hinkelman


Table of contents


8 September 2014

Prerequisite knowledge
  • Basic InDesign Skills
  • Digital Publishing Suite Overlays
  • HTML and JavaScript recommended
User level: All
Required Adobe products (retail)
Additional products (third-party/labs/open source)
  • HTML/JavaScript Editor
Sample files
By downloading software from the Adobe website you agree to the terms of our license agreement. Please read it before downloading.


Note: If you have questions about this article, use the DPS forum. Please don’t contact technical support with questions about Adobe Developer Connection articles.



Sales Enablement is becoming an increasingly common use case scenario for DPS applications. Communications and Marketing can centrally manage content, ensure materials are always up-to-date, send notifications that are hard to miss, and view analytics that show what is being used, by who, and how. Field reps enjoy the benefit of a one-stop shop for collateral, with the ability to present interactive content to customers on their mobile device when they are offline.
DPS app content is not editable by end-users. While this protects content from end-users adding green text in Curls Bold on a bright orange background, there is often a need to provide some level of customization. 
The request I hear the most is how organizations can enable the end-user to customize the presentation experience, such as using a “master” folio, with the flexibility to choose specific content within that folio to present to a customer. In a DPS application, end-users cannot delete content within a folio. However, leveraging the Reading APIs introduced in r30, we can create a custom navigation scheme that “skips” content we would like to hide. This provides a fluid delivery, without having to navigate using the TOC or necessitating the designer create multiple custom folios.

How it Works

Adding this capability to a folio is actually quite simple, using two Web overlays. 
The first Web overlay is placed on a “configuration page” within a folio (ideally, at the end).  Prior to delivery, the presenter will navigate to a configuration page.  The configuration Web overlay gathers article metadata from the entire folio and present a list of articles in an HTML form. The presenter can check the articles which they would like to keep visible. On clicking “Save”, a list of the checked articles is saved to the device in HTML localstorage[].
The second overlay is the navigation overlay. For this navigation to work, the page navigation Web overlay is placed on each page in each article. The navigation overlay consists of two navigation links – “next” and “previous”, which are dynamically created.
When each page loads, it checks for the current article position number. Then it checks for the current article position in the list, and assigns the adjacent article numbers to the “next” and “previous” buttons.
In the sample files for this article, we assume that the desired result is to tap anywhere on the right side of the page to navigate forward, and anywhere on the left side to navigate backward. The navigation buttons are transparent, so as to not distract from the content. The overlay, which is placed to cover most of the page (leaving a small buffer at the top for the HUD), has two transparent boxes that fill the left and right side of the page, using CSS.
Example: A folio with 6 articles.  Articles 1-5 being the content, and Article 6 being the Configuration Page:
  • The end-user navigates to the end of the folio to configure the navigation.
  • The page displays all 5 articles found in the folio. The end-user checks Articles 1, 3, and 5, and clicks “Save”.
  • The end-user navigates to page 1. When the end-user taps on the right side of the screen, it navigates to page 3. If the end-user taps the right side again, it navigates to page 5. If the end-user taps the right side again, nothing happens (as they have reached the last article marked as viewable).  Tapping left navigates back to page 3.
  • The navigation settings are saved, even if the end-user closes the app and returns later.


Custom navigation example
Figure 1: Custom navigation example
A Code-free Workflow for Designers
Part of the design of this code was to enable designers to be able to add few Web overlays to any folio, without the necessity to know HTML. The designer can add the sample files to any folio by performing the following steps:
  1. Add all the files in the HTMLResources folder from the sample code to Add the zip file to the folio.
  2. Add a single page article at the end of the folio and place a Web overlay pointing to the config.html file.
  3. Add a Web overlay pointing to pageNav.html to each article/page within the folio.
In the “tap right/left to navigate” example, as the pageNav overlay takes up most of the page, it shoud be placed in a layer below other interactive overlays to ensure they still work. Also, it should ensure that you do not leave the page unintentionally when you meant to tap a slideshow. Ensure that “Allow Access to Entitlement Information” is checked on the config and pageNav Web overlays.
In order to test, you need to have the content in Folio Producer and view using either Adobe Content Reader or a DPS App. You will not be able to test the navigation using the “Preview” button in InDesign.
When placing the PageNav overlay, consider leaving a small margin of the page uncovered to allow the user to tap and bring up the HUD. Otherwise you risk the end-user from being able to exit the folio.


There is plenty of scope for further customization. Designers with HTML/CSS skills can modify the UI easily. If you have JavaScript experience, you can further customize the navigation control.
Sample File List and corresponding descriptions:
  • AdobeReadingAPI.js – Reading API used to access Article Metadata. This file should not be edited.
  • config.html – Web overlay placed on the configuration page
  • customNavConfig.js –JavaScript include file for config.htm
  • pageNav.html – Web overlay that will be placed on each article page to enable the custom navigation
  • pageNav.js – JavaScript include file for pageNav.html
  • customNav.css – Style sheet file used in both overlays
HTML/CSS Customization
The UI for the config.html and pageNav.html are defined in customNav.css by CSS.  If you are familiar with HTML/CSS and wish to customize the interface, you can edit the CSS file as needed. In the included example, the navigation buttons are transparent and cover the whole page. If you prefer something else (such as visible “Next” and “Prev” buttons) and would like to change it, edit a.navButton.
Preventing Swiping
Using this type of navigation requires tapping on an object. You cannot disable swiping in a DPS Application. However, you can leverage a workaround by placing the PageNav overlay in a scrollable frame. When adding your PageNav overlay, extend the width of the overlay 10 pixels wider than the page. Draw a new rectangle frame with the width of the page. Copy the PageNav overlay and paste into the new frame. Set the new frame as a horizontal scrollable frame and hide the scrollbars. When the user swipes, nothing will happen ( - the invisible PageNav overlay shifts slightly). The only areas the user will still be able to swipe are overlays (on top of the PageNav overlay) that do not have a swiping action (such as a video) and any area not covered by the PageNav overlay.
Updating the Files in
In this example, the necessary files are stored in for storage efficiency. During your development and testing, the following steps are recommended:
  • Extract all the files from and copy them on a Web server
  • Change the paths to point to the Web server URL instead of the “HTMLResources\” url.
On completion of testing, the following steps are recommended:
  • Change the paths back to the “HTMLResources\” URL
  • Place your final files in and upload to the folio.
There are two important reasons why this is recommended:
  1. It will allow you to test your changes instantly, without having to update Folio Producer everytime you make a change.
  2. Once the files in are uploaded to Folio Producer, they cannot be changed, even if you upload a new zip file. If you update a file after uploading, you would have to rename the changed files within the zip, and then update all references to it across the folio (and other files within
The files need not be stored in and can be placed on a Web server. stores the files locally and efficiently, and allows the end-user to work offline. See Importing HTML Resources for more information.
Note: To store files on a Web server, ensure that the end-user is online and has access to the URL, for the navigation to work.
Configuration Overlay using the API
The configuration Web overlay is responsible for:
  • Gathering article metadata for the entire folio
  • Presenting it to the user in an HTML form
  • Saving the end-user’s choices in HTML localstorage.
Load the Reading API first. It is important that no functions are executed until the API is fully loaded. To ensure that the API is fully loaded and is ready to return folio metadata, you can call the empty function init() using the adobeDPS.folioDataService.readySignal.addOnce() method. You can call the empty function by using the window.onAppear command and execute the function to collect the metadata.
adobeDPS.folioDataService.readySignal.addOnce(init); function init() { //do nothing } window.onAppear = function() { getData(); //begin using the API }
Once the API is loaded, it uses the adobeDPS.folioDataService.getArticleMetaData() method to get data from the articles. The API has to run this method on each article and article position numbers start at 0. So in the sample 6-article folio, it scans 0 to 4 (excluding 5, as article 6 is the config page).
To point the getArticleMetaData() method at an article, the index is the position relative to the article in which it is being executed. If the API is running this from Article 6 (which is really position 5), and we want to get the article metadata for the first article (position 0), it needs to start at -5, ending at -1 (not 0, excluding the config page).
As we want to be able to reuse these overlays in other folios, it is not hard-coded. To determine the starting relative index of any folio, we need to do the following:
  1. Get the total number of articles in the folio by calling adobeDPS.folioDataService.totalArticlesInFolio
  2. Converting the number into a negative number, and then subtracting 1. 
This assumes that the configuration page will always be the last article:
var firstArticlePos = -(adobeDPS.folioDataService.totalArticlesInFolio-1);
Now we are ready to send our tiny electronic census collectors to visit each folio and get the data:
for ( var i = firstArticlePos; i < 0; i++ ) { adobeDPS.folioDataService.getArticleMetaData(i,function(articleMetaData,ind) { var thisArticleNum = ind + (adobeDPS.folioDataService.totalArticlesInFolio-1); var isChecked = checkExisting(thisArticleNum); var html = el.innerHTML; //write data to HTML Table… }, function (error) { // debug code });
i will be the index, looping until we get to 0 (the current article). The method returns the articleMetaData constructor which has the folio metadata. The article position number is not one of those fields. As we get data from each article, we need to calculate the article position using each article’s relative index (ind), and set as the checkbox value in the form. That will be the number that is saved in the list of visible articles.
You need to add the checkExisting() function, which looks to see if there is already a saved list. If yes, pre-check the items already in the existing list:
function checkExisting (currentItemNum) { if (localStorage[getFolioID()]) { var htmlStorageArray = []; htmlStorageArray = localStorage[getFolioID()].split(','); var isFound = htmlStorageArray.indexOf(currentItemNum.toString()); if (Number(isFound) >= 0) { return "checked"; } else { return ""; } } }
When the end-user has selected the articles for viewing, the “Save” button calls saveList() which takes the value (which is the article position) of each checked folio and saves it to a list in localStorage[]. getFolioID() uses the folio path name to create a unique index name for localStorage[]. This allows multiple folios on the device to have their own custom navigation.
Navigation Overlay Using the API
Navigation Overlay is responsible for:
  • Reading the list in HTML localstorage
  • Generating forward and back navigation buttons using navto://releative links
Navigation Overlay is added to each article and page in the folio. Once localStorage[] has a list of articles, we must be able to read it and set the navigation buttons dynamically.
  1. Ensure the reading API is ready, just as we did in the configuration page.
  2. Determine what page we are on, using adobeDPS.folioDataService.getArticlePosition()method:
adobeDPS.folioDataService.getArticlePosition (function(articlePosition) { currentArticlePosition = articlePosition.currentIndexInFolio.toString(); setNavButtons(currentArticlePosition); })
  1. Check in the list stored in localStorage[] using getFolioID(), to ensure we are pulling the list for this folio:
function getFolioID() { var pathArray = window.location.pathname.split("/"); var folioID = pathArray[pathArray.length - 5]; return(folioID); }
  1. Check the list to see if the current article is in the list. If yes, get the article numbers before and after:
function setNavButtons(currentArticlePosition) { var htmlStorageArray = localStorage[getFolioID()].split(','); var currentArraypos = htmlStorageArray.indexOf(currentArticlePosition); var nextFolioNum = Number(htmlStorageArray[currentArraypos+1]); var prevFolioNum = Number(htmlStorageArray[currentArraypos-1]); //set HTML href properties… }
In the sample file, pageNav.html starts with two transparent navigation boxes, 50% wide and 100% height. Once the next and previous article position numbers have been determined, setNavButtons() sets the href properties of the “customNextPage” and “customPrevPage” links with navto://relative/ and their respective article position numbers. If they are at the start/end of the defined list, the link remains unset and the button does nothing.

Where to Go from Here

This is really just a basic example of how you can take advantage of the Reading APIs for custom navigation. You could add more functionality such as:
  • Allow the end-user to reorder the navigation list
  • Make visible navigation buttons
  • Add the ability to navigate to any page in an article (and not just the first).
As it is essentially HTML elements, you can do just about whatever in HTML. If you are leveraging entitlement, you could store the navigation settings on a Web service, and access the end-user’s navigation settings across multiple devices. In the event of an accidental swipe to a hidden page, you could add few lines of code to identify when the viewer lands on a page that is not in the list, and automatically navigate to a valid page, or maybe rickroll them if you are feeling nefarious.
For additional resources, see the article on the r30 Navigation APIs.  You can also review the Adobe DPS Reading SDK for detailed documentation on Reading APIs.
Comments are currently closed as we migrate to a new commenting system. In the interim, please provide any feedback using our feedback form. Thank you for your patience.