You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ga...@apache.org on 2015/03/05 09:50:57 UTC

[2/2] fauxton commit: updated refs/heads/master to 4cb0226

Document Pagination redone in React.js

This is the pagination and list of documents on the screen redone in
React.js. One change is that it no longer scrolls to the top on
paginate.

This fixes COUCHDB-2193 and COUCHDB-2572


Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/a5441229
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/a5441229
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/a5441229

Branch: refs/heads/master
Commit: a5441229acd6a805b16eb5b52abbf9917a3a02a9
Parents: e95eec5
Author: Garren Smith <ga...@gmail.com>
Authored: Wed Feb 18 16:47:06 2015 +0200
Committer: Garren Smith <ga...@gmail.com>
Committed: Thu Mar 5 10:50:21 2015 +0200

----------------------------------------------------------------------
 app/addons/documents/docs-list/actions.js       |  44 ----
 app/addons/documents/docs-list/actiontypes.js   |  18 --
 .../documents/docs-list/docs-list.react.jsx     | 119 ----------
 app/addons/documents/docs-list/stores.js        |  94 --------
 app/addons/documents/pagination/actions.js      |  78 +++++++
 app/addons/documents/pagination/actiontypes.js  |  23 ++
 .../documents/pagination/pagination.react.jsx   | 198 ++++++++++++++++
 app/addons/documents/pagination/stores.js       | 180 ++++++++++++++
 .../pagination/tests/pagination.actionsSpec.js  |  63 +++++
 .../tests/pagination.componentSpec.react.jsx    |  58 +++++
 .../pagination/tests/paginationStoreSpec.js     | 232 +++++++++++++++++++
 app/addons/documents/resources.js               |   4 +
 app/addons/documents/routes-documents.js        |  34 ++-
 app/addons/documents/routes-index-editor.js     |  12 +-
 app/addons/documents/shared-resources.js        |   3 +
 app/addons/documents/shared-routes.js           |  70 +-----
 .../documents/templates/all_docs_footer.html    |  20 --
 app/addons/documents/tests/doclistStoresSpec.js |  70 ------
 .../tests/docnumbers.componentSpec.react.jsx    |  58 -----
 .../documents/tests/docsnumbers-actionsSpec.js  |  38 ---
 app/addons/documents/tests/headerSpec.react.jsx |  12 +-
 .../tests/nightwatch/paginateAllDocs.js         |  87 +++++++
 .../documents/tests/nightwatch/paginateView.js  |  87 +++++++
 app/addons/documents/tests/viewsSpec.js         |  36 ---
 app/addons/documents/views.js                   |  63 +----
 app/addons/fauxton/components.js                | 152 ------------
 .../fauxton/templates/index_pagination.html     |  20 --
 app/addons/fauxton/tests/paginateSpec.js        |  88 -------
 assets/js/plugins/cloudant.pagingcollection.js  |   1 -
 29 files changed, 1060 insertions(+), 902 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/docs-list/actions.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/docs-list/actions.js b/app/addons/documents/docs-list/actions.js
deleted file mode 100644
index 5886cc6..0000000
--- a/app/addons/documents/docs-list/actions.js
+++ /dev/null
@@ -1,44 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-define([
-  'app',
-  'api',
-  'addons/documents/docs-list/actiontypes',
-  'addons/documents/docs-list/stores'
-],
-function (app, FauxtonAPI, ActionTypes, Stores) {
-
-  return {
-    collectionChanged: function (collection, pagination, perPage) {
-      FauxtonAPI.dispatch({
-        type: ActionTypes.COLLECTION_CHANGED,
-        collection: collection,
-        pagination: pagination,
-        perPage: perPage
-      });
-    },
-
-    updatePerPage: function (perPage) {
-      var pagination = Stores.allDocsListStore.getPagination();
-      pagination.updatePerPage(perPage);
-
-      FauxtonAPI.dispatch({
-        type: ActionTypes.PER_PAGE_CHANGE,
-        perPage: pagination.documentsLeftToFetch()
-      });
-
-      FauxtonAPI.triggerRouteEvent('perPageChange', pagination.documentsLeftToFetch());
-    }
-
-  };
-});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/docs-list/actiontypes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/docs-list/actiontypes.js b/app/addons/documents/docs-list/actiontypes.js
deleted file mode 100644
index dd5dfd5..0000000
--- a/app/addons/documents/docs-list/actiontypes.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-define([], function () {
-  return {
-    COLLECTION_CHANGED: 'COLLECTION_CHANGED',
-    PER_PAGE_CHANGE: 'PER_PAGE_CHANGE'
-  };
-});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/docs-list/docs-list.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/docs-list/docs-list.react.jsx b/app/addons/documents/docs-list/docs-list.react.jsx
deleted file mode 100644
index bdd81ee..0000000
--- a/app/addons/documents/docs-list/docs-list.react.jsx
+++ /dev/null
@@ -1,119 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-define([
-  "api",
-  "react",
-  'addons/documents/docs-list/stores',
-  'addons/documents/docs-list/actions'
-  ], function (FauxtonAPI, React, Stores, Actions) {
-    var allDocsListStore = Stores.allDocsListStore;
-
-    var PerPageSelector = React.createClass({
-
-      perPageChange: function (e) {
-        var perPage = parseInt(e.target.value, 10);
-        this.props.perPageChange(perPage);
-      },
-
-      render: function () {
-        return (
-          <div id="per-page">
-            <label htmlFor="select-per-page" className="drop-down inline">
-              Per page:
-              <select id="select-per-page" onChange={this.perPageChange} value={this.props.perPage.toString()} className="input-small">
-                <option value="5">5</option>
-                <option value="10">10</option>
-                <option value="20">20</option>
-                <option value="30">30</option>
-                <option value="50">50</option>
-                <option value="100">100</option>
-              </select>
-            </label>
-          </div>
-        );
-      }
-
-    });
-
-    var AllDocsNumber = React.createClass({
-
-      getStoreState: function () {
-        return {
-          totalRows: allDocsListStore.getTotalRows(),
-          pageStart: allDocsListStore.getPageStart(),
-          pageEnd: allDocsListStore.getPageEnd(),
-          updateSeq: allDocsListStore.getUpdateSeq(),
-          perPage: allDocsListStore.getPerPage()
-        };
-      },
-
-      getInitialState: function () {
-        return this.getStoreState();
-      },
-
-      componentDidMount: function() {
-        allDocsListStore.on('change', this.onChange, this);
-      },
-
-      componentWillUnmount: function() {
-        allDocsListStore.off('change', this.onChange);
-      },
-
-      onChange: function () {
-        this.setState(this.getStoreState());
-      },
-
-      pageNumber: function () {
-        if (this.state.totalRows === 0) {
-          return <p> Showing 0 documents. </p>;
-        }
-
-        return <p>Showing {this.state.pageStart} - {this.state.pageEnd}</p>;
-      },
-
-      updateSequence: function () {
-        if (this.state.updateSeq) {
-          return <span> Update Sequence: {this.state.updateSeq} </span>;
-        }
-      },
-
-      perPageChange: function (perPage) {
-        Actions.updatePerPage(perPage);
-      },
-
-      render: function () {
-        return (
-          <div>
-            <div className="index-indicator">
-              {this.pageNumber()}
-              {this.updateSequence()}
-            </div>
-            <PerPageSelector perPageChange={this.perPageChange} perPage={this.state.perPage} />
-          </div>
-        );
-      }
-
-    });
-
-    return {
-      AllDocsNumber: AllDocsNumber,
-      PerPageSelector: PerPageSelector,
-      renderAllDocsNumber: function (el) {
-        React.render(<AllDocsNumber/>, el);
-      },
-      removeAllDocsNumber: function (el) {
-        React.unmountComponentAtNode(el);
-      }
-    };
-
-  });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/docs-list/stores.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/docs-list/stores.js b/app/addons/documents/docs-list/stores.js
deleted file mode 100644
index bc7b3f2..0000000
--- a/app/addons/documents/docs-list/stores.js
+++ /dev/null
@@ -1,94 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-define([
-  'api',
-  'addons/documents/docs-list/actiontypes'
-],function (FauxtonAPI, ActionTypes) {
-
-  var Stores = {};
-
-  Stores.AllDocsListStore = FauxtonAPI.Store.extend({
-    initialize: function () {
-      this._totalRows = 0;
-      this._updateSeq = false;
-      this._pageStart = 0;
-      this._pageEnd = 20;
-      this._newView = false;
-      this._perPage = FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE;
-    },
-
-    collectionChanged: function (collection, pagination, perPage) {
-     if (!this._newView) {
-       this._totalRows = collection.length;
-       this._updateSeq = collection.updateSeq();
-     }
-
-     this._pageStart = pagination.pageStart();
-     this._pageEnd =  pagination.pageEnd();
-     this._perPage = perPage;
-     this._pagination = pagination;
-    },
-
-    getPagination: function () {
-      return this._pagination;
-    },
-
-    getPerPage: function () {
-      return this._perPage;
-    },
-
-    setPerPage: function (perPage) {
-      this._perPage = perPage;
-    },
-
-    getTotalRows: function () {
-      return this._totalRows;
-    },
-
-    getPageStart: function () {
-      return this._pageStart;
-    },
-
-    getPageEnd: function () {
-      return this._pageEnd;
-    },
-
-    getUpdateSeq: function () {
-      return this._updateSeq;
-    },
-
-    dispatch: function (action) {
-      switch (action.type) {
-        case ActionTypes.COLLECTION_CHANGED:
-          this.collectionChanged(action.collection, action.pagination, action.perPage);
-          this.triggerChange();
-          break;
-        case ActionTypes.PER_PAGE_CHANGE:
-          this.setPerPage(action.perPage);
-          this.triggerChange();
-          break;
-        default:
-          return;
-      }
-
-    }
-
-  });
-
-  Stores.allDocsListStore = new Stores.AllDocsListStore();
-
-  Stores.AllDocsListStore.dispatchToken = FauxtonAPI.dispatcher.register(Stores.allDocsListStore.dispatch);
-
-  return Stores;
-
-});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/pagination/actions.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/pagination/actions.js b/app/addons/documents/pagination/actions.js
new file mode 100644
index 0000000..c69087a
--- /dev/null
+++ b/app/addons/documents/pagination/actions.js
@@ -0,0 +1,78 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+define([
+  'app',
+  'api',
+  'addons/documents/pagination/actiontypes',
+  'addons/documents/pagination/stores'
+],
+function (app, FauxtonAPI, ActionTypes, Stores) {
+
+  var store = Stores.indexPaginationStore;
+
+  return {
+    updatePerPage: function (perPage) {
+      FauxtonAPI.dispatch({
+        type: ActionTypes.PER_PAGE_CHANGE,
+        perPage: perPage
+      });
+
+      FauxtonAPI.triggerRouteEvent('perPageChange', store.documentsLeftToFetch());
+    },
+
+    newPagination: function (collection) {
+      FauxtonAPI.dispatch({
+        type: ActionTypes.NEW_PAGINATION,
+        collection: collection
+      });
+    },
+
+    setDocumentLimit: function (docLimit) {
+      FauxtonAPI.dispatch({
+        type: ActionTypes.SET_PAGINATION_DOCUMENT_LIMIT,
+        docLimit: docLimit
+      });
+    },
+
+    collectionReset: function () {
+      FauxtonAPI.dispatch({
+        type: ActionTypes.PAGINATION_COLLECTION_RESET,
+      });
+    },
+
+    paginateNext: function () {
+      FauxtonAPI.dispatch({
+        type: ActionTypes.PAGINATE_NEXT,
+      });
+
+      FauxtonAPI.triggerRouteEvent('paginate', {
+       direction: 'next',
+       perPage: store.documentsLeftToFetch(),
+       currentPage: store.getCurrentPage()
+      });
+    },
+
+    paginatePrevious: function () {
+      FauxtonAPI.dispatch({
+        type: ActionTypes.PAGINATE_PREVIOUS,
+      });
+
+      FauxtonAPI.triggerRouteEvent('paginate', {
+       direction: 'previous',
+       perPage: store.getPerPage(),
+       currentPage: store.getCurrentPage()
+      });
+    },
+
+  };
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/pagination/actiontypes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/pagination/actiontypes.js b/app/addons/documents/pagination/actiontypes.js
new file mode 100644
index 0000000..fe2fe93
--- /dev/null
+++ b/app/addons/documents/pagination/actiontypes.js
@@ -0,0 +1,23 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+define([], function () {
+  return {
+    COLLECTION_CHANGED: 'COLLECTION_CHANGED',
+    PER_PAGE_CHANGE: 'PER_PAGE_CHANGE',
+    NEW_PAGINATION: 'NEW_PAGINATION',
+    COLLECTION_RESET: 'PAGINATION_COLLECTION_RESET',
+    PAGINATE_NEXT: 'PAGINATE_NEXT',
+    PAGINATE_PREVIOUS: 'PAGINATE_PREVIOUS',
+    SET_PAGINATION_DOCUMENT_LIMIT: 'SET_PAGINATION_DOCUMENT_LIMIT'
+  };
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/pagination/pagination.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/pagination/pagination.react.jsx b/app/addons/documents/pagination/pagination.react.jsx
new file mode 100644
index 0000000..75ea0a3
--- /dev/null
+++ b/app/addons/documents/pagination/pagination.react.jsx
@@ -0,0 +1,198 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+define([
+  "api",
+  "react",
+  'addons/documents/pagination/stores',
+  'addons/documents/pagination/actions',
+  ], function (FauxtonAPI, React, Stores, Actions) {
+    var indexPaginationStore = Stores.indexPaginationStore;
+
+    var IndexPaginationController = React.createClass({
+
+      getStoreState: function () {
+        return {
+          canShowPrevious: indexPaginationStore.canShowPrevious(),
+          canShowNext: indexPaginationStore.canShowNext(),
+        };
+      },
+
+      getInitialState: function () {
+        return this.getStoreState();
+      },
+
+      componentDidMount: function() {
+        indexPaginationStore.on('change', this.onChange, this);
+      },
+
+      componentWillUnmount: function() {
+        indexPaginationStore.off('change', this.onChange);
+      },
+
+      onChange: function () {
+        this.setState(this.getStoreState());
+      },
+
+      nextClicked: function (event) {
+        event.preventDefault();
+        event.stopPropagation();
+        if (!this.state.canShowNext) { return; }
+        Actions.paginateNext();
+      },
+
+      previousClicked: function (event) {
+        event.preventDefault();
+        event.stopPropagation();
+        if (!this.state.canShowPrevious) { return; }
+        Actions.paginatePrevious();
+      },
+
+      render: function () {
+        var canShowPreviousClassName = '';
+        var canShowNextClassName = '';
+
+        if (!this.state.canShowPrevious) {
+          canShowPreviousClassName = 'disabled';
+        }
+
+        if (!this.state.canShowNext) {
+          canShowNextClassName = 'disabled';
+        }
+        return (
+          <ul className="pagination">
+            <li className={canShowPreviousClassName} >
+              <a id="previous" onClick={this.previousClicked} className="icon fonticon-left-open" href="#" data-bypass="true"></a>
+            </li>
+            <li className={canShowNextClassName} >
+              <a id="next" onClick={this.nextClicked} className="icon fonticon-right-open" href="#" data-bypass="true"></a>
+            </li>
+        </ul>
+        );
+      }
+
+    });
+
+    var PerPageSelector = React.createClass({
+
+      perPageChange: function (e) {
+        var perPage = parseInt(e.target.value, 10);
+        this.props.perPageChange(perPage);
+      },
+
+      render: function () {
+        return (
+          <div id="per-page">
+            <label htmlFor="select-per-page" className="drop-down inline">
+              Per page:
+              <select id="select-per-page" onChange={this.perPageChange} value={this.props.perPage.toString()} className="input-small">
+                <option value="5">5</option>
+                <option value="10">10</option>
+                <option value="20">20</option>
+                <option value="30">30</option>
+                <option value="50">50</option>
+                <option value="100">100</option>
+              </select>
+            </label>
+          </div>
+        );
+      }
+
+    });
+
+    var AllDocsNumberController = React.createClass({
+
+      getStoreState: function () {
+        return {
+          totalRows: indexPaginationStore.getTotalRows(),
+          pageStart: indexPaginationStore.getPageStart(),
+          pageEnd: indexPaginationStore.getPageEnd(),
+          updateSeq: indexPaginationStore.getUpdateSeq(),
+          perPage: indexPaginationStore.getPerPage()
+        };
+      },
+
+      getInitialState: function () {
+        return this.getStoreState();
+      },
+
+      componentDidMount: function() {
+        indexPaginationStore.on('change', this.onChange, this);
+      },
+
+      componentWillUnmount: function() {
+        indexPaginationStore.off('change', this.onChange);
+      },
+
+      onChange: function () {
+        this.setState(this.getStoreState());
+      },
+
+      pageNumber: function () {
+        if (this.state.totalRows === 0) {
+          return <p> Showing 0 documents. </p>;
+        }
+
+        return <p>Showing {this.state.pageStart} - {this.state.pageEnd}</p>;
+      },
+
+      updateSequence: function () {
+        if (this.state.updateSeq) {
+          return <span> Update Sequence: {this.state.updateSeq} </span>;
+        }
+      },
+
+      perPageChange: function (perPage) {
+        Actions.updatePerPage(perPage);
+      },
+
+      render: function () {
+        return (
+          <div>
+            <div className="index-indicator">
+              {this.pageNumber()}
+              {this.updateSequence()}
+            </div>
+            <PerPageSelector perPageChange={this.perPageChange} perPage={this.state.perPage} />
+          </div>
+        );
+      }
+
+    });
+
+    var Footer = React.createClass({
+      render: function () {
+        return (
+          <footer className="index-pagination pagination-footer">
+            <div id="documents-pagination">
+              <IndexPaginationController />
+            </div>
+            <div id="item-numbers">
+              <AllDocsNumberController />
+            </div>
+          </footer>
+        );
+      }
+    });
+
+    return {
+      AllDocsNumber: AllDocsNumberController,
+      PerPageSelector: PerPageSelector,
+      renderFooter: function (el) {
+        React.render(<Footer/>, el);
+      },
+      removeFooter: function (el) {
+        React.unmountComponentAtNode(el);
+      }
+    };
+
+  });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/pagination/stores.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/pagination/stores.js b/app/addons/documents/pagination/stores.js
new file mode 100644
index 0000000..d37c66b
--- /dev/null
+++ b/app/addons/documents/pagination/stores.js
@@ -0,0 +1,180 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+define([
+  'app',
+  'api',
+  'addons/documents/pagination/actiontypes'
+],function (app, FauxtonAPI, ActionTypes) {
+
+  var Stores = {};
+  var maxDocLimit = 10000;
+
+  Stores.IndexPaginationStore = FauxtonAPI.Store.extend({
+    initialize: function () {
+      this.reset();
+    },
+
+    reset: function () {
+      this._pageStart = 1;
+      this._enabled = true;
+      this._currentPage = 1;
+      this._pageStart = 1;
+      this._newView = false;
+      this._docLimit = _.isUndefined(this._docLimit) ? maxDocLimit : this._docLimit;
+      this.initPerPage();
+    },
+
+    setDocumentLimit: function (docLimit) {
+      if (docLimit) {
+        this._docLimit = docLimit;
+      } else {
+        this._docLimit = maxDocLimit;
+      }
+
+      this.initPerPage();
+    },
+
+    newPagination: function (collection) {
+      this._collection = collection;
+      this.reset();
+    },
+
+    canShowPrevious: function () {
+      if (!this._enabled) { return false; }
+      return this._collection.hasPrevious();
+    },
+
+    canShowNext: function () {
+      if (!this._enabled) { return this._enabled; }
+
+      if ((this._pageStart + this._perPage) >= this._docLimit) {
+        return false;
+      }
+
+      return this._collection.hasNext();
+    },
+
+    paginateNext: function () {
+      this._currentPage += 1;
+      this._pageStart += this.getPerPage();
+    },
+
+    paginatePrevious: function () {
+      this._currentPage -= 1;
+
+      this._pageStart = this._pageStart - this.getPerPage();
+      if (this._pageStart < 1) {
+        this._pageStart = 1;
+      }
+    },
+
+    getCurrentPage: function () {
+      return this._currentPage;
+    },
+
+    totalDocsViewed: function () {
+      return this._perPage * this._currentPage;
+    },
+
+    documentsLeftToFetch: function () {
+      var documentsLeftToFetch = this._docLimit - this.totalDocsViewed();
+
+      if (documentsLeftToFetch < this.getPerPage() ) {
+        return documentsLeftToFetch;
+      }
+
+      return this._perPage;
+    },
+
+    getPerPage: function () {
+      return this._perPage;
+    },
+
+    initPerPage: function () {
+      var perPage = FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE;
+
+      if (window.localStorage) {
+        var storedPerPage = app.utils.localStorageGet('fauxton:perpage');
+
+        if (storedPerPage) {
+          perPage = parseInt(storedPerPage, 10);
+        }
+      }
+
+      if (this._docLimit < perPage) {
+        perPage = this._docLimit;
+      }
+
+      this.setPerPage(perPage);
+    },
+
+    setPerPage: function (perPage) {
+      this._perPage = perPage;
+      app.utils.localStorageSet('fauxton:perpage', perPage);
+    },
+
+    getTotalRows: function () {
+      return this._collection.length;
+    },
+
+    getPageStart: function () {
+      return this._pageStart;
+    },
+
+    getPageEnd: function () {
+      return this._pageStart + this._collection.length - 1;
+    },
+
+    getUpdateSeq: function () {
+      return this._collection.updateSeq();
+    },
+
+    dispatch: function (action) {
+
+      switch (action.type) {
+        case ActionTypes.NEW_PAGINATION:
+          this.newPagination(action.collection);
+          this.triggerChange();
+          break;
+        case ActionTypes.SET_PAGINATION_DOCUMENT_LIMIT:
+          this.setDocumentLimit(action.docLimit);
+          this.triggerChange();
+          break;
+        case ActionTypes.PAGINATION_COLLECTION_RESET:
+          this.triggerChange();
+          break;
+        case ActionTypes.PAGINATE_NEXT:
+          this.paginateNext();
+          this.triggerChange();
+          break;
+        case ActionTypes.PAGINATE_PREVIOUS:
+          this.paginatePrevious();
+          this.triggerChange();
+          break;
+        case ActionTypes.PER_PAGE_CHANGE:
+          this.reset();
+          this.setPerPage(action.perPage);
+          this.triggerChange();
+          break;
+        default:
+          return;
+      }
+    }
+  });
+
+  Stores.indexPaginationStore = new Stores.IndexPaginationStore();
+  Stores.indexPaginationStore.dispatchToken = FauxtonAPI.dispatcher.register(Stores.indexPaginationStore.dispatch);
+
+  return Stores;
+
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/pagination/tests/pagination.actionsSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/pagination/tests/pagination.actionsSpec.js b/app/addons/documents/pagination/tests/pagination.actionsSpec.js
new file mode 100644
index 0000000..e01a23d
--- /dev/null
+++ b/app/addons/documents/pagination/tests/pagination.actionsSpec.js
@@ -0,0 +1,63 @@
+define([
+  'api',
+  'addons/documents/pagination/actions',
+  'addons/documents/pagination/stores',
+  'testUtils',
+], function (FauxtonAPI, Actions, Stores, testUtils) {
+  var assert = testUtils.assert;
+
+  FauxtonAPI.router = new FauxtonAPI.Router([]);
+
+  describe('Pagination Actions', function () {
+
+    afterEach(function () {
+      Stores.indexPaginationStore.documentsLeftToFetch.restore && Stores.indexPaginationStore.documentsLeftToFetch.restore();
+      Stores.indexPaginationStore.getCurrentPage.restore && Stores.indexPaginationStore.getCurrentPage.restore();
+      Stores.indexPaginationStore.getPerPage.restore && Stores.indexPaginationStore.getPerPage.restore();
+      FauxtonAPI.triggerRouteEvent.restore();
+    });
+
+    describe('updatePerPage', function () {
+
+      it('triggers routeEvent', function () {
+        var stub = sinon.stub(Stores.indexPaginationStore, 'documentsLeftToFetch');
+        stub.returns(30);
+        var spy = sinon.spy(FauxtonAPI, 'triggerRouteEvent');
+        Actions.updatePerPage(30);
+
+        assert.ok(spy.calledWith('perPageChange', 30));
+      });
+    });
+
+    describe('paginateNext', function () {
+
+      it('triggers routeEvent', function () {
+        var spyEvent = sinon.spy(FauxtonAPI, 'triggerRouteEvent');
+        var spyDocuments = sinon.spy(Stores.indexPaginationStore, 'documentsLeftToFetch');
+        var spyPage = sinon.spy(Stores.indexPaginationStore, 'getCurrentPage');
+        Actions.paginateNext();
+
+        assert.ok(spyEvent.calledOnce);
+        assert.ok(spyDocuments.calledOnce);
+        assert.ok(spyPage.calledOnce);
+      });
+
+    });
+
+    describe('paginatePrevious', function () {
+
+      it('triggers routeEvent', function () {
+        var spyEvent = sinon.spy(FauxtonAPI, 'triggerRouteEvent');
+        var spyPerPage = sinon.spy(Stores.indexPaginationStore, 'getPerPage');
+        var spyPage = sinon.spy(Stores.indexPaginationStore, 'getCurrentPage');
+        Actions.paginatePrevious();
+
+        assert.ok(spyEvent.calledOnce);
+        assert.ok(spyPerPage.called);
+        assert.ok(spyPage.calledOnce);
+      });
+
+    });
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/pagination/tests/pagination.componentSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/pagination/tests/pagination.componentSpec.react.jsx b/app/addons/documents/pagination/tests/pagination.componentSpec.react.jsx
new file mode 100644
index 0000000..1b4f3c5
--- /dev/null
+++ b/app/addons/documents/pagination/tests/pagination.componentSpec.react.jsx
@@ -0,0 +1,58 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+define([
+  'api',
+  'addons/documents/pagination/pagination.react',
+  'testUtils',
+  "react"
+], function (FauxtonAPI, Views, utils, React) {
+  FauxtonAPI.router = new FauxtonAPI.Router([]);
+
+  var assert = utils.assert;
+  var TestUtils = React.addons.TestUtils;
+
+  describe('All Docs Number', function () {
+
+    describe('PerPageSelector', function () {
+      var container, selectorEl, perPageChange;
+
+      beforeEach(function () {
+        perPageChange = sinon.spy();
+        container = document.createElement('div');
+        selectorEl = TestUtils.renderIntoDocument(
+          <Views.PerPageSelector
+            perPageChange={perPageChange}
+            perPage={10}
+          />,
+          container
+        );
+      });
+
+      afterEach(function () {
+        React.unmountComponentAtNode(container);
+      });
+
+      it('on new select calls callback with new page size', function () {
+        var selectEl = $(selectorEl.getDOMNode()).find('#select-per-page')[0];
+        var perPage = 5;
+        TestUtils.Simulate.change(selectEl, {
+          target: {
+            value: perPage
+          }
+        });
+
+        assert.ok(perPageChange.calledWith(perPage));
+      });
+
+    });
+  });
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/pagination/tests/paginationStoreSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/pagination/tests/paginationStoreSpec.js b/app/addons/documents/pagination/tests/paginationStoreSpec.js
new file mode 100644
index 0000000..0c45c88
--- /dev/null
+++ b/app/addons/documents/pagination/tests/paginationStoreSpec.js
@@ -0,0 +1,232 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+define([
+  'api',
+  'addons/documents/pagination/stores',
+  'addons/documents/pagination/actiontypes',
+  'testUtils'
+], function (FauxtonAPI, Stores, ActionTypes, testUtils) {
+  var assert = testUtils.assert;
+  var dispatchToken;
+  var store;
+
+  describe('Index Pagination Store', function () {
+
+    beforeEach(function () {
+      store = new Stores.IndexPaginationStore();
+      dispatchToken = FauxtonAPI.dispatcher.register(store.dispatch);
+    });
+
+    afterEach(function () {
+      FauxtonAPI.dispatcher.unregister(dispatchToken);
+    });
+
+    describe('#collectionChanged', function () {
+      var collection;
+      beforeEach(function () {
+        collection = new Backbone.Collection([{id:1}, {id: 2}]);
+        collection.updateSeq = function () { return 'updateSeq';};
+        store.reset();
+      });
+
+      it('sets total rows correctly', function () {
+        store.newPagination(collection);
+        assert.equal(store.getTotalRows(), 2);
+      });
+
+      it('sets updateSeq', function () {
+        store.newPagination(collection);
+        assert.equal(store.getUpdateSeq(), 'updateSeq');
+      });
+
+    });
+
+    describe('canShowPrevious', function () {
+      it('cannot show previous if disabled', function () {
+        store._enabled = false;
+        assert.notOk(store.canShowPrevious());
+      });
+
+      it('can show if collection can show', function () {
+        store._enabled = true;
+        store._collection = new Backbone.Collection();
+        store._collection.hasPrevious = function () { return true;};
+        assert.ok(store.canShowPrevious());
+      });
+
+    });
+
+    describe('canShowNext', function () {
+      it('cannot show next if disabled', function () {
+        store._enabled = false;
+        assert.notOk(store.canShowNext());
+      });
+
+      it('cannot show if pageStart and perPage greater than docLimit', function () {
+        store._enabled = true;
+        store._docLimit = 10;
+        store._perPage = 20;
+
+        assert.notOk(store.canShowNext());
+      });
+
+      it('can show if collection can show', function () {
+        store._enabled = true;
+        store._docLimit = 100000;
+        store.reset();
+        store._collection = new Backbone.Collection();
+        store._collection.hasNext = function () { return true;};
+        assert.ok(store.canShowNext());
+      });
+    });
+
+    describe('paginateNext', function () {
+      beforeEach(function () {
+        store.setPerPage(20);
+      });
+
+      it('should increment page number', function () {
+
+        store.reset();
+        store.paginateNext();
+
+        assert.equal(store.getCurrentPage(), 2);
+      });
+
+      it('should increment page start', function () {
+
+        store.reset();
+        store.paginateNext();
+
+        assert.equal(store.getPageStart(), 21);
+      });
+
+      it('should set correct page end', function () {
+        store._collection = new Backbone.Collection();
+        store._collection.length = 20;
+        store.reset();
+        store.paginateNext();
+
+        assert.equal(store.getPageEnd(), 40);
+      });
+    });
+
+    describe('paginatePrevious', function () {
+      beforeEach(function () {
+        store.reset();
+      });
+
+      it('should decrement page number', function () {
+        store.paginateNext();
+        store.paginatePrevious();
+
+        assert.equal(store.getCurrentPage(), 1);
+      });
+
+      it('should decrement page start', function () {
+        store.paginateNext();
+        store.paginatePrevious();
+
+        assert.equal(store.getPageStart(), 1);
+      });
+
+      it('should decrement page end', function () {
+        store._collection = new Backbone.Collection();
+        store._collection.length = 20;
+        store.paginateNext();
+        store.paginatePrevious();
+
+        assert.equal(store.getPageEnd(), 20);
+      });
+
+    });
+
+    describe('totalDocsViewed', function () {
+      beforeEach(function () {
+        store.reset();
+      });
+
+      it('returns correct count for page 1 and 20 docs per page', function () {
+        assert.equal(store.totalDocsViewed(), 20);
+      });
+
+      it('returns correct count for page 3 and 10 docs per page', function () {
+        store._perPage = 10;
+        store._currentPage = 3;
+
+        assert.equal(store.totalDocsViewed(), 30);
+      });
+    });
+
+    describe('documentsLeftToFetch', function () {
+      beforeEach(function () {
+        store.reset();
+      });
+
+      it('returns 20 documents left', function () {
+        assert.equal(store.documentsLeftToFetch(), 20);
+      });
+
+      it('returns less if close to limit', function () {
+        store._docLimit = 35;
+        store._perPage = 10;
+        store._currentPage = 3;
+        assert.equal(store.documentsLeftToFetch(), 5);
+      });
+
+    });
+
+    describe('#initPerPage', function () {
+
+      it('uses default if no local storage set', function () {
+        window.localStorage.removeItem('fauxton:perpage');
+        store.initPerPage();
+        assert.equal(store.getPerPage(), 20);
+      });
+
+      it('uses localstorage when available', function (){
+        window.localStorage.setItem('fauxton:perpage', 44);
+        store.initPerPage();
+        assert.equal(store.getPerPage(), 44);
+      });
+
+      it('uses doc limit when its less than perPage', function (){
+        window.localStorage.setItem('fauxton:perpage', 100);
+        store._docLimit = 6;
+        store.initPerPage();
+        assert.equal(store.getPerPage(), 6);
+      });
+
+    });
+
+    describe('#setDocumentLimit', function () {
+
+      it('sets document if exists', function () {
+        store.setDocumentLimit(10);
+        assert.equal(store._docLimit, 10);
+      });
+
+      it('sets perPage to doclimit if doclimit less than perPage', function () {
+        store.setPerPage(20);
+        store.setDocumentLimit(1);
+        assert.equal(store._docLimit, 1);
+      });
+
+      it('sets doclimit to 10000 if NaN', function () {
+        store.setDocumentLimit(NaN);
+        assert.equal(store._docLimit, 10000);
+      });
+
+    });
+  });
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/resources.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/resources.js b/app/addons/documents/resources.js
index a8fb3d3..d2e460d 100644
--- a/app/addons/documents/resources.js
+++ b/app/addons/documents/resources.js
@@ -227,6 +227,10 @@ function(app, FauxtonAPI, Documents, PagingCollection) {
     },
 
     updateSeq: function() {
+      if (!this.viewMeta) {
+        return false;
+      }
+
       return this.viewMeta.update_seq || false;
     },
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/routes-documents.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes-documents.js b/app/addons/documents/routes-documents.js
index 79a3c70..5edafc8 100644
--- a/app/addons/documents/routes-documents.js
+++ b/app/addons/documents/routes-documents.js
@@ -16,17 +16,20 @@ define([
 
   // Modules
   'addons/documents/shared-routes',
-  "addons/documents/views",
-  "addons/documents/views-changes",
-  "addons/documents/views-index",
-  "addons/documents/views-doceditor",
-
-  "addons/databases/base",
-  "addons/documents/resources",
-  "addons/fauxton/components"
+  'addons/documents/views',
+  'addons/documents/views-changes',
+  'addons/documents/views-index',
+  'addons/documents/views-doceditor',
+
+  'addons/databases/base',
+  'addons/documents/resources',
+  'addons/fauxton/components',
+  'addons/documents/pagination/actions',
+  'addons/documents/pagination/stores'
 ],
 
-function(app, FauxtonAPI, BaseRoute, Documents, Changes, Index, DocEditor, Databases, Resources, Components) {
+function(app, FauxtonAPI, BaseRoute, Documents, Changes, Index, DocEditor,
+        Databases, Resources, Components, PaginationActions, PaginationStores) {
 
 
   var DocumentsRouteObject = BaseRoute.extend({
@@ -154,28 +157,19 @@ function(app, FauxtonAPI, BaseRoute, Documents, Changes, Index, DocEditor, Datab
       this.viewEditor && this.viewEditor.remove();
       this.headerView && this.headerView.remove();
 
-      this.database.allDocs.paging.pageSize = this.getDocPerPageLimit(urlParams, parseInt(docParams.limit, 10));
 
       if (!docParams) {
         docParams = {};
       }
-      this.perPageDefault = docParams.limit || FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE;
 
-      this.pagination = new Components.IndexPagination({
-        collection: collection,
-        scrollToSelector: '.scrollable',
-        docLimit: urlParams.limit,
-        perPage: this.perPageDefault
-      });
-      this.setView('#documents-pagination', this.pagination);
+      PaginationActions.newPagination(collection);
+      this.database.allDocs.paging.pageSize = PaginationStores.indexPaginationStore.getPerPage();
 
       // documentsView will populate the collection
       this.documentsView = this.setView("#dashboard-lower-content", new Documents.Views.AllDocsList({
-        pagination: this.pagination,
         database: this.database,
         collection: collection,
         docParams: docParams,
-        perPageDefault: this.perPageDefault,
         bulkDeleteDocsCollection: new Documents.BulkDeleteDocCollection([], {databaseId: this.database.get('id')})
       }));
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/routes-index-editor.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes-index-editor.js b/app/addons/documents/routes-index-editor.js
index 5855e1e..af51646 100644
--- a/app/addons/documents/routes-index-editor.js
+++ b/app/addons/documents/routes-index-editor.js
@@ -20,11 +20,14 @@ define([
   'addons/documents/views',
   'addons/documents/views-index',
   'addons/databases/base',
-  'addons/fauxton/components'
+  'addons/fauxton/components',
+  'addons/documents/pagination/actions',
+  'addons/documents/pagination/stores'
 
 ],
 
-function (app, FauxtonAPI, Helpers, BaseRoute, Documents, Index, Databases, Components) {
+function (app, FauxtonAPI, Helpers, BaseRoute, Documents, Index,
+        Databases, Components, PaginationActions, PaginationStores) {
 
 
   var IndexEditorAndResults = BaseRoute.extend({
@@ -71,7 +74,6 @@ function (app, FauxtonAPI, Helpers, BaseRoute, Documents, Index, Databases, Comp
         database: this.database
       }));
 
-
       this.breadcrumbs = this.setView('#breadcrumbs', new Components.Breadcrumbs({
         toggleDisabled: true,
         crumbs: [
@@ -90,10 +92,12 @@ function (app, FauxtonAPI, Helpers, BaseRoute, Documents, Index, Databases, Comp
         view: viewName,
         params: docParams,
         paging: {
-          pageSize: this.getDocPerPageLimit(urlParams, parseInt(docParams.limit, 10))
+          pageSize: PaginationStores.indexPaginationStore.getPerPage()
         }
       });
 
+      PaginationActions.newPagination(this.indexedDocs);
+
       this.viewEditor = this.setView('#left-content', new Index.ViewEditorReact({
         viewName: viewName,
         newView: false,

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/shared-resources.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/shared-resources.js b/app/addons/documents/shared-resources.js
index a25532b..130bab6 100644
--- a/app/addons/documents/shared-resources.js
+++ b/app/addons/documents/shared-resources.js
@@ -277,6 +277,9 @@ define([
     },
 
     updateSeq: function() {
+      if (!this.viewMeta) {
+          return false;
+      }
       return this.viewMeta.update_seq || false;
     },
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/shared-routes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/shared-routes.js b/app/addons/documents/shared-routes.js
index 8167d8f..53ef50d 100644
--- a/app/addons/documents/shared-routes.js
+++ b/app/addons/documents/shared-routes.js
@@ -3,8 +3,10 @@ define([
   'api',
   'addons/documents/shared-resources',
   'addons/databases/base',
-  'addons/fauxton/components'
-], function (app, FauxtonAPI, Documents, Databases, Components) {
+  'addons/fauxton/components',
+  'addons/documents/pagination/actions',
+  'addons/documents/pagination/stores'
+], function (app, FauxtonAPI, Documents, Databases, Components, PaginationActions, PaginationStores ) {
 
 
   // The Documents section is built up a lot of different route object which share code. This contains
@@ -83,36 +85,17 @@ define([
       ];
     },
 
-    // document-list
-
-    setDocPerPageLimit: function (perPage) {
-      app.utils.localStorageSet('fauxton:perpage', perPage);
-    },
-
     createViewDocumentsView: function (options) {
       if (!options.docParams) {
         options.docParams = {};
       }
 
-      this.perPageDefault = options.docParams.limit || FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE;
-
-      this.pagination = new Components.IndexPagination({
-        collection: options.indexedDocs,
-        scrollToSelector: '.scrollable',
-        docLimit: options.urlParams.limit,
-        perPage: this.perPageDefault
-      });
-      this.setView('#documents-pagination', this.pagination);
-
       return this.setView("#dashboard-lower-content", new Documents.Views.AllDocsList({
-        pagination: this.pagination,
-        allDocsNumber: this.allDocsNumber,
         database: options.database,
         collection: options.indexedDocs,
         viewList: true,
         ddocInfo: this.ddocInfo(options.designDoc, options.designDocs, options.view),
-        docParams: options.docParams,
-        perPageDefault: this.perPageDefault,
+        docParams: options.docParams
       }));
     },
 
@@ -124,32 +107,13 @@ define([
       };
     },
 
-    getDocPerPageLimit: function (urlParams, perPage) {
-      var storedPerPage = perPage;
-
-      if (window.localStorage) {
-        storedPerPage = app.utils.localStorageGet('fauxton:perpage');
-
-        if (!storedPerPage) {
-          this.setDocPerPageLimit(perPage);
-          storedPerPage = perPage;
-        } else {
-          storedPerPage = parseInt(storedPerPage, 10);
-        }
-      }
-
-      if (!urlParams.limit || urlParams.limit > storedPerPage) {
-        return parseInt(storedPerPage, 10);
-      } else {
-        return parseInt(urlParams.limit, 10);
-      }
-    },
-
     createParams: function (options) {
       var urlParams = app.getParams(options),
-          params = Documents.QueryParams.parse(urlParams),
-          limit = this.getDocPerPageLimit(params, FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE);
+          params = Documents.QueryParams.parse(urlParams);
 
+      PaginationActions.setDocumentLimit(parseInt(urlParams.limit, 10));
+
+      var limit = PaginationStores.indexPaginationStore.getPerPage();
       return {
         urlParams: urlParams,
         docParams: _.extend(params, {limit: limit})
@@ -162,15 +126,9 @@ define([
           urlParams = params.urlParams,
           docParams = params.docParams,
           ddoc = event.ddoc,
-          defaultPageSize,
-          isLazyInit,
-          pageSize,
+          pageSize = PaginationStores.indexPaginationStore.getPerPage(),
           collection;
 
-      isLazyInit = _.isUndefined(this.documentsView) || _.isUndefined(this.documentsView.allDocsNumber);
-      defaultPageSize = isLazyInit ? FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE : this.documentsView.perPage();
-      docParams.limit = pageSize = this.getDocPerPageLimit(urlParams, defaultPageSize);
-
       if (event.allDocs) {
         this.eventAllDocs = true; // this is horrible. But I cannot get the trigger not to fire the route!
         this.database.buildAllDocs(docParams);
@@ -200,21 +158,13 @@ define([
         }
       }
 
-      this.documentsView.setParams(docParams, urlParams);
-
       // this will lazily initialize all sub-views and render them
       this.documentsView.forceRender();
     },
 
     perPageChange: function (perPage) {
-      // We need to restore the collection parameters to the defaults (1st page)
-      // and update the page size
-      this.perPage = perPage;
-
       this.documentsView.forceRender();
       this.documentsView.collection.pageSizeReset(perPage, {fetch: false});
-
-      this.setDocPerPageLimit(perPage);
     },
 
     paginate: function (options) {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/templates/all_docs_footer.html
----------------------------------------------------------------------
diff --git a/app/addons/documents/templates/all_docs_footer.html b/app/addons/documents/templates/all_docs_footer.html
deleted file mode 100644
index 7cd112d..0000000
--- a/app/addons/documents/templates/all_docs_footer.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<%
-/*
-Licensed under the Apache License, Version 2.0 (the "License"); you may not
-use this file except in compliance with the License. You may obtain a copy of
-the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-License for the specific language governing permissions and limitations under
-the License.
-*/
-%>
-
-<footer class="index-pagination pagination-footer">
-  <div id="documents-pagination"></div>
-  <div id="item-numbers"></div>
-</footer>

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/tests/doclistStoresSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/doclistStoresSpec.js b/app/addons/documents/tests/doclistStoresSpec.js
deleted file mode 100644
index 6af1e00..0000000
--- a/app/addons/documents/tests/doclistStoresSpec.js
+++ /dev/null
@@ -1,70 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-define([
-  'api',
-  'addons/documents/docs-list/stores',
-  'addons/documents/docs-list/actiontypes',
-  'testUtils'
-], function (FauxtonAPI, Stores, ActionTypes, testUtils) {
-  var assert = testUtils.assert;
-  var store;
-  var dispatchToken;
-
-
-  describe('AllDocsListStore', function () {
-
-    beforeEach(function () {
-      store = new Stores.AllDocsListStore();
-      dispatchToken = FauxtonAPI.dispatcher.register(store.dispatch);
-    });
-
-    afterEach(function () {
-      FauxtonAPI.dispatcher.unregister(dispatchToken);
-    });
-
-    describe('#collectionChanged', function () {
-      var collection, pagination;
-      beforeEach(function () {
-        collection = new Backbone.Collection([{id:1}, {id: 2}]);
-        collection.updateSeq = function () { return 'updateSeq';};
-        pagination = {
-          pageStart: function () { return 10; },
-          pageEnd: function () { return 30; }
-        };
-      });
-
-      it('sets total rows correctly', function () {
-        store.collectionChanged(collection, pagination);
-        assert.equal(store.getTotalRows(), 2);
-      });
-
-      it('sets updateSeq', function () {
-        store.collectionChanged(collection, pagination);
-        assert.equal(store.getUpdateSeq(), 'updateSeq');
-      });
-
-      it('sets pageStart', function () {
-        store.collectionChanged(collection, pagination);
-        assert.equal(store.getPageStart(), 10);
-      });
-
-      it('sets pageEnd', function () {
-        store.collectionChanged(collection, pagination);
-        assert.equal(store.getPageEnd(), 30);
-      });
-
-    });
-
-
-  });
-});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/tests/docnumbers.componentSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/docnumbers.componentSpec.react.jsx b/app/addons/documents/tests/docnumbers.componentSpec.react.jsx
deleted file mode 100644
index dffc3c7..0000000
--- a/app/addons/documents/tests/docnumbers.componentSpec.react.jsx
+++ /dev/null
@@ -1,58 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-define([
-  'api',
-  'addons/documents/docs-list/docs-list.react',
-  'testUtils',
-  "react"
-], function (FauxtonAPI, Views, utils, React) {
-  FauxtonAPI.router = new FauxtonAPI.Router([]);
-
-  var assert = utils.assert;
-  var TestUtils = React.addons.TestUtils;
-
-  describe('All Docs Number', function () {
-
-    describe('PerPageSelector', function () {
-      var container, selectorEl, perPageChange;
-
-      beforeEach(function () {
-        perPageChange = sinon.spy();
-        container = document.createElement('div');
-        selectorEl = TestUtils.renderIntoDocument(
-          <Views.PerPageSelector
-            perPageChange={perPageChange}
-            perPage={10}
-          />,
-          container
-        );
-      });
-
-      afterEach(function () {
-        React.unmountComponentAtNode(container);
-      });
-
-      it('on new select calls callback with new page size', function () {
-        var selectEl = $(selectorEl.getDOMNode()).find('#select-per-page')[0];
-        var perPage = 5;
-        TestUtils.Simulate.change(selectEl, {
-          target: {
-            value: perPage
-          }
-        });
-
-        assert.ok(perPageChange.calledWith(perPage));
-      });
-
-    });
-  });
-});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/tests/docsnumbers-actionsSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/docsnumbers-actionsSpec.js b/app/addons/documents/tests/docsnumbers-actionsSpec.js
deleted file mode 100644
index 0646910..0000000
--- a/app/addons/documents/tests/docsnumbers-actionsSpec.js
+++ /dev/null
@@ -1,38 +0,0 @@
-define([
-  'api',
-  'addons/documents/docs-list/actions',
-  'addons/documents/docs-list/stores',
-  'testUtils',
-], function (FauxtonAPI, Actions, Stores, testUtils) {
-  var assert = testUtils.assert;
-
-  FauxtonAPI.router = new FauxtonAPI.Router([]);
-
-  describe('All Docs Numbers Actions', function () {
-
-    describe('updatePerPage', function () {
-      var pagination;
-
-      beforeEach(function () {
-        pagination = {
-          updatePerPage: function () {},
-          documentsLeftToFetch: function () { return 30; }
-        };
-      });
-
-      afterEach(function () {
-        Stores.allDocsListStore.getPagination.restore();
-        FauxtonAPI.triggerRouteEvent.restore();
-      });
-
-      it('triggers routeEvent', function () {
-        var stub = sinon.stub(Stores.allDocsListStore, 'getPagination');
-        stub.returns(pagination);
-        var spy = sinon.spy(FauxtonAPI, 'triggerRouteEvent');
-        Actions.updatePerPage(30);
-
-        assert.ok(spy.calledWith('perPageChange', 30));
-      });
-    });
-  });
-});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/tests/headerSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/headerSpec.react.jsx b/app/addons/documents/tests/headerSpec.react.jsx
index 052bc9c..ce914af 100644
--- a/app/addons/documents/tests/headerSpec.react.jsx
+++ b/app/addons/documents/tests/headerSpec.react.jsx
@@ -20,10 +20,11 @@ define([
   'addons/documents/resources',
   'addons/databases/base',
   'addons/fauxton/components',
+  'addons/documents/pagination/actions',
 
   'testUtils',
   'react'
-], function (FauxtonAPI, Views, Stores, Actions, Documents, Resources, Databases, Components, utils, React) {
+], function (FauxtonAPI, Views, Stores, Actions, Documents, Resources, Databases, Components, PaginationActions, utils, React) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -68,25 +69,18 @@ define([
       var database = new Databases.Model({id: 'registry'});
       bulkDeleteDocCollection = new Resources.BulkDeleteDocCollection([], {databaseId: 'registry'});
 
-
       database.allDocs = new Resources.AllDocs({_id: "ente"}, {
         database: database,
         viewMeta: {update_seq: 1},
         params: {}
       });
 
-      var pagination = new Components.IndexPagination({
-        collection: database.allDocs,
-        scrollToSelector: '#dashboard-content',
-        docLimit: 20,
-        perPage: 20
-      });
+      PaginationActions.newPagination(database.allDocs);
 
       var view = new Documents.Views.AllDocsList({
         viewList: false,
         bulkDeleteDocsCollection: bulkDeleteDocCollection,
         collection: database.allDocs,
-        pagination: pagination,
       });
 
       viewSandbox = new ViewSandbox();

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/tests/nightwatch/paginateAllDocs.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/nightwatch/paginateAllDocs.js b/app/addons/documents/tests/nightwatch/paginateAllDocs.js
new file mode 100644
index 0000000..ffadfd0
--- /dev/null
+++ b/app/addons/documents/tests/nightwatch/paginateAllDocs.js
@@ -0,0 +1,87 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+module.exports = {
+
+  'change number of items per page': function (client) {
+    /*jshint multistr: true */
+    var waitTime = 10000,
+        newDatabaseName = client.globals.testDatabaseName,
+        baseUrl = client.globals.test_settings.launch_url;
+
+    client
+      .populateDatabase(newDatabaseName)
+      .loginToGUI()
+      .url(baseUrl + '/#/database/' + newDatabaseName + '/_all_docs')
+      .waitForElementPresent('.control-toggle-alternative-header', waitTime, false)
+      .click('#select-per-page')
+      // hack to get select working by clicking on it and using keyboard to select
+      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
+      .keys(['\uE013', '\uE006'])
+      .waitForElementNotPresent('.spinner', waitTime)
+      .execute(function () {
+        return $('.doc-row').length;
+      }, function (result) {
+          client.assert.equal(result.value, 10);
+      })
+      .end();
+  },
+
+  'paginate to page two and back': function (client) {
+    /*jshint multistr: true */
+    var waitTime = 10000,
+        newDatabaseName = client.globals.testDatabaseName,
+        baseUrl = client.globals.test_settings.launch_url;
+
+    client
+      .populateDatabase(newDatabaseName)
+      .loginToGUI()
+      .url(baseUrl + '/#/database/' + newDatabaseName + '/_all_docs')
+      .waitForElementPresent('.control-toggle-alternative-header', waitTime, false)
+      .click('#select-per-page')
+      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
+      .keys(['\uE013', '\uE006'])
+      .waitForElementNotPresent('.spinner', waitTime)
+      .click('#next')
+      .waitForElementNotPresent('.spinner', waitTime)
+      .waitForElementPresent('div[data-id="document_17"]', waitTime)
+      .click('#previous')
+      .waitForElementNotPresent('.spinner', waitTime)
+      .waitForElementPresent('div[data-id="document_1"]', waitTime)
+      .end();
+  },
+
+  'PerPage change resets to page 1': function (client) {
+    /*jshint multistr: true */
+    var waitTime = 10000,
+        newDatabaseName = client.globals.testDatabaseName,
+        baseUrl = client.globals.test_settings.launch_url;
+
+    client
+      .populateDatabase(newDatabaseName)
+      .loginToGUI()
+      .url(baseUrl + '/#/database/' + newDatabaseName + '/_all_docs')
+      .waitForElementPresent('.control-toggle-alternative-header', waitTime, false)
+      .click('#select-per-page')
+      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
+      .keys(['\uE013', '\uE006'])
+      .waitForElementNotPresent('.spinner', waitTime)
+      .click('#next')
+      .waitForElementNotPresent('.spinner', waitTime)
+      .click('#select-per-page')
+      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
+      .keys(['\uE013', '\uE006'])
+      .waitForElementNotPresent('.spinner', waitTime)
+      .waitForElementPresent('div[data-id="document_1"]', waitTime)
+      .end();
+  }
+};

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/tests/nightwatch/paginateView.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/nightwatch/paginateView.js b/app/addons/documents/tests/nightwatch/paginateView.js
new file mode 100644
index 0000000..ba57e89
--- /dev/null
+++ b/app/addons/documents/tests/nightwatch/paginateView.js
@@ -0,0 +1,87 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+module.exports = {
+
+  'change number of items per page': function (client) {
+    /*jshint multistr: true */
+    var waitTime = 10000,
+        newDatabaseName = client.globals.testDatabaseName,
+        baseUrl = client.globals.test_settings.launch_url;
+
+    client
+      .populateDatabase(newDatabaseName)
+      .loginToGUI()
+      .url(baseUrl + '/#/database/' + newDatabaseName + '/_design/keyview/_view/keyview')
+      .waitForElementPresent('#toggle-query', waitTime, false)
+      .click('#select-per-page')
+      // hack to get select working by clicking on it and using keyboard to select
+      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
+      .keys(['\uE013', '\uE006'])
+      .waitForElementNotPresent('.spinner', waitTime)
+      .execute(function () {
+        return $('.doc-row').length;
+      }, function (result) {
+          client.assert.equal(result.value, 10);
+      })
+      .end();
+  },
+
+  'paginate to page two and back': function (client) {
+    /*jshint multistr: true */
+    var waitTime = 10000,
+        newDatabaseName = client.globals.testDatabaseName,
+        baseUrl = client.globals.test_settings.launch_url;
+
+    client
+      .populateDatabase(newDatabaseName)
+      .loginToGUI()
+      .url(baseUrl + '/#/database/' + newDatabaseName + '/_design/keyview/_view/keyview')
+      .waitForElementPresent('#toggle-query', waitTime, false)
+      .click('#select-per-page')
+      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
+      .keys(['\uE013', '\uE006'])
+      .waitForElementNotPresent('.spinner', waitTime)
+      .click('#next')
+      .waitForElementNotPresent('.spinner', waitTime)
+      .waitForElementPresent('div[data-id="document_19"]', waitTime)
+      .click('#previous')
+      .waitForElementNotPresent('.spinner', waitTime)
+      .waitForElementPresent('div[data-id="document_1"]', waitTime)
+      .end();
+  },
+
+  'PerPage change resets to page 1': function (client) {
+    /*jshint multistr: true */
+    var waitTime = 10000,
+        newDatabaseName = client.globals.testDatabaseName,
+        baseUrl = client.globals.test_settings.launch_url;
+
+    client
+      .populateDatabase(newDatabaseName)
+      .loginToGUI()
+      .url(baseUrl + '/#/database/' + newDatabaseName + '/_design/keyview/_view/keyview')
+      .waitForElementPresent('#toggle-query', waitTime, false)
+      .click('#select-per-page')
+      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
+      .keys(['\uE013', '\uE006'])
+      .waitForElementNotPresent('.spinner', waitTime)
+      .click('#next')
+      .waitForElementNotPresent('.spinner', waitTime)
+      .click('#select-per-page')
+      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
+      .keys(['\uE013', '\uE006'])
+      .waitForElementNotPresent('.spinner', waitTime)
+      .waitForElementPresent('div[data-id="document_1"]', waitTime)
+      .end();
+  }
+};

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/tests/viewsSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/viewsSpec.js b/app/addons/documents/tests/viewsSpec.js
index f24da86..0479762 100644
--- a/app/addons/documents/tests/viewsSpec.js
+++ b/app/addons/documents/tests/viewsSpec.js
@@ -26,40 +26,4 @@ define([
     });
   });
 
-  describe('Footer', function (done) {
-    var footer;
-
-    beforeEach(function () {
-      footer = new Documents.Views.Footer();
-      viewSandbox = new ViewSandbox();
-      viewSandbox.renderView(footer, done);
-    });
-
-    afterEach(function () {
-      viewSandbox.remove();
-    });
-
-    it('removes allDocs if it exists', function () {
-      var spy = sinon.spy(footer.allDocsNumber, 'remove');
-
-      footer.remove();
-
-      assert.ok(spy.calledOnce);
-    });
-
-
-    it('does not remove allDocs if it exists', function () {
-      var error = false;
-      footer.allDocsNumber = false;
-
-      try {
-        footer.remove();
-      } catch(e) {
-        error = true;
-      }
-
-      assert.notOk(error);
-    });
-
-  });
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/documents/views.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/views.js b/app/addons/documents/views.js
index 75e2b0a..4e23007 100644
--- a/app/addons/documents/views.js
+++ b/app/addons/documents/views.js
@@ -24,8 +24,9 @@ define([
   // React
   'addons/documents/header/header.react',
   'addons/documents/header/header.actions',
-  'addons/documents/docs-list/docs-list.react',
-  'addons/documents/docs-list/actions',
+  'addons/documents/pagination/pagination.react',
+  'addons/documents/pagination/actions',
+  'addons/documents/pagination/stores',
 
   //plugins
   "plugins/prettify"
@@ -33,7 +34,7 @@ define([
 
 function (app, FauxtonAPI, Components, Documents,
   Databases, Views, QueryOptions, ReactHeader, ReactHeaderActions,
-  ReactAllDocsList, AllDocsListActions) {
+  ReactPagination, PaginationActions, PaginationStores) {
 
   function showError (msg) {
     FauxtonAPI.addNotification({
@@ -44,25 +45,12 @@ function (app, FauxtonAPI, Components, Documents,
   }
 
   Views.Footer = FauxtonAPI.View.extend({
-    template: "addons/documents/templates/all_docs_footer",
-
-    beforeRender: function () {
-     this.allDocsNumber = new Views.ReactAllDocsNumber();
-     this.setView('#item-numbers', this.allDocsNumber);
-    },
-
-    cleanup: function () {
-      this.allDocsNumber && this.allDocsNumber.remove();
-    }
-  });
-
-  Views.ReactAllDocsNumber = FauxtonAPI.View.extend({
     afterRender: function () {
-      ReactAllDocsList.renderAllDocsNumber(this.el);
+      ReactPagination.renderFooter(this.el);
     },
 
     cleanup: function () {
-      ReactAllDocsList.removeAllDocsNumber(this.el);
+      ReactPagination.removeFooter(this.el);
     }
   });
 
@@ -300,7 +288,6 @@ function (app, FauxtonAPI, Components, Documents,
       }
       this.docParams = options.docParams || {};
       this.expandDocs = true;
-      this.perPageDefault = options.perPageDefault;
 
       // some doclists don't have an option to delete
       if (!this.viewList) {
@@ -312,9 +299,7 @@ function (app, FauxtonAPI, Components, Documents,
       FauxtonAPI.when(ids.map(function (id) {
         return this.removeDocument(id);
       }.bind(this))).done(function () {
-        var perPage = this.pagination.getPerPage();
-        this.pagination.updatePerPage(perPage);
-        FauxtonAPI.triggerRouteEvent('perPageChange', this.pagination.documentsLeftToFetch());
+        FauxtonAPI.triggerRouteEvent('perPageChange', PaginationStores.indexPaginationStore.documentsLeftToFetch());
         FauxtonAPI.addNotification({
           msg: 'Successfully deleted your docs',
           clear:  true
@@ -378,10 +363,9 @@ function (app, FauxtonAPI, Components, Documents,
     establish: function() {
       if (this.newView) { return null; }
 
-      return this.collection.fetch({
-        reset: true,
-        success:  function() { },
-        error: function(model, xhr, options){
+      return this.collection.fetch({reset: true}).then(function () {
+        PaginationActions.collectionReset();
+      }, function (model, xhr, options) {
           // TODO: handle error requests that slip through
           // This should just throw a notification, not break the page
           FauxtonAPI.addNotification({
@@ -392,7 +376,6 @@ function (app, FauxtonAPI, Components, Documents,
 
           //now redirect back to alldocs
           FauxtonAPI.navigate(model.database.url("index") + "?limit=100");
-        }
       });
     },
 
@@ -439,7 +422,7 @@ function (app, FauxtonAPI, Components, Documents,
 
     serialize: function() {
       return {
-        endOfResults: !this.pagination.canShowNextfn()
+        endOfResults: !PaginationStores.indexPaginationStore.canShowNext()
       };
     },
 
@@ -487,9 +470,6 @@ function (app, FauxtonAPI, Components, Documents,
 
       this.removeNestedViews();
 
-      this.pagination.setCollection(this.collection);
-      AllDocsListActions.collectionChanged(this.collection, this.pagination, this.perPageDefault);
-
       docs = this.expandDocs ? this.collection : this.collection.simple();
 
       docs.each(function(doc) {
@@ -512,22 +492,6 @@ function (app, FauxtonAPI, Components, Documents,
       }, this);
     },
 
-    setCollection: function (collection) {
-      this.collection = collection;
-      this.pagination.setCollection(collection);
-      this.allDocsNumber.setCollection(collection);
-    },
-
-    setParams: function (docParams, urlParams) {
-      this.docParams = docParams;
-      this.params = urlParams;
-      this.perPageDefault = this.docParams.limit;
-
-      if (this.params.limit) {
-        this.pagination.docLimit = this.params.limit;
-      }
-    },
-
     afterRender: function () {
       $("#dashboard-content").scrollTop(0);
 
@@ -548,11 +512,8 @@ function (app, FauxtonAPI, Components, Documents,
         selectedOnPage: this.$('.js-to-delete').length,
         documentsOnPageCount: this.$('.doc-row').length
       });
-    },
-
-    perPage: function () {
-      return this.allDocsNumber.perPage();
     }
+
   });
 
   Views.JumpToDoc = FauxtonAPI.View.extend({

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/fauxton/components.js
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/components.js b/app/addons/fauxton/components.js
index c59a7f2..d74e816 100644
--- a/app/addons/fauxton/components.js
+++ b/app/addons/fauxton/components.js
@@ -346,158 +346,6 @@ function(app, FauxtonAPI, ace, spin, ZeroClipboard) {
   });
 
 
-  Components.IndexPagination = FauxtonAPI.View.extend({
-    className: 'pagination',
-    tagName: 'ul',
-    template: "addons/fauxton/templates/index_pagination",
-    events: {
-      "click a": 'scrollTo',
-      "click a#next": 'nextClicked',
-      "click a#previous": 'previousClicked'
-    },
-
-    scrollTo: function () {
-      if (!this.scrollToSelector) { return; }
-      $(this.scrollToSelector).animate({ scrollTop: 0 }, 'slow');
-    },
-
-    initialize: function (options) {
-      this.previousUrlfn = options.previousUrlfn;
-      this.nextUrlfn = options.nextUrlfn;
-      this.scrollToSelector = options.scrollToSelector;
-      _.bindAll(this);
-      this.docLimit = options.docLimit || 1000000;
-      this.perPage = options.perPage || 20;
-      this.setDefaults();
-    },
-
-    setDefaults: function () {
-      this._pageNumber = [];
-      this._pageStart = 1;
-      this.enabled = true;
-      this.currentPage = 1;
-    },
-
-    canShowPreviousfn: function () {
-      if (!this.enabled) { return this.enabled; }
-      return this.collection.hasPrevious();
-    },
-
-    canShowNextfn: function () {
-      if (!this.enabled) { return this.enabled; }
-
-      if ((this.pageStart() + this.perPage) >= this.docLimit) {
-        return false;
-      }
-
-      return this.collection.hasNext();
-    },
-
-    previousClicked: function (event) {
-      event.preventDefault();
-      event.stopPropagation();
-      if (!this.canShowPreviousfn()) { return; }
-
-      this.decPageNumber();
-
-      FauxtonAPI.triggerRouteEvent('paginate', {
-       direction: 'previous',
-       perPage: this.perPage,
-       currentPage: this.currentPage
-      });
-    },
-
-    documentsLeftToFetch: function () {
-      var documentsLeftToFetch = this.docLimit - this.totalDocsViewed(),
-          limit = this.perPage;
-
-      if (documentsLeftToFetch < this.perPage ) {
-        limit = documentsLeftToFetch;
-      }
-
-      return limit;
-    },
-
-    nextClicked: function (event) {
-      event.preventDefault();
-      event.stopPropagation();
-      if (!this.canShowNextfn()) { return; }
-
-      this.incPageNumber();
-
-      FauxtonAPI.triggerRouteEvent('paginate', {
-       direction: 'next',
-       perPage: this.documentsLeftToFetch(),
-       currentPage: this.currentPage
-      });
-
-    },
-
-    serialize: function () {
-      return {
-        canShowNextfn: this.canShowNextfn,
-        canShowPreviousfn: this.canShowPreviousfn,
-      };
-    },
-
-    updatePerPage: function (newPerPage) {
-      this.setDefaults();
-      this.perPage = newPerPage;
-    },
-
-    page: function () {
-      return this._pageStart - 1;
-    },
-
-    incPageNumber: function () {
-      this.currentPage = this.currentPage + 1;
-      this._pageNumber.push({perPage: this.perPage});
-      this._pageStart = this._pageStart + this.perPage;
-    },
-
-    totalDocsViewed: function () {
-      return _.reduce(this._pageNumber, function (total, value) {
-        return total + value.perPage;
-      }, 0);
-    },
-
-    decPageNumber: function () {
-      this.currentPage = this.currentPage - 1;
-      this._pageNumber.pop();
-      var val = this._pageStart - this.perPage;
-      if (val < 1) {
-        val = 1;
-      }
-
-      this._pageStart = val;
-    },
-
-    pageStart: function () {
-      return this._pageStart;
-    },
-
-    pageEnd: function () {
-      return this.page() + this.collection.length;
-    },
-
-    disable: function () {
-      this.enabled = false;
-    },
-
-    enable: function () {
-      this.enabled = true;
-    },
-
-    setCollection: function (collection) {
-      this.collection = collection;
-      this.render();
-    },
-
-    getPerPage: function () {
-      return this.perPage;
-    }
-  });
-
   // A super-simple replacement for window.confirm()
   Components.ConfirmationModal = FauxtonAPI.View.extend({
     template: 'addons/fauxton/templates/confirmation_modal',

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/fauxton/templates/index_pagination.html
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/templates/index_pagination.html b/app/addons/fauxton/templates/index_pagination.html
deleted file mode 100644
index 92d6683..0000000
--- a/app/addons/fauxton/templates/index_pagination.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!--
-Licensed under the Apache License, Version 2.0 (the "License"); you may not
-use this file except in compliance with the License. You may obtain a copy of
-the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-License for the specific language governing permissions and limitations under
-the License.
--->
-
-<li <% if (!canShowPreviousfn()) {%> class="disabled" <% } %>>
- <a id="previous" class="icon fonticon-left-open" href="#"></a>
-</li>
-<li <% if (!canShowNextfn()) {%> class="disabled" <% } %>>
- <a id="next" class="icon fonticon-right-open" href="#"></a>
-</li>

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/app/addons/fauxton/tests/paginateSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/tests/paginateSpec.js b/app/addons/fauxton/tests/paginateSpec.js
deleted file mode 100644
index 471df5b..0000000
--- a/app/addons/fauxton/tests/paginateSpec.js
+++ /dev/null
@@ -1,88 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-define([
-       'app',
-       'addons/fauxton/components',
-       'addons/documents/resources',
-       'testUtils',
-       'api'
-], function (app, Views, Models, testUtils, FauxtonAPI) {
-  var assert = testUtils.assert,
-  ViewSandbox = testUtils.ViewSandbox;
-
-
-  describe('IndexPaginate', function () {
-    var viewSandbox, paginate, collection, navigateMock;
-
-    beforeEach(function (done) {
-      collection = new Models.IndexCollection([{
-        id:'myId1',
-        doc: 'num1'
-      },
-      {
-        id:'myId2',
-        doc: 'num2'
-      }], {
-        database: {id: 'databaseId', safeID: function () { return this.id;}},
-        design: '_design/myDoc'
-      });
-
-      paginate = new Views.IndexPagination({
-        collection: collection,
-        previousUrlfn: function () {},
-        nextUrlfn: function () {},
-        canShowPreviousfn: function () { return true; },
-        canShowNextfn: function () { return true;}
-      });
-      viewSandbox = new ViewSandbox();
-      viewSandbox.renderView(paginate, done); 
-    });
-
-    afterEach(function () {
-      viewSandbox.remove();
-    });
-
-    describe('#next', function () {
-      beforeEach(function () {
-        //do this so it doesn't throw an error on other unwired up components
-        FauxtonAPI.triggerRouteEvent = function () {};
-        //FauxtonAPI.triggerRouteEvent.restore && FauxtonAPI.triggerRouteEvent.restore();
-        //FauxtonAPI.navigate.restore && FauxtonAPI.navigate.restore(); 
-      });
-
-      it('Should trigger routeEvent', function () {
-        var navigateMock = sinon.spy(FauxtonAPI, 'triggerRouteEvent');
-
-        paginate.$('a#next').click();
-
-        assert.ok(navigateMock.calledOnce);
-        FauxtonAPI.triggerRouteEvent.restore();
-      });
-
-    });
-
-
-    describe('#previous', function () {
-
-      it('Should trigger routeEvent', function () {
-        var navigateMock = sinon.spy(FauxtonAPI, 'triggerRouteEvent');
-
-        paginate.$('a#previous').click();
-
-        assert.ok(navigateMock.calledOnce);
-        FauxtonAPI.triggerRouteEvent.restore();
-      });
-
-    });
-
-  });
-});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a5441229/assets/js/plugins/cloudant.pagingcollection.js
----------------------------------------------------------------------
diff --git a/assets/js/plugins/cloudant.pagingcollection.js b/assets/js/plugins/cloudant.pagingcollection.js
index 2ab5eaf..e383489 100644
--- a/assets/js/plugins/cloudant.pagingcollection.js
+++ b/assets/js/plugins/cloudant.pagingcollection.js
@@ -221,4 +221,3 @@
 
   return PagingCollection;
 }));
-