Skip to content

Ono List Pager

The Ono List Pager is a very configurable jQuery plugin for transforming ordinary HTML lists in a UI control. To see the Ono List Pager in action, check out the demo page or go directly to the download page.

Demo

Download

Table Of Contents

Some quick specs:

  • Works in IE7+, Firefox, Chrome, Safari and Opera.
  • Supports gestures in mobile browsers.
  • Supports arrow key events.
  • Works with the principle of progressive enhancement, so your content is also accessible to search engines and users without JavaScript.
  • Very configurable and extendible.
  • Open source and available on Github.
  • The library size is just 30Kb. If your webserver uses gzip files, it will be even smaller.

Installation

You need to load the following components in order to run the Ono List Pager:

  • <script src=”javascript/jquery.min.js”></script>
  • <script src=”javascript/jquery.easing.1.3.min.js”></script>
    (optional but recommended)
  • <script src=”javascript/jquery.onopager.min.js”></script>
  • <link href=”css/onoPager-basic.css” rel=”stylesheet” />
  • <link href=”css/onoPager-theme-greyscale.css” rel=”stylesheet” />
    (optional)

Basic usage

After that you can change any list (UL or OL) into a pager by calling something like this:

jQuery('#foo').onoPager({
  cssClass: 'onoPager_greyscale',
  listContainer: {
    width: '280px'
  },
  listItems: {
    width: '260px'
  },
  status: {
    active: false
  },
  pageByArrowKey: {
    active: true,
    preventDefault: false
  },
  swipeTriggersPage: true,
  animationType: 'linear',
  animationEasing: 'easeOutCubic',
  animationSpeed: 1000
});

This example uses just a few of the possible configuration options. Check out the demo page for more configuration examples. You can read more about each configuration option on the documentation site.

Custom transitions

How animation objects work

The animations for the paging transitions and the time indicators are open for extension. To understand how it works, we’ll have to look at an existing animation. If you look at the code example above, you’ll see the option animationType: 'linear'. What the onoPager does is creating a base animation object, defined in the namespace onoPager.animation._standard that you can find in the file jquery.onopager.animation.js. In that base object standard internal values and methods are defined.

After that the base object is extended with the custom ‘linear’ object in the namespace onoPager.animation.linear. The base object is only extended when the custom animation object complies to a simple interface: it must have 3 public methods called ‘init’, ‘page’ and ‘pageHover’.

Make your own custom object

It’s best to create a custom animation object by copying and then editing an existing one. You can copy a relatively simple object like onoPager.animation.linear and rename it to onoPager.animation.foo. Since we will create a brand new object i would recommend you to save the object in a separate file (jquery.onopager.animation.foo.js) and make sure that this file is loaded.

Before we are going to edit this brand new animation object, let’s examine the first lines:

onoPager.animation.foo = function(newConfig, extraConfig) {
  /**
   * New animation object.
   * @memberOf onoPager.animation.foo
   * @this
   */
  var fooInstance = new onoPager.animation._standard(newConfig, extraConfig);
  var tools = onoPager.tools;

On line 7 the base object is created. You can look at the code in onoPager.animation._standard to see what’s in it.

On line 8 a shortcut is created to onoPager.tools. This object has many helper methods. Most of them give different values depending on the orientation you chose in the configuration. The orientation is either ‘horizontal’ or ‘vertical’, but you could make up your own orientation if you want to.

The interface

After that you get the public methods that make up any animation object interface:

/**
   * @see onoPager.animation._standard#init
   * @memberOf onoPager.animation.linear
   * @this
   */
  fooInstance.init = function() {
    ...
  }

  /**
   * @see onoPager.animation._standard#init
   * @memberOf onoPager.animation.linear
   * @this
   */
  fooInstance.page = function(oldIndex, newIndex, direction) {
    ...
  }

  /**
   * @see onoPager.animation._standard#pagerHover
   * @memberOf onoPager.animation.linear
   * @this
   */
  fooInstance.pagerHover = function(move) {
    // Not implemented
  }
  • init is an event that is called when the animation object is created. You use this event to set up the pager
  • page is an event that is called when the user initiates an event. As arguments it will send the index of both the current page and the next page. In some cases, like in the linearContinuous animation object, you’ll need the third argument ‘direction’ to know in which direction the pager is heading.
  • pagerHover is an event that is triggered when the user hovers the mouse over the ‘next’ or ‘previous’-link and is used in the scroller animation object.

Within those events anything goes. You can place any code you like. But most of the time, you’ll want to use the variables and methods of the base class. So lets look at the variables that are available in the base class:

onoPager.animation._standard = function(newConfig, extraConfig) {
// These default variables are overwritten by the variables in the argument
// "newConfig". All variables are explained in
// http://www.thebrightlines.com/onopager/documentation/onoPager/symbols/onoPager.animation.html#.createAnimation.
  this._config = {
    list: null, /* The list element */
    listContainer: null, /* The element that contains the list */
    listContainerHeight: '', /* Default height of the container (if set) */
    adjustHeightToListItem: {}, /* Sets height per page if { active: true } */
    listItems: null, /* The list item elements */
    animationSpeed: 1000, /* The default animation speed */
    orientation: null, /* Horizontal or vertical */
    pagePerItem: true,
    pageNext: null, /* The page 'next'-element */
    pagePrevious: null, /* The page 'previous'-element */
    activeIndex: 0, /* The index of the visible page view */
    pager: {}, /* Reference to pager object */
    scroller: {}, /* Reference to scroller object */
    autoPage: {}, /* Reference to autopager object */
    extraConfig: {} /* Extra optional configuration for the animation object */
  };

You won’t need all variables, but you certainly will need a few. These default variables in this._config are overwritten by the variables in the argument “newConfig”. All variables are explained with a bit more detail in the documentation.

animation.init

This method is called after the animation object is initialized. The comments explain what is done here. In the code are a lot of references to variables in the base object like this._config.orientation to know if the pager must animate on the horizontal or vertical axis. Another base functionality is the method linearInstance._setActiveClass() that will set the class “active” on the visible list item (if pagerPerItem is set to true).

An interesting base method is tools.getOuterSize(). By supplying the orientation like this tools.getOuterSize(linearInstance._config.orientation, jQuery(this)), the code will get either the total width or height, depending on the current orientation.

In animation objects are always a lot of references to this._config.listItems and this._config.list, which, if the pager is built with an unordered list, are references to the UL and the LI’s of the pager.

  linearInstance.init = function() {
    // This animation only works with horizontal and vertical orientation.
    if (this._config.orientation != 'horizontal' &&
        this._config.orientation != 'vertical') {
      throw new Error('Orientation must be either horizontal ' +
        'or vertical. It\'s now ' + this._config.orientation);
    }

    var listBounds = 0;

    // Set class 'active' to the visible list item if the pager is set to page
    // per list item.
    linearInstance._setActiveClass(linearInstance._config.activeIndex, true);

    // Set list container width
    this._config.listItems.each(function(index) {
      listBounds += tools.getOuterSize(
        linearInstance._config.orientation,
        jQuery(this)
      );
    });
    this._config.listItems.css('float', 'left');
    this._config.list.css('position', 'relative');
    this._config.list.css(
      tools.getWidthHeight(this._config.orientation), listBounds + 'px'
    );

    // Set list container height
    this._setListContainerHeight(
      this._config.listContainer,
      this._config.listItems
    );

    // set initial offset
    var offset = tools.getPosition(
      this._config.orientation,
      jQuery(this._config.listItems[this._config.activeIndex])
    );
    if (this._config.orientation == 'horizontal') {
      this._config.list.css({ 'left': '-' + offset + 'px' });
    } else {
      this._config.list.css({ 'top': '-' + offset + 'px' });
    }
  }

animation.page

In this piece of code it’s good to look at the animate method at the end of the code block. Normally you can reference to base variables and methods by using the this variable. But in some blocks of code, like the callback in the animate method, this refers to the function it resides in. In that case you have to replace thiswith the longer variable name of the animation object, which in this case is linearInstance.

It’s also worthy to note the values this._config.animationSpeed and this._config.animationEasing that are practically needed for any animation.

  linearInstance.page = function(oldIndex, newIndex, direction) {
    var offset;

    // Remove active class from old list item before animating
    if (oldIndex != newIndex) {
      linearInstance._setActiveClass(oldIndex, false);
    }

    // Stop all current animations
    this._config.list.stop(true, false);

    // Determine new offset for the list
    if (this._config.pagePerItem == true) {
      offset = tools.getPosition(
        this._config.orientation,
        jQuery(this._config.listItems[newIndex])
      );
    } else {
      var size = tools.getInnerSize(
        linearInstance._config.orientation,
        this._config.listContainer
      );
      offset = size * newIndex;
    }

    // Adjust the list offset to make sure that the list container is filled
    // with list items at all times. This might not be the case when
    // pagePerItem in the pager config is not set to true
    offset = this._checkMaxScroll(offset);

    // Set animate style properties
    var cssObj = {};
    var topLeft = tools.getTopLeft(this._config.orientation);
    cssObj[topLeft] = '-' + offset + 'px';

    // Run animation
    this._config.list.animate(
      cssObj,
      {
        duration: this._config.animationSpeed,
        easing: this._config.animationEasing,
        complete: function() {
          // Set active class on visible list item
          linearInstance._setActiveClass(newIndex, true);
        }
      }
    );
  }

Custom time indicators

Please read the previous section Custom transitions first if you didn’t.

Writing custom time indicators works pretty much the same way. You can find the animation objects in jquery.onopager.autopageAnimation.js. Just like in jquery.onopager.animation.js there’s a basic animation object onoPager.autopageAnimation._standard with base functionality van variables and some animation objects that do the real work and extend that basic object, like onoPager.autopageAnimation.timeline and onoPager.autopageAnimation.clock. You can select an animation type during the creation of a pager with the configuration. Here’s an example:

jQuery('ul').onoPager(
  {
    autoPage: {
      active: true,
      interval: 5000,
      autoPageAnimationType: 'timeline'
      }
  }
);

If you want to create your own animation object, you have to copy an existing object and rename it to, for example, this: onoPager.autopageAnimation.foo.

Below are the variables that are available to all autopage animation objects. Check out the documentation.

this._config = {
    listContainer: null, /* The element of the list */
    animationSpeed: 0, /* Time the animation takes */
    orientation: null, /* 'horizontal' or 'vertical' */
    root: null, /* The DOM element in which all animation must take place. */
    autoPageInterval: 0 /* The interval between autopaging */
  };

Below the interface of a autopage animation object. The method init will be called when the pager is being created, while start is called each time a paging is finished. You can do whatever you want in those methods. Anything goes.

  /**
   * @see onoPager.autopageAnimation._standard#init
   * @memberOf onoPager.autopageAnimation.timeline
   * @this
   */
  timelineInstance.init = function() {
    ...
  }

  /**
   * @see onoPager.autopageAnimation._standard#start
   * @memberOf onoPager.autopageAnimation.timeline
   * @this
   */
  timelineInstance.start = function() {
    ...
  }

Browser support

If your time indicator animation only works in new browsers because it -for example- requires Canvas support, you can add a little code below your custom animation code:

onoPager.autopageAnimation.clock.isSupportedByBrowser = function() {
  var canvas = document.createElement('canvas');
  if (canvas.getContext) {
    return true;
  } else {
    return false;
  }
}

This example checks browser support for Canvas. True means there’s Canvas support. If the browser fails this simple test, it will start the pager without time indication animation. If you want to create a fallback, you would have to check browser support before calling jQuery(’SELECTOR’).onoPager().