summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGarren Smith <garren.smith@gmail.com>2013-09-06 14:49:36 +0200
committerGarren Smith <garren.smith@gmail.com>2013-09-10 16:17:16 +0200
commitd081ae59821e9abe9f37e1c82a94aafd95a2a339 (patch)
tree141059f8f721e7f9267896ec2554c7ffd1679bc4
parent4ac5314ae15d6105113efc03678a85de46141329 (diff)
downloadcouchdb-d081ae59821e9abe9f37e1c82a94aafd95a2a339.tar.gz
Fauxton: Index pagination basics working and tests
-rw-r--r--src/fauxton/app/modules/databases/views.js10
-rw-r--r--src/fauxton/app/modules/documents/resources.js64
-rw-r--r--src/fauxton/app/modules/documents/tests/resourcesSpec.js84
-rw-r--r--src/fauxton/app/modules/documents/views.js36
-rw-r--r--src/fauxton/app/modules/fauxton/base.js23
-rw-r--r--src/fauxton/app/modules/fauxton/paginate.js93
-rw-r--r--src/fauxton/app/templates/documents/all_docs_list.html15
-rw-r--r--src/fauxton/app/templates/fauxton/index_pagination.html24
-rw-r--r--src/fauxton/test/core/paginateSpec.js100
9 files changed, 403 insertions, 46 deletions
diff --git a/src/fauxton/app/modules/databases/views.js b/src/fauxton/app/modules/databases/views.js
index c177264a1..ef7584127 100644
--- a/src/fauxton/app/modules/databases/views.js
+++ b/src/fauxton/app/modules/databases/views.js
@@ -13,11 +13,11 @@
define([
"app",
- "modules/fauxton/base",
+ "modules/fauxton/paginate",
"api"
],
-function(app, Fauxton, FauxtonAPI) {
+function(app, Paginate, FauxtonAPI) {
var Views = {};
Views.Item = FauxtonAPI.View.extend({
@@ -32,8 +32,8 @@ function(app, Fauxton, FauxtonAPI) {
});
Views.List = FauxtonAPI.View.extend({
- dbLimit: 10,
- perPage: 10,
+ dbLimit: 20,
+ perPage: 20,
template: "templates/databases/list",
events: {
"click button.all": "selectAll",
@@ -83,7 +83,7 @@ function(app, Fauxton, FauxtonAPI) {
}));
}, this);
- this.insertView("#database-pagination", new Fauxton.Pagination({
+ this.insertView("#database-pagination", new Paginate.Pagination({
page: this.page,
perPage: this.perPage,
total: this.collection.length,
diff --git a/src/fauxton/app/modules/documents/resources.js b/src/fauxton/app/modules/documents/resources.js
index 0a80ad83a..a9e9836d6 100644
--- a/src/fauxton/app/modules/documents/resources.js
+++ b/src/fauxton/app/modules/documents/resources.js
@@ -255,14 +255,41 @@ function(app, FauxtonAPI) {
this.params = options.params;
},
- url: function() {
+ url: function(context) {
var query = "";
if (this.params) {
query = "?" + $.param(this.params);
}
+
+ if (context === 'app') {
+ return 'database/' + this.database.id + "/_all_docs" + query;
+ }
return app.host + "/" + this.database.id + "/_all_docs" + query;
},
+ urlNextPage: function (num, lastId) {
+ if (!lastId) {
+ lastId = this.last().id;
+ }
+
+ this.params.startkey_docid = '"' + lastId + '"';
+ this.params.startkey = '"' + lastId + '"';
+ this.params.limit = num;
+ return this.url('app');
+ },
+
+ urlPreviousPage: function (num, firstId) {
+ this.params.limit = num;
+ if (firstId) {
+ this.params.startkey_docid = '"' + firstId + '"';
+ this.params.startkey = '"' + firstId + '"';
+ } else {
+ delete this.params.startkey;
+ delete this.params.startkey_docid;
+ }
+ return this.url('app');
+ },
+
totalRows: function() {
return this.viewMeta.total_rows || "unknown";
},
@@ -301,15 +328,44 @@ function(app, FauxtonAPI) {
this.design = options.design.replace('_design/','');
},
- url: function() {
+ url: function(context) {
var query = "";
if (this.params) {
query = "?" + $.param(this.params);
}
- var url = [app.host, this.database.id, "_design", this.design, this.idxType, this.view];
+
+ var startOfUrl = app.host;
+ if (context === 'app') {
+ startOfUrl = 'database';
+ }
+
+ var url = [startOfUrl, this.database.id, "_design", this.design, this.idxType, this.view];
return url.join("/") + query;
},
+ urlNextPage: function (num, lastId) {
+ if (!lastId) {
+ lastId = this.last().id;
+ }
+
+ this.params.startkey_docid = '"' + lastId + '"';
+ this.params.startkey = '"' + lastId + '"';
+ this.params.limit = num;
+ return this.url('app');
+ },
+
+ urlPreviousPage: function (num, firstId) {
+ this.params.limit = num;
+ if (firstId) {
+ this.params.startkey_docid = '"' + firstId + '"';
+ this.params.startkey = '"' + firstId + '"';
+ } else {
+ delete this.params.startkey;
+ delete this.params.startkey_docid;
+ }
+ return this.url('app');
+ },
+
totalRows: function() {
return this.viewMeta.total_rows || "unknown";
},
@@ -324,7 +380,7 @@ function(app, FauxtonAPI) {
this.viewMeta = {
total_rows: resp.total_rows,
- offest: resp.offest,
+ offset: resp.offset,
update_seq: resp.update_seq
};
return _.map(resp.rows, function(row) {
diff --git a/src/fauxton/app/modules/documents/tests/resourcesSpec.js b/src/fauxton/app/modules/documents/tests/resourcesSpec.js
new file mode 100644
index 000000000..35bbdb367
--- /dev/null
+++ b/src/fauxton/app/modules/documents/tests/resourcesSpec.js
@@ -0,0 +1,84 @@
+// 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([
+ 'modules/documents/resources',
+ 'testUtils'
+], function (Models, testUtils) {
+ var assert = testUtils.assert;
+
+ describe('IndexCollection', function () {
+ var collection;
+ beforeEach(function () {
+ collection = new Models.IndexCollection([{
+ id:'myId1',
+ doc: 'num1'
+ },
+ {
+ id:'myId2',
+ doc: 'num2'
+ }], {
+ database: {id: 'databaseId'},
+ design: '_design/myDoc'
+ });
+
+ });
+
+ it('Should return urlNext', function () {
+ var url = collection.urlNextPage(20);
+
+ assert.equal(url, 'database/databaseId/_design/myDoc/_view/?limit=20&reduce=false&startkey_docid=%22myId2%22&startkey=%22myId2%22');
+
+ });
+
+ it('Should return urlPrevious', function () {
+ var url = collection.urlPreviousPage(20, 'myId1');
+
+ assert.equal(url, 'database/databaseId/_design/myDoc/_view/?limit=20&reduce=false&startkey_docid=%22myId1%22&startkey=%22myId1%22');
+
+ });
+
+ });
+
+ describe('AllDocs', function () {
+ var collection;
+ beforeEach(function () {
+ collection = new Models.AllDocs([{
+ _id:'myId1',
+ doc: 'num1'
+ },
+ {
+ _id:'myId2',
+ doc: 'num2'
+ }], {
+ database: {id: 'databaseId'},
+ params: {limit: 20}
+ });
+
+ });
+
+ it('Should return urlNext', function () {
+ var url = collection.urlNextPage(20);
+
+ assert.equal(url, 'database/databaseId/_all_docs?limit=20&startkey_docid=%22myId2%22&startkey=%22myId2%22');
+
+ });
+
+ it('Should return urlPrevious', function () {
+ var url = collection.urlPreviousPage(20, 'myId1');
+ assert.equal(url, 'database/databaseId/_all_docs?limit=20&startkey_docid=%22myId1%22&startkey=%22myId1%22');
+ });
+
+
+ });
+
+});
+
diff --git a/src/fauxton/app/modules/documents/views.js b/src/fauxton/app/modules/documents/views.js
index 83e1e8fd3..c345c9cb7 100644
--- a/src/fauxton/app/modules/documents/views.js
+++ b/src/fauxton/app/modules/documents/views.js
@@ -14,6 +14,7 @@ define([
"app",
"api",
+ "modules/fauxton/paginate",
"modules/documents/resources",
"modules/pouchdb/base",
@@ -29,7 +30,7 @@ define([
],
-function(app, FauxtonAPI, Documents, pouchdb, Codemirror, JSHint, resizeColumns) {
+function(app, FauxtonAPI, Paginate, Documents, pouchdb, Codemirror, JSHint, resizeColumns) {
var Views = {};
Views.Tabs = FauxtonAPI.View.extend({
@@ -435,6 +436,7 @@ function(app, FauxtonAPI, Documents, pouchdb, Codemirror, JSHint, resizeColumns)
this.ddocID = options.ddocInfo.id;
}
this.newView = options.newView || false;
+ this.addPagination();
},
establish: function() {
@@ -510,7 +512,39 @@ function(app, FauxtonAPI, Documents, pouchdb, Codemirror, JSHint, resizeColumns)
}, this);
},
+ addPagination: function () {
+ var collection = this.collection;
+
+ this.pagination = new Paginate.IndexPagination({
+ collection: this.collection,
+ scrollToSelector: '#dashboard-lower-content',
+ previousUrlfn: function () {
+ return collection.urlPreviousPage(20, this.previousIds.pop());
+ },
+ canShowPreviousfn: function () {
+ if (collection.viewMeta.offset === 0) {
+ return false;
+ }
+
+ return true;
+ },
+ canShowNextfn: function () {
+
+ if ((collection.viewMeta.offset + 1) === collection.viewMeta.total_rows) {
+ return false;
+ }
+
+ return true;
+ },
+
+ nextUrlfn: function () {
+ return collection.urlNextPage(20);
+ }
+ });
+ },
+
beforeRender: function() {
+ this.insertView('#documents-pagination', this.pagination);
this.collection.each(function(doc) {
this.rows[doc.id] = this.insertView("table.all-docs tbody", new this.nestedView({
model: doc
diff --git a/src/fauxton/app/modules/fauxton/base.js b/src/fauxton/app/modules/fauxton/base.js
index 8fa40fa2f..a4b3a5e82 100644
--- a/src/fauxton/app/modules/fauxton/base.js
+++ b/src/fauxton/app/modules/fauxton/base.js
@@ -260,27 +260,6 @@ function(app, Backbone, resizeColumns) {
}
});
- Fauxton.Pagination = Backbone.View.extend({
- template: "templates/fauxton/pagination",
-
- initialize: function(options) {
- this.page = parseInt(options.page, 10);
- this.perPage = options.perPage;
- this.total = options.total;
- this.totalPages = Math.ceil(this.total / this.perPage);
- this.urlFun = options.urlFun;
- },
-
- serialize: function() {
- return {
- page: this.page,
- perPage: this.perPage,
- total: this.total,
- totalPages: this.totalPages,
- urlFun: this.urlFun
- };
- }
- });
-
+
return Fauxton;
});
diff --git a/src/fauxton/app/modules/fauxton/paginate.js b/src/fauxton/app/modules/fauxton/paginate.js
new file mode 100644
index 000000000..a32bbbe62
--- /dev/null
+++ b/src/fauxton/app/modules/fauxton/paginate.js
@@ -0,0 +1,93 @@
+// 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",
+ // Libs
+ "api"
+],
+
+function(app, FauxtonAPI) {
+ var Paginate = app.module();
+
+ Paginate.Pagination = FauxtonAPI.View.extend({
+ template: "templates/fauxton/pagination",
+
+ initialize: function(options) {
+ this.page = parseInt(options.page, 10);
+ this.perPage = options.perPage;
+ this.total = options.total;
+ this.totalPages = Math.ceil(this.total / this.perPage);
+ this.urlFun = options.urlFun;
+ },
+
+ serialize: function() {
+ return {
+ page: this.page,
+ perPage: this.perPage,
+ total: this.total,
+ totalPages: this.totalPages,
+ urlFun: this.urlFun
+ };
+ }
+ });
+
+ Paginate.IndexPagination = FauxtonAPI.View.extend({
+ template: "templates/fauxton/index_pagination",
+ events: {
+ "click a": 'scrollTo',
+ "click a#next": 'nextClicked',
+ "click a#previous": 'previousClicked'
+ },
+
+ currentDirection: 'next',
+ previousIds: [],
+
+ scrollTo: function () {
+ if (!this.scrollToSelector) { return; }
+ $(this.scrollToSelector).animate({ scrollTop: 0 }, 'slow');
+ },
+
+ initialize: function (options) {
+ this.previousUrlfn = options.previousUrlfn;
+ this.nextUrlfn = options.nextUrlfn;
+ this.canShowPreviousfn = options.canShowPreviousfn;
+ this.canShowNextfn = options.canShowNextfn;
+ this.scrollToSelector = options.scrollToSelector;
+ _.bindAll(this);
+ },
+
+ previousClicked: function (event) {
+ event.preventDefault();
+ this.currentDirection = 'previous';
+ FauxtonAPI.navigate(this.previousUrlfn());
+ },
+
+ nextClicked: function (event) {
+ event.preventDefault();
+ this.currentDirection = 'next';
+ this.previousIds.push(this.collection.first().id);
+ FauxtonAPI.navigate(this.nextUrlfn());
+ },
+
+ serialize: function () {
+ return {
+ canShowNextfn: this.canShowNextfn,
+ canShowPreviousfn: this.canShowPreviousfn,
+ };
+ }
+
+ });
+
+ return Paginate;
+});
+
diff --git a/src/fauxton/app/templates/documents/all_docs_list.html b/src/fauxton/app/templates/documents/all_docs_list.html
index fd1a5b0b2..f60257551 100644
--- a/src/fauxton/app/templates/documents/all_docs_list.html
+++ b/src/fauxton/app/templates/documents/all_docs_list.html
@@ -41,18 +41,5 @@ the License.
<table class="all-docs table table-striped table-condensed">
<tbody></tbody>
</table>
- <!--
- <div class="pagination pagination-centered">
- <ul>
- <li class="disabled"><a href="#">&laquo;</a></li>
- <li class="active"><a href="#">1</a></li>
- <li><a href="#">2</a></li>
- <li><a href="#">3</a></li>
- <li><a href="#">4</a></li>
- <li><a href="#">5</a></li>
- <li><a href="#">&raquo;</a></li>
- </ul>
- </div>
- -->
-
+ <div id="documents-pagination"></div>
</div>
diff --git a/src/fauxton/app/templates/fauxton/index_pagination.html b/src/fauxton/app/templates/fauxton/index_pagination.html
new file mode 100644
index 000000000..f445377d8
--- /dev/null
+++ b/src/fauxton/app/templates/fauxton/index_pagination.html
@@ -0,0 +1,24 @@
+<!--
+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.
+-->
+
+<div class="pagination pagination-centered">
+ <ul>
+ <li <% if (!canShowPreviousfn()) {%> class="disabled" <% } %>>
+ <a id="previous" href="#"> Previous </a>
+ </li>
+ <li <% if (!canShowNextfn()) {%> class="disabled" <% } %>>
+ <a id="next" href="#"> Next </a></li>
+ </ul>
+</div>
+
diff --git a/src/fauxton/test/core/paginateSpec.js b/src/fauxton/test/core/paginateSpec.js
new file mode 100644
index 000000000..6b7bfb6e7
--- /dev/null
+++ b/src/fauxton/test/core/paginateSpec.js
@@ -0,0 +1,100 @@
+// 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',
+ 'modules/fauxton/paginate',
+ 'modules/documents/resources',
+ 'testUtils',
+ 'app'
+], function (FauxtonAPI, Views, Models, testUtils, app) {
+ var assert = testUtils.assert,
+ ViewSandbox = testUtils.ViewSandbox;
+
+
+ describe('IndexPaginate', function () {
+ var viewSandbox, paginate, collection, navigateMock;
+ beforeEach(function () {
+ app.router = {
+ navigate: function () {}
+ };
+
+ collection = new Models.IndexCollection([{
+ id:'myId1',
+ doc: 'num1'
+ },
+ {
+ id:'myId2',
+ doc: 'num2'
+ }], {
+ database: {id: 'databaseId'},
+ design: '_design/myDoc'
+ });
+
+ paginate = new Views.IndexPagination({
+ collection: collection,
+ previousUrlfn: function () {},
+ nextUrlfn: function () {},
+ canShowPreviousfn: function () {},
+ canShowNextfn: function () {}
+ });
+ viewSandbox = new ViewSandbox();
+ viewSandbox.renderView(paginate);
+ });
+
+ afterEach(function () {
+ viewSandbox.remove();
+ });
+
+ describe('#next', function () {
+
+ it('should set direction as next', function () {
+ paginate.$('a#next').click();
+
+ assert.equal(paginate.currentDirection, 'next');
+
+ });
+
+ it('Should navigate', function () {
+ var navigateMock = sinon.spy(FauxtonAPI, 'navigate');
+
+ paginate.$('a#next').click();
+
+ assert.ok(navigateMock.calledOnce);
+ FauxtonAPI.navigate.restore();
+ });
+
+ });
+
+
+ describe('#previous', function () {
+
+ it('should set direction as next', function () {
+ paginate.$('a#previous').click();
+
+ assert.equal(paginate.currentDirection, 'previous');
+
+ });
+
+ it('Should navigate', function () {
+ var navigateMock = sinon.spy(FauxtonAPI, 'navigate');
+
+ paginate.$('a#previous').click();
+
+ assert.ok(navigateMock.calledOnce);
+ FauxtonAPI.navigate.restore();
+ });
+
+
+ });
+
+ });
+});