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 2013/09/17 16:24:28 UTC

git commit: updated refs/heads/fauxton-typeahead to b14ba5b

Updated Branches:
  refs/heads/fauxton-typeahead [created] b14ba5b55


add typeahead view


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

Branch: refs/heads/fauxton-typeahead
Commit: b14ba5b55eae8bc5e77beef53f3e1c74090318f9
Parents: 8a33322
Author: Garren Smith <ga...@gmail.com>
Authored: Tue Sep 17 16:23:32 2013 +0200
Committer: Garren Smith <ga...@gmail.com>
Committed: Tue Sep 17 16:23:32 2013 +0200

----------------------------------------------------------------------
 src/fauxton/app/addons/replication/views.js   | 534 ++++++++++-----------
 src/fauxton/app/modules/databases/views.js    |  36 +-
 src/fauxton/app/modules/documents/views.js    |   6 +-
 src/fauxton/app/modules/fauxton/components.js | 138 ++++++
 src/fauxton/app/modules/fauxton/paginate.js   |  92 ----
 5 files changed, 408 insertions(+), 398 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb/blob/b14ba5b5/src/fauxton/app/addons/replication/views.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/replication/views.js b/src/fauxton/app/addons/replication/views.js
index bd3daa1..f4b96fd 100644
--- a/src/fauxton/app/addons/replication/views.js
+++ b/src/fauxton/app/addons/replication/views.js
@@ -11,303 +11,285 @@
 // the License.
 
 define([
-  "app",
-  "api",
-  "addons/replication/resources"
+       "app",
+       "api",
+       "modules/fauxton/components",
+       "addons/replication/resources"
 ],
-function(app, FauxtonAPI, replication) {
+function(app, FauxtonAPI, Components, replication) {
   var View = {},
-			Events ={},
-			pollingInfo ={
-        rate: 5,
-        intervalId: null
-      };
+  Events ={},
+  pollingInfo ={
+    rate: 5,
+    intervalId: null
+  };
 
   _.extend(Events, Backbone.Events);
-  
-// NOTES: http://wiki.apache.org/couchdb/Replication
 
-// Replication form view is huge
-// -----------------------------------
-// afterRender: autocomplete on the target input field
-// beforeRender:  add the status table
-// disableFields:  disable non active fields on submit 
-// enableFields:  enable field when radio btns are clicked
-// establish:  get the DB list for autocomplete
-// formValidation:  make sure fields aren't empty
-// showProgress:  make a call to active_tasks model and show only replication types.  Poll every 5 seconds. (make this it's own view)
-// startReplication:  saves to the model, starts replication
-// submit:  form submit handler
-// swapFields:  change to and from target
-// toggleAdvancedOptions:  toggle advanced
+  // NOTES: http://wiki.apache.org/couchdb/Replication
+
+  // Replication form view is huge
+  // -----------------------------------
+  // afterRender: autocomplete on the target input field
+  // beforeRender:  add the status table
+  // disableFields:  disable non active fields on submit 
+  // enableFields:  enable field when radio btns are clicked
+  // establish:  get the DB list for autocomplete
+  // formValidation:  make sure fields aren't empty
+  // showProgress:  make a call to active_tasks model and show only replication types.  Poll every 5 seconds. (make this it's own view)
+  // startReplication:  saves to the model, starts replication
+  // submit:  form submit handler
+  // swapFields:  change to and from target
+  // toggleAdvancedOptions:  toggle advanced
 
   View.ReplicationForm = FauxtonAPI.View.extend({
-		template: "addons/replication/templates/form",
-		events:  {
-			"submit #replication": "validate",
-			"click .btn-group .btn": "showFields",
-			"click .swap": "swapFields",
-			"click .options": "toggleAdvancedOptions"
-		},
-		initialize: function(options){
-			this.status = options.status;
-			this.selectedDB = options.selectedDB;
-			this.newRepModel = new replication.Replicate({});
-		},
-		afterRender: function(){
-			var dbLimit = 30;
-      var ajaxReq;
-      //re-using what we have on DB search
-      this.$el.find("input#to_name").typeahead({
-        source: function(query, process) {
-          var url = [
-            app.host,
-            "/_all_dbs?startkey=%22",
-            query,
-            "%22&endkey=%22",
-            query,
-            "\u9999%22&limit=",
-            dbLimit
-          ].join('');
-          if (ajaxReq) ajaxReq.abort();
-          ajaxReq = $.ajax({
-            url: url,
-            dataType: 'json',
-            success: function(data) {
-              process(data);
-            }
-          });
-        }
+    template: "addons/replication/templates/form",
+    events:  {
+      "submit #replication": "validate",
+      "click .btn-group .btn": "showFields",
+      "click .swap": "swapFields",
+      "click .options": "toggleAdvancedOptions"
+    },
+    initialize: function(options){
+      this.status = options.status;
+      this.selectedDB = options.selectedDB;
+      this.newRepModel = new replication.Replicate({});
+    },
+    afterRender: function(){
+      this.dbSearchTypeahead = new Components.DbSearchTypeahead({
+        dbLimit: 30,
+        el: "input#to_name"
       });
 
-		},
+      this.dbSearchTypeahead.render();
 
-		beforeRender:  function(){
-		this.insertView("#replicationStatus", new View.ReplicationList({
-			collection: this.status
-		}));
-		},
-		cleanup: function(){
-			clearInterval(pollingInfo.intervalId);
-		},
-		enableFields: function(){
-			this.$el.find('input','select').attr('disabled',false);
-		},
-		disableFields: function(){
-				this.$el.find('input:hidden','select:hidden').attr('disabled',true);
-		},
-		showFields: function(e){
-			var $currentTarget = this.$(e.currentTarget),
-					targetVal = $currentTarget.val();
+    },
 
-			if (targetVal === "local"){
-				$currentTarget.parents('.form_set').addClass('local');
-			}else{
-				$currentTarget.parents('.form_set').removeClass('local');
-			}
-		},
-		establish: function(){
-			return [ this.collection.fetch(), this.status.fetch()];
-		},
-		validate: function(e){
-			e.preventDefault();
-			var notification;
-			if (this.formValidation()){
-					notification = FauxtonAPI.addNotification({
-						msg: "Please enter every field.",
-						type: "error",
-						clear: true
-					});
-			}else if (this.$('input#to_name').is(':visible') && !this.$('input[name=create_target]').is(':checked')){
-				var alreadyExists = this.collection.where({"name":this.$('input#to_name').val()});
-				if (alreadyExists.length === 0){
-					notification = FauxtonAPI.addNotification({
-						msg: "This database doesn't exist. Check create target if you want to create it.",
-						type: "error",
-						clear: true
-					});
-				}
-			}else{
-				this.submit(e);
-			}
-		},
-		formValidation: function(e){
-			var $remote = this.$el.find('input:visible'),
+    beforeRender:  function(){
+      this.insertView("#replicationStatus", new View.ReplicationList({
+        collection: this.status
+      }));
+    },
+    cleanup: function(){
+      clearInterval(pollingInfo.intervalId);
+    },
+    enableFields: function(){
+      this.$el.find('input','select').attr('disabled',false);
+    },
+    disableFields: function(){
+      this.$el.find('input:hidden','select:hidden').attr('disabled',true);
+    },
+    showFields: function(e){
+      var $currentTarget = this.$(e.currentTarget),
+      targetVal = $currentTarget.val();
+
+      if (targetVal === "local"){
+        $currentTarget.parents('.form_set').addClass('local');
+      }else{
+        $currentTarget.parents('.form_set').removeClass('local');
+      }
+    },
+    establish: function(){
+      return [ this.collection.fetch(), this.status.fetch()];
+    },
+    validate: function(e){
+      e.preventDefault();
+      var notification;
+      if (this.formValidation()){
+        notification = FauxtonAPI.addNotification({
+          msg: "Please enter every field.",
+          type: "error",
+          clear: true
+        });
+      }else if (this.$('input#to_name').is(':visible') && !this.$('input[name=create_target]').is(':checked')){
+        var alreadyExists = this.collection.where({"name":this.$('input#to_name').val()});
+        if (alreadyExists.length === 0){
+          notification = FauxtonAPI.addNotification({
+            msg: "This database doesn't exist. Check create target if you want to create it.",
+            type: "error",
+            clear: true
+          });
+        }
+      }else{
+        this.submit(e);
+      }
+    },
+    formValidation: function(e){
+      var $remote = this.$el.find('input:visible'),
       error = false;
       for(var i=0; i<$remote.length; i++){
-				if ($remote[i].value =="http://" || $remote[i].value ===""){
-					error = true;
-				}
+        if ($remote[i].value =="http://" || $remote[i].value ===""){
+          error = true;
+        }
       }
-			return error;
-		},
-		serialize: function(){
-			return {
-				databases:  this.collection.toJSON(),
-				selectedDB: this.selectedDB
-			};
-		},
-		startReplication: function(json){
-			var that = this;
-			this.newRepModel.save(json,{
-				success: function(resp){
-					var notification = FauxtonAPI.addNotification({
-						msg: "Replication from "+resp.get('source')+" to "+ resp.get('target')+" has begun.",
-						type: "success",
-						clear: true
-					});
-					that.updateButtonText(false);
-					Events.trigger('update:tasks');
-				},
-				error: function(model, xhr, options){
-					var errorMessage = JSON.parse(xhr.responseText);
-					var notification = FauxtonAPI.addNotification({
-						msg: errorMessage.reason,
-						type: "error",
-						clear: true
-					});
-					that.updateButtonText(false);
-				}
-			});
-			this.enableFields();
-		},		
-		updateButtonText: function(wait){
-			var $button = this.$('#replication button[type=submit]');
-			if(wait){
-				$button.text('Starting replication...').attr('disabled', true);
-			} else {
-				$button.text('Replication').attr('disabled', false);
-			}
-		},
-		submit: function(e){
-			this.disableFields(); 
-			var formJSON = {};
-			_.map(this.$(e.currentTarget).serializeArray(), function(formData){
-				if(formData.value !== ''){
-					formJSON[formData.name] = (formData.value ==="true"? true: formData.value.replace(/\s/g, '').toLowerCase());
-
-				}
-			});
+      return error;
+    },
+    serialize: function(){
+      return {
+        databases:  this.collection.toJSON(),
+        selectedDB: this.selectedDB
+      };
+    },
+    startReplication: function(json){
+      var that = this;
+      this.newRepModel.save(json,{
+        success: function(resp){
+          var notification = FauxtonAPI.addNotification({
+            msg: "Replication from "+resp.get('source')+" to "+ resp.get('target')+" has begun.",
+            type: "success",
+            clear: true
+          });
+          that.updateButtonText(false);
+          Events.trigger('update:tasks');
+        },
+        error: function(model, xhr, options){
+          var errorMessage = JSON.parse(xhr.responseText);
+          var notification = FauxtonAPI.addNotification({
+            msg: errorMessage.reason,
+            type: "error",
+            clear: true
+          });
+          that.updateButtonText(false);
+        }
+      });
+      this.enableFields();
+    },		
+    updateButtonText: function(wait){
+      var $button = this.$('#replication button[type=submit]');
+      if(wait){
+        $button.text('Starting replication...').attr('disabled', true);
+      } else {
+        $button.text('Replication').attr('disabled', false);
+      }
+    },
+    submit: function(e){
+      this.disableFields(); 
+      var formJSON = {};
+      _.map(this.$(e.currentTarget).serializeArray(), function(formData){
+        if(formData.value !== ''){
+          formJSON[formData.name] = (formData.value ==="true"? true: formData.value.replace(/\s/g, '').toLowerCase());
+        }
+      });
 
-			this.updateButtonText(true);
-			this.startReplication(formJSON);
-		},	
-		swapFields: function(e){
-			e.preventDefault();
-			//WALL O' VARIABLES
-			var $fromSelect = this.$('#from_name'),
-					$toSelect = this.$('#to_name'),
-					$toInput = this.$('#to_url'),
-					$fromInput = this.$('#from_url'),
-					fromSelectVal = $fromSelect.val(),
-					fromInputVal = $fromInput.val(),
-					toSelectVal = $toSelect.val(),
-					toInputVal = $toInput.val();
+      this.updateButtonText(true);
+      this.startReplication(formJSON);
+    },	
+    swapFields: function(e){
+      e.preventDefault();
+      //WALL O' VARIABLES
+      var $fromSelect = this.$('#from_name'),
+          $toSelect = this.$('#to_name'),
+          $toInput = this.$('#to_url'),
+          $fromInput = this.$('#from_url'),
+          fromSelectVal = $fromSelect.val(),
+          fromInputVal = $fromInput.val(),
+          toSelectVal = $toSelect.val(),
+          toInputVal = $toInput.val();
 
-					$fromSelect.val(toSelectVal);
-					$toSelect.val(fromSelectVal);
+      $fromSelect.val(toSelectVal);
+      $toSelect.val(fromSelectVal);
 
-					$fromInput.val(toInputVal);
-					$toInput.val(fromInputVal);
-		}
+      $fromInput.val(toInputVal);
+      $toInput.val(fromInputVal);
+    }
   });
 
 
-View.ReplicationList = FauxtonAPI.View.extend({
-	tagName: "ul",
-	initialize:  function(){
-		Events.bind('update:tasks', this.establish, this);
-		this.listenTo(this.collection, "reset", this.render);
-		this.$el.prepend("<li class='header'><h4>Active Replication Tasks</h4></li>");
-	},
-	establish: function(){
-		return [this.collection.fetch({reset: true})];
-	},
-	setPolling: function(){
-		var that = this;
-		this.cleanup();
-		pollingInfo.intervalId = setInterval(function() {
-			that.establish();
-		}, pollingInfo.rate*1000);
-	},
-  cleanup: function(){
-		clearInterval(pollingInfo.intervalId);
-  },
-	beforeRender:  function(){
-    this.collection.forEach(function(item) {
-      this.insertView(new View.replicationItem({ 
-        model: item
-      }));
-    }, this);
-	},
-	showHeader: function(){
-		if (this.collection.length > 0){
-			this.$el.parent().addClass('showHeader');
-		} else {
-			this.$el.parent().removeClass('showHeader');
-		}
-	},
-	afterRender: function(){
-		this.showHeader();
-		this.setPolling();
-	}
-});
+  View.ReplicationList = FauxtonAPI.View.extend({
+    tagName: "ul",
+    initialize:  function(){
+      Events.bind('update:tasks', this.establish, this);
+      this.listenTo(this.collection, "reset", this.render);
+      this.$el.prepend("<li class='header'><h4>Active Replication Tasks</h4></li>");
+    },
+    establish: function(){
+      return [this.collection.fetch({reset: true})];
+    },
+    setPolling: function(){
+      var that = this;
+      this.cleanup();
+      pollingInfo.intervalId = setInterval(function() {
+        that.establish();
+      }, pollingInfo.rate*1000);
+    },
+    cleanup: function(){
+      clearInterval(pollingInfo.intervalId);
+    },
+    beforeRender:  function(){
+      this.collection.forEach(function(item) {
+        this.insertView(new View.replicationItem({ 
+          model: item
+        }));
+      }, this);
+    },
+    showHeader: function(){
+      if (this.collection.length > 0){
+        this.$el.parent().addClass('showHeader');
+      } else {
+        this.$el.parent().removeClass('showHeader');
+      }
+    },
+    afterRender: function(){
+      this.showHeader();
+      this.setPolling();
+    }
+  });
 
-	//make this a table row item.
-	View.replicationItem = FauxtonAPI.View.extend({
-		tagName: "li",
-		className: "row",
-		template: "addons/replication/templates/progress",
-		events: {
-			"click .cancel": "cancelReplication"
-		},
-		initialize: function(){
-			this.newRepModel = new replication.Replicate({});
-		},
-		establish: function(){
-			return [this.model.fetch()];
-		},
-		cancelReplication: function(e){
-			//need to pass "cancel": true with source & target
-			var $currentTarget = this.$(e.currentTarget),
-					repID = $currentTarget.attr('data-rep-id');
-			this.newRepModel.save({
-				"replication_id": repID,
-				"cancel": true
-			},
-			{
-				success: function(model, xhr, options){
-					var notification = FauxtonAPI.addNotification({
-						msg: "Replication stopped.",
-						type: "success",
-						clear: true
-					});
-				},
-				error: function(model, xhr, options){
-					var errorMessage = JSON.parse(xhr.responseText);
-					var notification = FauxtonAPI.addNotification({
-						msg: errorMessage.reason,
-						type: "error",
-						clear: true
-					});
-				}
-			});
-		},
-		afterRender: function(){
-			if (this.model.get('continuous')){
-				this.$el.addClass('continuous');
-			}
-		},
-		serialize: function(){
-			return {
-				progress:  this.model.get('progress'),
-				target: this.model.get('target'),
-				source: this.model.get('source'),
-				continuous: this.model.get('continuous'),
-				repid: this.model.get('replication_id')
-			};
-		}
-	});
+  //make this a table row item.
+  View.replicationItem = FauxtonAPI.View.extend({
+    tagName: "li",
+    className: "row",
+    template: "addons/replication/templates/progress",
+    events: {
+      "click .cancel": "cancelReplication"
+    },
+    initialize: function(){
+      this.newRepModel = new replication.Replicate({});
+    },
+    establish: function(){
+      return [this.model.fetch()];
+    },
+    cancelReplication: function(e){
+      //need to pass "cancel": true with source & target
+      var $currentTarget = this.$(e.currentTarget),
+      repID = $currentTarget.attr('data-rep-id');
+      this.newRepModel.save({
+        "replication_id": repID,
+        "cancel": true
+      },
+      {
+        success: function(model, xhr, options){
+          var notification = FauxtonAPI.addNotification({
+            msg: "Replication stopped.",
+            type: "success",
+            clear: true
+          });
+        },
+        error: function(model, xhr, options){
+          var errorMessage = JSON.parse(xhr.responseText);
+          var notification = FauxtonAPI.addNotification({
+            msg: errorMessage.reason,
+            type: "error",
+            clear: true
+          });
+        }
+      });
+    },
+    afterRender: function(){
+      if (this.model.get('continuous')){
+        this.$el.addClass('continuous');
+      }
+    },
+    serialize: function(){
+      return {
+        progress:  this.model.get('progress'),
+        target: this.model.get('target'),
+        source: this.model.get('source'),
+        continuous: this.model.get('continuous'),
+        repid: this.model.get('replication_id')
+      };
+    }
+  });
 
   return View;
 });

http://git-wip-us.apache.org/repos/asf/couchdb/blob/b14ba5b5/src/fauxton/app/modules/databases/views.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/modules/databases/views.js b/src/fauxton/app/modules/databases/views.js
index ef75841..749f79c 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/paginate",
-  "api"
+  "modules/fauxton/components",
+  "api",
 ],
 
-function(app, Paginate, FauxtonAPI) {
+function(app, Components, FauxtonAPI) {
   var Views = {};
 
   Views.Item = FauxtonAPI.View.extend({
@@ -83,7 +83,7 @@ function(app, Paginate, FauxtonAPI) {
         }));
       }, this);
 
-      this.insertView("#database-pagination", new Paginate.Pagination({
+      this.insertView("#database-pagination", new Components.Pagination({
         page: this.page,
         perPage: this.perPage,
         total: this.collection.length,
@@ -98,30 +98,12 @@ function(app, Paginate, FauxtonAPI) {
     },
 
     afterRender: function() {
-      var dbLimit = this.dbLimit;
-      var ajaxReq;
-
-      this.$el.find("input.search-query").typeahead({
-        source: function(query, process) {
-          var url = [
-            app.host,
-            "/_all_dbs?startkey=%22",
-            query,
-            "%22&endkey=%22",
-            query,
-            "\u9999%22&limit=",
-            dbLimit
-          ].join('');
-          if (ajaxReq) ajaxReq.abort();
-          ajaxReq = $.ajax({
-            url: url,
-            dataType: 'json',
-            success: function(data) {
-              process(data);
-            }
-          });
-        }
+      this.dbSearchTypeahead = new Components.DbSearchTypeahead({
+        dbLimit: this.dbLimit,
+        el: "input.search-query"
       });
+
+      this.dbSearchTypeahead.render();
     },
 
     selectAll: function(evt){

http://git-wip-us.apache.org/repos/asf/couchdb/blob/b14ba5b5/src/fauxton/app/modules/documents/views.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/modules/documents/views.js b/src/fauxton/app/modules/documents/views.js
index 40f610e..36c6eeb 100644
--- a/src/fauxton/app/modules/documents/views.js
+++ b/src/fauxton/app/modules/documents/views.js
@@ -14,7 +14,7 @@ define([
        "app",
 
        "api",
-       "modules/fauxton/paginate",
+       "modules/fauxton/components",
 
        "modules/documents/resources",
        "modules/pouchdb/base",
@@ -30,7 +30,7 @@ define([
 
 ],
 
-function(app, FauxtonAPI, Paginate, Documents, pouchdb, Codemirror, JSHint, resizeColumns) {
+function(app, FauxtonAPI, Components, Documents, pouchdb, Codemirror, JSHint, resizeColumns) {
   var Views = {};
 
   Views.Tabs = FauxtonAPI.View.extend({
@@ -520,7 +520,7 @@ function(app, FauxtonAPI, Paginate, Documents, pouchdb, Codemirror, JSHint, resi
     addPagination: function () {
       var collection = this.collection;
 
-      this.pagination = new Paginate.IndexPagination({
+      this.pagination = new Components.IndexPagination({
         collection: this.collection,
         scrollToSelector: '#dashboard-content',
         previousUrlfn: function () {

http://git-wip-us.apache.org/repos/asf/couchdb/blob/b14ba5b5/src/fauxton/app/modules/fauxton/components.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/modules/fauxton/components.js b/src/fauxton/app/modules/fauxton/components.js
new file mode 100644
index 0000000..10e08dc
--- /dev/null
+++ b/src/fauxton/app/modules/fauxton/components.js
@@ -0,0 +1,138 @@
+// 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 Components = app.module();
+
+  Components.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
+      };
+    }
+  });
+
+  Components.IndexPagination = FauxtonAPI.View.extend({
+    template: "templates/fauxton/index_pagination",
+    events: {
+      "click a": 'scrollTo',
+      "click a#next": 'nextClicked',
+      "click a#previous": 'previousClicked'
+    },
+
+    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();
+      FauxtonAPI.navigate(this.previousUrlfn(), {trigger: false});
+      FauxtonAPI.triggerRouteEvent('paginate', 'previous');
+    },
+
+    nextClicked: function (event) {
+      event.preventDefault();
+      this.previousIds.push(this.collection.first().id);
+      FauxtonAPI.navigate(this.nextUrlfn(), {trigger: false});
+      FauxtonAPI.triggerRouteEvent('paginate', 'next');
+    },
+
+    serialize: function () {
+      return {
+        canShowNextfn: this.canShowNextfn,
+        canShowPreviousfn: this.canShowPreviousfn,
+      };
+    }
+
+  });
+
+  //TODO allow more of the typeahead options.
+  //Current this just does what we need but we
+  //need to support the other typeahead options.
+  Components.Typeahead = FauxtonAPI.View.extend({
+
+    initialize: function (options) {
+      this.source = options.source;
+      _.bindAll(this);
+    },
+
+    afterRender: function () {
+      this.$el.typeahead({
+        source: this.source
+      });
+    }
+
+  });
+
+  Components.DbSearchTypeahead = Components.Typeahead.extend({
+    initialize: function (options) {
+      this.dbLimit = options.dbLimit || 30;
+      _.bindAll(this);
+    },
+    source: function(query, process) {
+      var url = [
+        app.host,
+        "/_all_dbs?startkey=%22",
+        query,
+        "%22&endkey=%22",
+        query,
+        "\u9999%22&limit=",
+        this.dbLimit
+      ].join('');
+
+      if (this.ajaxReq) { this.ajaxReq.abort(); }
+
+      this.ajaxReq = $.ajax({
+        url: url,
+        dataType: 'json',
+        success: function(data) {
+          process(data);
+        }
+      });
+    }
+  });
+
+  return Components;
+});
+

http://git-wip-us.apache.org/repos/asf/couchdb/blob/b14ba5b5/src/fauxton/app/modules/fauxton/paginate.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/modules/fauxton/paginate.js b/src/fauxton/app/modules/fauxton/paginate.js
deleted file mode 100644
index 074fb47..0000000
--- a/src/fauxton/app/modules/fauxton/paginate.js
+++ /dev/null
@@ -1,92 +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",
-       // 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'
-    },
-
-    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();
-      FauxtonAPI.navigate(this.previousUrlfn(), {trigger: false});
-      FauxtonAPI.triggerRouteEvent('paginate', 'previous');
-    },
-
-    nextClicked: function (event) {
-      event.preventDefault();
-      this.previousIds.push(this.collection.first().id);
-      FauxtonAPI.navigate(this.nextUrlfn(), {trigger: false});
-      FauxtonAPI.triggerRouteEvent('paginate', 'next');
-    },
-
-    serialize: function () {
-      return {
-        canShowNextfn: this.canShowNextfn,
-        canShowPreviousfn: this.canShowPreviousfn,
-      };
-    }
-
-  });
-
-  return Paginate;
-});
-