diff options
author | Garren Smith <garren.smith@gmail.com> | 2014-01-07 14:30:30 +0200 |
---|---|---|
committer | Garren Smith <garren.smith@gmail.com> | 2014-01-08 16:19:36 +0200 |
commit | 1a3937022cc11fb0b5256165f4e4f2259fd9f468 (patch) | |
tree | 41873b64d6e028c4e798430266820a82914ec2cb | |
parent | 767b0582fd69c12a527cc2dc0e32ed3c4f54885e (diff) | |
download | couchdb-1a3937022cc11fb0b5256165f4e4f2259fd9f468.tar.gz |
Fauxton: Improve UX for pagination
10 files changed, 114 insertions, 49 deletions
diff --git a/src/fauxton/app/modules/documents/resources.js b/src/fauxton/app/modules/documents/resources.js index 83589ca3a..43bb0fdc7 100644 --- a/src/fauxton/app/modules/documents/resources.js +++ b/src/fauxton/app/modules/documents/resources.js @@ -225,6 +225,10 @@ function(app, FauxtonAPI) { }); Documents.ViewRow = Backbone.Model.extend({ + // this is a hack so that backbone.collections doesn't group + // these by id and reduce the number of items returned. + idAttribute: "_id", + docType: function() { if (!this.id) return "reduction"; @@ -329,16 +333,15 @@ function(app, FauxtonAPI) { return this.url('app'); }, - urlPreviousPage: function (num, firstId) { - this.params.limit = num; - if (firstId) { - this.params.startkey_docid = '"' + firstId + '"'; - this.params.startkey = '"' + firstId + '"'; + urlPreviousPage: function (num, params) { + if (params) { + this.params = params; } else { - delete this.params.startkey; - delete this.params.startkey_docid; + this.params = {reduce: false}; } - return this.url('app'); + + this.params.limit = num; + return this.url('app'); }, totalRows: function() { @@ -429,24 +432,27 @@ function(app, FauxtonAPI) { urlNextPage: function (num, lastId) { if (!lastId) { - lastId = this.last().id; + lastDoc = this.last(); } - this.params.startkey_docid = '"' + lastId + '"'; - this.params.startkey = '"' + lastId + '"'; - this.params.limit = num; + var id = lastDoc.get("id"); + if (id) { + this.params.startkey_docid = id; + } + + this.params.startkey = JSON.stringify(lastDoc.get('key')); + this.params.limit = num + 1; return this.url('app'); }, - urlPreviousPage: function (num, firstId) { - this.params.limit = num; - if (firstId) { - this.params.startkey_docid = '"' + firstId + '"'; - this.params.startkey = '"' + firstId + '"'; + urlPreviousPage: function (num, params) { + if (params) { + this.params = params; } else { - delete this.params.startkey; - delete this.params.startkey_docid; + this.params = {reduce: false}; } + + this.params.limit = num; return this.url('app'); }, @@ -463,6 +469,8 @@ function(app, FauxtonAPI) { }, totalRows: function() { + if (this.params.reduce) { return "unknown_reduce";} + return this.viewMeta.total_rows || "unknown"; }, diff --git a/src/fauxton/app/modules/documents/routes.js b/src/fauxton/app/modules/documents/routes.js index 538cd56eb..dbad6d067 100644 --- a/src/fauxton/app/modules/documents/routes.js +++ b/src/fauxton/app/modules/documents/routes.js @@ -188,7 +188,6 @@ function(app, FauxtonAPI, Documents, Databases) { allDocs: function(databaseName, options) { var docOptions = app.getParams(options); - docOptions.include_docs = true; this.data.database.buildAllDocs(docOptions); if (docOptions.startkey && docOptions.startkey.indexOf('_design') > -1) { @@ -234,8 +233,6 @@ function(app, FauxtonAPI, Documents, Databases) { params: params }); - - var ddocInfo = { id: "_design/" + decodeDdoc, currView: view, @@ -301,9 +298,9 @@ function(app, FauxtonAPI, Documents, Databases) { ddoc = event.ddoc; if (event.allDocs) { - docOptions.include_docs = true; - this.data.database.buildAllDocs(docOptions); - return; + this.documentsView.collection = this.data.database.buildAllDocs(docOptions); + this.documentsView.cleanup(); + return this.documentsView.forceRender(); } this.data.indexedDocs = new Documents.IndexCollection(null, { @@ -313,6 +310,7 @@ function(app, FauxtonAPI, Documents, Databases) { params: app.getParams() }); + this.documentsView && this.documentsView.remove(); this.documentsView = this.setView("#dashboard-lower-content", new Documents.Views.AllDocsList({ database: this.data.database, collection: this.data.indexedDocs, diff --git a/src/fauxton/app/modules/documents/views.js b/src/fauxton/app/modules/documents/views.js index e1554356a..0c75b8198 100644 --- a/src/fauxton/app/modules/documents/views.js +++ b/src/fauxton/app/modules/documents/views.js @@ -446,6 +446,8 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum initialize: function (options) { this.newView = options.newView || false; + this.showNumbers = options.showNumbers; + this.pagination = options.pagination; this.listenTo(this.collection, 'totalRows:decrement', this.render); }, @@ -453,7 +455,9 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum serialize: function () { var totalRows = 0, recordStart = 0, - updateSeq = false; + updateSeq = false, + pageStart = 0, + pageEnd = 20; if (!this.newView) { totalRows = this.collection.totalRows(); @@ -461,13 +465,20 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum } recordStart = this.collection.recordStart(); + if (this.pagination) { + pageStart = this.pagination.pageStart(); + pageEnd = this.pagination.pageEnd(); + } return { database: app.mixins.safeURLName(this.collection.database.id), updateSeq: updateSeq, offset: recordStart, totalRows: totalRows, + showNumbers: this.showNumbers, numModels: this.collection.models.length + recordStart - 1, + pageStart: pageStart, + pageEnd: pageEnd }; } @@ -492,7 +503,7 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum beforeRender: function () { this.advancedOptions = this.insertView('#query', new Views.AdvancedOptions({ - updateViewFn: this.updateView, + updateViewFn: this.updateAllDocs, previewFn: this.previewView, hasReduce: false, showPreview: false, @@ -509,7 +520,7 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum }, - updateView: function (event, paramInfo) { + updateAllDocs: function (event, paramInfo) { event.preventDefault(); var errorParams = paramInfo.errorParams, @@ -578,7 +589,6 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum } this.newView = options.newView || false; this.expandDocs = true; - this.addPagination(); }, establish: function() { @@ -651,7 +661,6 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum }); model.collection.remove(model.id); - console.log(model.id.match('_design'), !!model.id.match('_design')); if (!!model.id.match('_design')) { FauxtonAPI.triggerRouteEvent('reloadDesignDocs'); } @@ -667,22 +676,31 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum addPagination: function () { var collection = this.collection; + var perPage = function () { + if (collection.params.limit && collection.skipFirstItem) { + return parseInt(collection.params.limit, 10) - 1; + } else if (collection.params.limit) { + return parseInt(collection.params.limit, 10); + } + + return 20; + }; this.pagination = new Components.IndexPagination({ collection: this.collection, scrollToSelector: '#dashboard-content', previousUrlfn: function () { - return collection.urlPreviousPage(20, this.previousIds.pop()); + return collection.urlPreviousPage(perPage(), this.previousParams.pop()); }, canShowPreviousfn: function () { - if (collection.viewMeta.offset === 0) { + if (this.previousParams.length === 0) { return false; } return true; }, canShowNextfn: function () { - if (collection.length === 0 || (collection.viewMeta.offset + collection.length + 2) >= collection.viewMeta.total_rows) { + if (collection.length < (perPage() -1)) { return false; } @@ -690,18 +708,34 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, resizeColum }, nextUrlfn: function () { - return collection.urlNextPage(20); + return collection.urlNextPage(perPage()); } }); }, + + cleanup: function () { + this.pagination.remove(); + this.allDocsNumber.remove(); + _.each(this.rows, function (row) {row.remove();}); + }, beforeRender: function() { + var showNumbers = true; + + this.addPagination(); + this.insertView('#documents-pagination', this.pagination); + + if (this.designDocs || this.collection.idxType === '_view' || this.collection.params.startkey === '"_design"') { + showNumbers = false; + } + this.allDocsNumber = this.setView('#item-numbers', new Views.AllDocsNumber({ collection: this.collection, - newView: this.newView + newView: this.newView, + showNumbers: showNumbers, + pagination: this.pagination })); - this.insertView('#documents-pagination', this.pagination); var docs = this.expandDocs ? this.collection : this.collection.simple(); docs.each(function(doc) { diff --git a/src/fauxton/app/modules/fauxton/components.js b/src/fauxton/app/modules/fauxton/components.js index 6afe0467c..a9f45addb 100644 --- a/src/fauxton/app/modules/fauxton/components.js +++ b/src/fauxton/app/modules/fauxton/components.js @@ -60,8 +60,6 @@ function(app, FauxtonAPI, ace) { "click a#previous": 'previousClicked' }, - previousIds: [], - scrollTo: function () { if (!this.scrollToSelector) { return; } $(this.scrollToSelector).animate({ scrollTop: 0 }, 'slow'); @@ -74,6 +72,7 @@ function(app, FauxtonAPI, ace) { this.canShowNextfn = options.canShowNextfn; this.scrollToSelector = options.scrollToSelector; _.bindAll(this); + this.previousParams = []; }, previousClicked: function (event) { @@ -88,10 +87,11 @@ function(app, FauxtonAPI, ace) { event.preventDefault(); event.stopPropagation(); if (!this.canShowNextfn()) { return; } - var doc = this.collection.first(); - if (doc) { - this.previousIds.push(doc.id); + var params = _.clone(this.collection.params); + + if (params) { + this.previousParams.push(params); } FauxtonAPI.navigate(this.nextUrlfn(), {trigger: false}); @@ -103,6 +103,27 @@ function(app, FauxtonAPI, ace) { canShowNextfn: this.canShowNextfn, canShowPreviousfn: this.canShowPreviousfn, }; + }, + + pageLimit: function () { + var limit = 20; + + if (this.collection.params.limit && this.collection.skipFirstItem) { + limit = parseInt(this.collection.params.limit, 10) - 1; + } else if (this.collection.params.limit) { + limit = parseInt(this.collection.params.limit, 10); + } + + return limit; + }, + + pageStart: function () { + return (this.previousParams.length * this.pageLimit()) + 1; + + }, + + pageEnd: function () { + return (this.previousParams.length * this.pageLimit()) + this.pageLimit(); } }); diff --git a/src/fauxton/app/templates/databases/item.html b/src/fauxton/app/templates/databases/item.html index e2f80712f..313dd961b 100644 --- a/src/fauxton/app/templates/databases/item.html +++ b/src/fauxton/app/templates/databases/item.html @@ -13,7 +13,7 @@ the License. --> <td> - <a href="#/database/<%=encoded%>/_all_docs?limit=<%=docLimit%>"><%= database.get("name") %></a> + <a href="#/database/<%=encoded%>/_all_docs?limit=<%=docLimit%>&include_docs=true"><%= database.get("name") %></a> </td> <td><%= database.status.humanSize() %></td> <td><%= database.status.numDocs() %></td> diff --git a/src/fauxton/app/templates/documents/advanced_options.html b/src/fauxton/app/templates/documents/advanced_options.html index 8e96574b1..e2563253f 100644 --- a/src/fauxton/app/templates/documents/advanced_options.html +++ b/src/fauxton/app/templates/documents/advanced_options.html @@ -67,8 +67,9 @@ the License. Limit: <select name="limit" class="input-small"> <option>5</option> - <option selected="selected">10</option> - <option>25</option> + <option>10</option> + <option selected="selected">20</option> + <option>30</option> <option>50</option> <option>100</option> </select> diff --git a/src/fauxton/app/templates/documents/all_docs_layout.html b/src/fauxton/app/templates/documents/all_docs_layout.html index 526c200d1..6b4a31bc4 100644 --- a/src/fauxton/app/templates/documents/all_docs_layout.html +++ b/src/fauxton/app/templates/documents/all_docs_layout.html @@ -12,7 +12,7 @@ License for the specific language governing permissions and limitations under the License. --> <ul class="nav nav-tabs window-resizeable" id="db-views-tabs-nav"> - <li><a id="toggle-query" class="fonticon-plus fonticon" href="#query" data-toggle="tab">Query Options</a></li> + <li><a id="toggle-query" class="fonticon-plus fonticon" href="#query" data-bypass="true" data-toggle="tab">Query Options</a></li> </ul> <div class="tab-content"> <div class="tab-pane" id="query"> diff --git a/src/fauxton/app/templates/documents/all_docs_number.html b/src/fauxton/app/templates/documents/all_docs_number.html index c4ea8f64a..df8fe07b6 100644 --- a/src/fauxton/app/templates/documents/all_docs_number.html +++ b/src/fauxton/app/templates/documents/all_docs_number.html @@ -13,8 +13,10 @@ the License. --> <% if (totalRows === "unknown"){ %> Showing 0 documents. <a href="#/database/<%=database%>/new"> Create your first document.</a> -<% } else { %> +<% } else if (showNumbers) { %> Showing <%=offset%> - <%= numModels %> of <%= totalRows %> rows +<% } else { %> + Showing <%=pageStart%> - <%= pageEnd %> <%}%> <% if (updateSeq) { %> -- Update Sequence: <%= updateSeq %> diff --git a/src/fauxton/app/templates/documents/index_row_docular.html b/src/fauxton/app/templates/documents/index_row_docular.html index 383545359..f1b221757 100644 --- a/src/fauxton/app/templates/documents/index_row_docular.html +++ b/src/fauxton/app/templates/documents/index_row_docular.html @@ -11,8 +11,9 @@ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> - -<td class="select"><input type="checkbox"></td> +<% if (doc.isEditable()) { %> + <td class="select"><input type="checkbox"></td> +<% } %> <td> <div> <pre class="prettyprint"><%- doc.prettyJSON() %></pre> diff --git a/src/fauxton/app/templates/documents/sidebar.html b/src/fauxton/app/templates/documents/sidebar.html index 8a73ae9a3..362dd0cbc 100644 --- a/src/fauxton/app/templates/documents/sidebar.html +++ b/src/fauxton/app/templates/documents/sidebar.html @@ -55,7 +55,7 @@ the License. <nav> <ul class="nav nav-list"> - <li class="active"><a id="all-docs" href="#<%= database.url('index') %>?limit=<%= docLimit %>" class="toggle-view"> All documents</a></li> + <li class="active"><a id="all-docs" href="#<%= database.url('index') %>?limit=<%= docLimit %>&include_docs=true" class="toggle-view"> All documents</a></li> <li><a id="design-docs" href='#<%= database.url("index") %>?limit=<%= docLimit %>&startkey="_design"&endkey="_e"' class="toggle-view"> All design docs</a></li> </ul> <ul class="nav nav-list views"> |