You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ro...@apache.org on 2015/02/16 13:36:44 UTC

fauxton commit: updated refs/heads/master to 92834ea

Repository: couchdb-fauxton
Updated Branches:
  refs/heads/master 39a6f3387 -> 92834eae0


Centralize URLs
- a more centralized system for retrieving, setting, and navigating URLs.
- Currently urls needed for Fauxton depend on the url specified within
each model. But a URL is essentially a string, so my proposal is that we
re-write the retrieval for each URL into one file.

- This should help when deciding what kind of URL a developer would need
 for each specific task, and also help in debugging if they are working
with URLs.

Jira: 2566


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

Branch: refs/heads/master
Commit: 92834eae02eadc361de3a21ee1079d8f47af6492
Parents: 39a6f33
Author: Michelle Phung <mi...@gmail.com>
Authored: Thu Nov 20 16:56:51 2014 +0200
Committer: Robert Kowalski <ro...@apache.org>
Committed: Mon Feb 16 13:35:28 2015 +0100

----------------------------------------------------------------------
 app/addons/compaction/routes.js                 |  2 +-
 .../nightwatch/compactAndCleanIsPresent.js      | 30 +++++++
 app/addons/cors/components.react.jsx            | 15 +++-
 app/addons/databases/base.js                    | 43 +++++++++-
 app/addons/databases/resources.js               | 12 ++-
 app/addons/databases/views.js                   |  2 +-
 app/addons/documents/base.js                    | 90 ++++++++++++++++++++
 app/addons/documents/resources.js               | 27 +++---
 app/addons/documents/routes-documents.js        | 13 ++-
 app/addons/documents/shared-resources.js        | 29 +++----
 app/addons/documents/shared-routes.js           |  7 +-
 app/addons/documents/shared-views.js            | 67 +++++++++------
 app/addons/documents/templates/changes.html     |  2 +-
 .../documents/templates/design_doc_menu.html    | 32 +++----
 .../documents/templates/index_menu_item.html    |  6 +-
 app/addons/documents/templates/sidebar.html     | 10 +--
 app/addons/documents/tests/actionsSpec.js       |  3 +-
 .../tests/nightwatch/editDocumentsFromView.js   |  2 +-
 app/addons/documents/views-changes.js           |  5 +-
 app/addons/documents/views-doceditor.js         |  6 +-
 app/addons/documents/views.js                   |  4 +-
 app/addons/fauxton/components.js                | 21 ++---
 app/addons/replication/base.js                  |  7 ++
 app/core/api.js                                 | 38 +++++++++
 app/core/tests/apiSpec.js                       | 50 +++++++++++
 25 files changed, 402 insertions(+), 121 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/compaction/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/compaction/routes.js b/app/addons/compaction/routes.js
index 2b7414c..6d39524 100644
--- a/app/addons/compaction/routes.js
+++ b/app/addons/compaction/routes.js
@@ -67,7 +67,7 @@ function(app, FauxtonAPI, Compaction, Databases, BaseRoute) {
 
     cleanup: function () {
       if (this.pageContent) {
-        this.removeView('#dashboard-upper-content');
+        this.removeView('#dashboard-content');
       }
       if (this.leftheader) {
         this.removeView('#breadcrumbs');

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/compaction/tests/nightwatch/compactAndCleanIsPresent.js
----------------------------------------------------------------------
diff --git a/app/addons/compaction/tests/nightwatch/compactAndCleanIsPresent.js b/app/addons/compaction/tests/nightwatch/compactAndCleanIsPresent.js
new file mode 100644
index 0000000..13970c5
--- /dev/null
+++ b/app/addons/compaction/tests/nightwatch/compactAndCleanIsPresent.js
@@ -0,0 +1,30 @@
+// 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 = {
+  'Compact and Clean Menu shows up' : function (client) {
+    var waitTime = 10000,
+        newDatabaseName = client.globals.testDatabaseName,
+        baseUrl = client.globals.test_settings.launch_url;
+
+    client
+      .loginToGUI()
+      .url(baseUrl)
+
+      //navigate to 'Compact & Clean' view
+      .clickWhenVisible('#dashboard-content a[href="#/database/' + newDatabaseName + '/_all_docs"]')
+      .clickWhenVisible('#docLink_compact')
+      .waitForElementVisible('#compact-db', waitTime, false)
+      .waitForElementVisible('#cleanup-views', waitTime, false)
+      .end();
+  }
+};

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/cors/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/cors/components.react.jsx b/app/addons/cors/components.react.jsx
index 1de76c1..583c8c0 100644
--- a/app/addons/cors/components.react.jsx
+++ b/app/addons/cors/components.react.jsx
@@ -231,8 +231,15 @@ define([
     },
 
     enableCorsChange: function (event) {
-      if (this.state.corsEnabled && !_.isEmpty(this.state.origins) && !this.state.isAllOrigins) {
-        var result = window.confirm('Are you sure? Disabling CORS will overwrite your specific origin domains.');
+      if (this.state.corsEnabled && !_.isEmpty(this.state.origins) ) {
+        var msg = FauxtonAPI.getExtensions('cors:disableCorsPrompt');
+        if (_.isUndefined(msg[0])) {
+          msg =  'Are you sure? Disabling CORS will overwrite your specific origin domains.';
+        } else {
+          msg = msg[0];
+        }
+
+        var result = window.confirm(msg);
         if (!result) { return; }
       }
 
@@ -273,11 +280,11 @@ define([
 
     getCorsNotice: function () {
       var msg = FauxtonAPI.getExtensions('cors:notice');
-      if (_.isUndefined(msg)) {
+      if (_.isUndefined(msg[0])) {
         return 'Cross-Origin Resource Sharing (CORS) lets you connect to remote servers directly from the browser, so you can host browser-based apps on static pages and talk directly with CouchDB to load your data.';
       }
 
-      return msg;
+      return msg[0];
     },
 
     render: function () {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/databases/base.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/base.js b/app/addons/databases/base.js
index e1aa846..7e30fec 100644
--- a/app/addons/databases/base.js
+++ b/app/addons/databases/base.js
@@ -39,8 +39,49 @@ function(app, FauxtonAPI, Databases, Views) {
     var name = _.isObject(database) ? database.id : database,
         dbname = app.utils.safeURLName(name);
 
-    return ["/database/", dbname, "/_all_docs?limit=" + Databases.DocLimit].join('');
+    return ['/database/', dbname, '/_all_docs?limit=' + Databases.DocLimit].join('');
   };
 
+  FauxtonAPI.registerUrls('changes', {
+    server: function (id, query) {
+      return app.host + '/' + id + '/_changes' + query;
+
+    },
+    app: function (id, query) {
+      return '/database/' + id + '/_changes' + query;
+    },
+
+    apiurl: function (id, query) {
+        return window.location.origin + '/' + id + '/_changes' + query;
+    }
+  });
+
+  FauxtonAPI.registerUrls('allDBs', {
+    app: function(){
+      return '_all_dbs' ;
+    }
+  });
+
+  FauxtonAPI.registerUrls('databaseBaseURL', {
+    server: function (database) {
+      return window.location.origin + '/' + database;
+    },
+    app: function (database) {
+      return  '/database/' + database;
+    }
+  });
+
+  FauxtonAPI.registerUrls('permissions', {
+    server: function (id) {
+      return app.host + '/' + id + '/permissions';
+    },
+    app: function (id) {
+      return '/database/' + id + '/permissions';
+    },
+    apiurl: function (id) {
+      return window.location.origin + '/_api/v2/db/'+ id + '/_security' ;
+    }
+  });
+
   return Databases;
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/databases/resources.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/resources.js b/app/addons/databases/resources.js
index 9483c6e..f248e9b 100644
--- a/app/addons/databases/resources.js
+++ b/app/addons/databases/resources.js
@@ -57,9 +57,9 @@ function(app, FauxtonAPI, Documents) {
       } else if (context === "apiurl") { 
         return window.location.origin + "/database/" + this.safeID() + "/_all_docs";
       } else if (context === "changes") {
-        return "/database/" + this.safeID() + "/_changes?descending=true&limit=100&include_docs=true";
+        return FauxtonAPI.urls('changes', 'app', this.safeID(), '?descending=true&limit=100&include_docs=true');
       } else if (context === "changes-apiurl") { 
-        return window.location.origin + "/" + this.safeID() + "/_changes?descending=true&limit=100&include_docs=true";
+        return FauxtonAPI.urls('changes', 'apiurl' , this.safeID(), '?descending=true&limit=100&include_docs=true');
       } else if (context === "app") {
         return "/database/" + this.safeID();
       } else {
@@ -96,12 +96,10 @@ function(app, FauxtonAPI, Documents) {
       if (this.params) {
         query = "?" + $.param(this.params);
       }
-      if (context === "apiurl") { 
-        return window.location.origin + '/' + this.database.safeID() + '/_changes' + query;
-      } else {
 
-      return app.host + '/' + this.database.safeID() + '/_changes' + query;
-      }
+     if (!context) { context = 'server';}
+
+      return FauxtonAPI.urls('changes', context, this.database.safeID(), query);
     },
 
     parse: function (resp) {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/databases/views.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/views.js b/app/addons/databases/views.js
index 42de806..ded4acb 100644
--- a/app/addons/databases/views.js
+++ b/app/addons/databases/views.js
@@ -147,7 +147,7 @@ function(app, Components, FauxtonAPI, Databases) {
           // TODO: switch to using a model, or Databases.databaseUrl()
           // Neither of which are in scope right now
           // var db = new Database.Model({id: dbname});
-          var url = ['/database/', app.utils.safeURLName(dbname), '/_all_docs'].join('');
+          var url = FauxtonAPI.urls('allDocs', 'app', app.utils.safeURLName(dbname));
           FauxtonAPI.navigate(url);
       } else {
         FauxtonAPI.addNotification({

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/base.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/base.js b/app/addons/documents/base.js
index cb68a31..5c74fa2 100644
--- a/app/addons/documents/base.js
+++ b/app/addons/documents/base.js
@@ -20,5 +20,95 @@ define([
 ],
 
 function(app, FauxtonAPI, Documents) {
+
+  FauxtonAPI.registerUrls( 'allDocs', {
+    server: function (id, query) {
+      return app.host + '/' + id + '/_all_docs' + query;
+    },
+    app: function (id, query) {
+      return 'database/' + id + '/_all_docs' + query;
+    },
+    apiurl: function (id, query) {
+      return window.location.origin + '/' + id + '/_all_docs' + query;
+    }
+  });
+
+  FauxtonAPI.registerUrls( 'designDocs', {
+    server: function (id, designDoc) {
+      return app.host + '/' + id + '/' + designDoc + '/_info';
+    },
+
+    app: function (id, designDoc) {
+      return 'database/' + id + '/_design/' + app.utils.safeURLName(designDoc) + '/_info';
+    },
+
+    apiurl: function (id, designDoc) {
+      return window.location.origin + '/' + id + '/' + designDoc + '/_info';
+    }
+  });
+
+  FauxtonAPI.registerUrls( 'view', {
+    server: function (id, designDoc, viewName) {
+      return app.host + '/' + id + '/_design/' + designDoc + '/_view/' + viewName;
+    },
+
+    app: function (id, designDoc) {
+      return 'database/' + id + '/_design/' + designDoc + '/_view/';
+    },
+
+    apiurl: function (id, designDoc, viewName) {
+      return window.location.origin + '/' + id + '/_design/' + designDoc + '/_view/' + viewName;
+    },
+
+    showNewlySavedView: function (database, designDocs, viewName) {
+      return '/database/' + database +'/' + designDocs + '/_view/' + viewName;
+    },
+
+    fragment: function (database, designDocs, viewName) {
+      return 'database/' + database + designDocs + '/_view/' + viewName;
+    }
+  });
+
+  FauxtonAPI.registerUrls( 'document', {
+    server: function (database, doc) {
+      return app.host + '/' + database + '/' + doc;
+    },
+
+    app: function (database, doc) {
+      return '/database/' + database + '/' + doc;
+    },
+
+    apiurl: function (database, doc) {
+      return window.location.origin + '/' + database + '/' + doc;
+    },
+
+    'web-index': function (database, doc) {
+      return '/database/' + database + '/' + doc;
+    }
+  });
+
+  FauxtonAPI.registerUrls( 'new', {
+    newDocument: function (database) {
+      return '/database/' + database + '/new' ;
+    },
+
+    newView: function (database) {
+      return '/database/' + database + '/new_view' ;
+    },
+
+    addView: function (database, ddoc) {
+      return '/database/' + database + '/new_view/' + ddoc;
+    }
+  });
+
+  FauxtonAPI.registerUrls( 'base', {
+    server: function (database) {
+      return app.host + '/' + database + '/' ;
+    },
+
+    app: function (database) {
+      return '/database/' + database + '/' ;
+    },
+  });
   return Documents;
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/resources.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/resources.js b/app/addons/documents/resources.js
index 660a52f..5867038 100644
--- a/app/addons/documents/resources.js
+++ b/app/addons/documents/resources.js
@@ -54,14 +54,12 @@ function(app, FauxtonAPI, Documents, PagingCollection) {
       this.database = options.database;
     },
 
-    url: function(context) {
-      if (context === "app") {
-        return this.database.url("app") + "/" + this.safeID() + '/_info';
-      } else if (context === "apiurl"){
-        return window.location.origin + "/" + this.database.safeID() + "/" + this.safeID() + '/_info';
-      } else {
-        return app.host + "/" + this.database.safeID() + "/" + this.safeID() + '/_info';
+    url: function (context) {
+      if (!context) {
+        context = 'server';
       }
+
+      return FauxtonAPI.urls('designDocs', context, this.database.safeID(), this.safeID());
     },
 
     // Need this to work around backbone router thinking _design/foo
@@ -216,11 +214,13 @@ function(app, FauxtonAPI, Documents, PagingCollection) {
       } else if (context === "apiurl"){
         startOfUrl = window.location.origin;
       }
-      var design = app.utils.safeURLName(this.design),
-          view = app.utils.safeURLName(this.view);
 
-      var url = [startOfUrl, this.database.safeID(), "_design", design, this.idxType, view];
-      return url.join("/") + query;
+      var database = this.database.safeID(),
+          design = app.utils.safeURLName(this.design),
+          view = app.utils.safeURLName(this.view),
+          url = FauxtonAPI.urls('view', 'server', database, design, view);
+
+      return url + query;
     },
 
     url: function () {
@@ -385,7 +385,7 @@ function(app, FauxtonAPI, Documents, PagingCollection) {
       links: [{
         title: 'Replicate Database',
         icon: 'fonticon-replicate',
-        url: '#/replication/' + database.get('id')
+        url: FauxtonAPI.urls('replication', 'app', database.get('id'))
       },{
         title: 'Delete',
         icon: 'fonticon-trash',
@@ -402,8 +402,7 @@ function(app, FauxtonAPI, Documents, PagingCollection) {
   };
 
   Documents.getExtensionLinks = function (database) {
-    var newUrlPrefix = "#" + database.url('app');
-
+    var newUrlPrefix = '#' + FauxtonAPI.urls('databaseBaseURL', 'app', database.get('id'));
     var menuLinks = [{
       title: 'New Doc',
       url: newUrlPrefix + '/new',

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/routes-documents.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes-documents.js b/app/addons/documents/routes-documents.js
index b88ee22..5d5e2af 100644
--- a/app/addons/documents/routes-documents.js
+++ b/app/addons/documents/routes-documents.js
@@ -52,7 +52,7 @@ function(app, FauxtonAPI, BaseRoute, Documents, Changes, Index, DocEditor, Datab
         route: "tempFn",
         roles: ['fx_loggedIn']
       },
-      "database/:database/_design/:ddoc/metadata": {
+      "database/:database/_design/:ddoc/_info": {
         route: "designDocMetadata",
         roles: ['fx_loggedIn']
       },
@@ -86,7 +86,7 @@ function(app, FauxtonAPI, BaseRoute, Documents, Changes, Index, DocEditor, Datab
     initViews: function (dbName) {
       this.databaseName = dbName;
       this.database = new Databases.Model({id: this.databaseName});
-      this.allDatabases = new Databases.List();
+      this.allDatabases = this.getAllDatabases();
 
       this.createDesignDocsCollection();
 
@@ -98,12 +98,17 @@ function(app, FauxtonAPI, BaseRoute, Documents, Changes, Index, DocEditor, Datab
       this.addSidebar();
     },
 
+    getAllDatabases: function () {
+      return new Databases.List();  //getAllDatabases() can be overwritten instead of hard coded into initViews
+    },
+
     // this safely assumes the db name is valid
     onSelectDatabase: function (dbName) {
       this.cleanup();
       this.initViews(dbName);
 
-      FauxtonAPI.navigate('/database/' + app.utils.safeURLName(dbName) + '/_all_docs', {
+      var url = FauxtonAPI.urls('allDocs', 'app',  app.utils.safeURLName(dbName), '');
+      FauxtonAPI.navigate(url, {
         trigger: true
       });
 
@@ -502,7 +507,7 @@ function(app, FauxtonAPI, BaseRoute, Documents, Changes, Index, DocEditor, Datab
       this.rightHeader.hideQueryOptions();
 
       this.apiUrl = function () {
-        return [this.database.url("changes-apiurl"), this.database.documentation()];
+        return [FauxtonAPI.urls('changes', 'apiurl', this.database.id, ''), this.database.documentation()];
       };
     },
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/shared-resources.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/shared-resources.js b/app/addons/documents/shared-resources.js
index 2d086aa..a25532b 100644
--- a/app/addons/documents/shared-resources.js
+++ b/app/addons/documents/shared-resources.js
@@ -27,15 +27,10 @@ define([
       return FauxtonAPI.constants.DOC_URLS.GENERAL;
     },
     url: function(context) {
-      if (context === "app") {
-        return this.getDatabase().url("app") + "/" + this.safeID();
-      } else if (context === "web-index") {
-        return this.getDatabase().url("app") + "/" + app.utils.safeURLName(this.id);
-      } else if (context === "apiurl"){
-        return window.location.origin + "/" + this.getDatabase().safeID() + "/" + this.safeID();
-      } else {
-        return app.host + "/" + this.getDatabase().safeID() + "/" + this.safeID();
+      if (context === undefined) {
+        context = 'server';
       }
+      return FauxtonAPI.urls('document', context, this.getDatabase().safeID(), this.safeID());
     },
 
     initialize: function(_attrs, options) {
@@ -98,7 +93,9 @@ define([
     },
 
     getDdocView: function(view) {
-      if (!this.isDdoc() || !this.hasViews()) return false;
+      if (!this.isDdoc() || !this.hasViews()) {
+        return false;
+      }
 
       var doc = this.get('doc');
       if (doc) {
@@ -109,7 +106,9 @@ define([
     },
 
     setDdocView: function (view, map, reduce) {
-      if (!this.isDdoc()) return false;
+      if (!this.isDdoc()) {
+        return false;
+      }
       var views = this.get('views'),
         tempView = views[view] || {};
 
@@ -242,14 +241,10 @@ define([
       } else if (this.params) {
         query = "?" + $.param(this.params);
       }
-
-      if (context === 'app') {
-        return 'database/' + this.database.safeID() + "/_all_docs" + query;
-      } else if (context === "apiurl"){
-        return window.location.origin + "/" + this.database.safeID() + "/_all_docs" + query;
-      } else {
-        return app.host + "/" + this.database.safeID() + "/_all_docs" + query;
+      if (_.isUndefined(context)) {
+        context = 'server';
       }
+      return FauxtonAPI.urls('allDocs', context, this.database.safeID(), query);
     },
 
     url: function () {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/shared-routes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/shared-routes.js b/app/addons/documents/shared-routes.js
index df991cb..167e4bc 100644
--- a/app/addons/documents/shared-routes.js
+++ b/app/addons/documents/shared-routes.js
@@ -54,9 +54,12 @@ define([
     },
 
     getCrumbs: function (database) {
+      var name = _.isObject(database) ? database.id : database,
+        dbname = app.utils.safeURLName(name);
+
       return [
-        { "type": "back", "link": "/_all_dbs" },
-        { "name": database.id, "link": Databases.databaseUrl(database), className: "lookahead-tray-link" }
+        { "type": "back", "link": FauxtonAPI.urls('allDBs', 'app')},
+        { "name": database.id, "link": FauxtonAPI.urls('allDocs', 'app', dbname, '?limit=' + Databases.DocLimit), className: "lookahead-tray-link" }
       ];
     }
   });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/shared-views.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/shared-views.js b/app/addons/documents/shared-views.js
index 5c37225..8042d92 100644
--- a/app/addons/documents/shared-views.js
+++ b/app/addons/documents/shared-views.js
@@ -42,41 +42,51 @@ function(app, FauxtonAPI, Components, Documents, Databases) {
       var docLinks = FauxtonAPI.getExtensions('docLinks'),
           newLinks = FauxtonAPI.getExtensions('sidebar:newLinks'),
           addLinks = FauxtonAPI.getExtensions('sidebar:links'),
-          extensionList = FauxtonAPI.getExtensions('sidebar:list');
+          extensionList = FauxtonAPI.getExtensions('sidebar:list'),
+          safeDatabaseName = this.database.safeID(),
+          changesLink = '#' + FauxtonAPI.urls('changes', 'app', safeDatabaseName, ''),
+          permissionsLink = '#' + FauxtonAPI.urls('permissions', 'app', safeDatabaseName),
+          databaseUrl = FauxtonAPI.urls('allDocs', 'app', safeDatabaseName, ''),
+          db_url = FauxtonAPI.urls('allDocs', 'server', safeDatabaseName, ''),
+          base = FauxtonAPI.urls('base', 'app', safeDatabaseName);
+
       return {
-        changes_url: '#' + this.database.url('changes'),
-        permissions_url: '#' + this.database.url('app') + '/permissions',
-        db_url: '#' + this.database.url('index'),
+        changes_url: changesLink,
+        permissions_url: permissionsLink,
+        db_url: db_url,
+        database_url: '#' + databaseUrl,
         database: this.collection.database,
-        database_url: '#' + this.database.url('app'),
         docLinks: docLinks,
         addLinks: addLinks,
         newLinks: newLinks,
-        extensionList: extensionList > 0
+        extensionList: extensionList > 0,
+        databaseUrl: databaseUrl,
+        base: base
       };
     },
 
-    getNewButtonLinks: function () {
+    getNewButtonLinks: function () {  //these are links for the sidebar '+' on All Docs and All Design Docs
       var database = this.collection.database,
-          newurlPrefix = "#" + database.url('app'),
-          addLinks = FauxtonAPI.getExtensions('sidebar:links');
+          addLinks = FauxtonAPI.getExtensions('sidebar:links'),
+          databaseName = database.id,
+          newUrlPrefix = '#' + FauxtonAPI.urls('databaseBaseURL','app', databaseName);
 
-      return _.reduce(FauxtonAPI.getExtensions('sidebar:links'), function (menuLinks, link) {
+      return _.reduce(addLinks, function (menuLinks, link) {
 
         menuLinks.push({
           title: link.title,
-          url: newurlPrefix + "/" + link.url,
+          url: newUrlPrefix + '/' + link.url,
           icon: 'fonticon-plus-circled'
         });
 
         return menuLinks; 
      }, [{
           title: 'New Doc',
-          url: newurlPrefix + '/new',
+          url: newUrlPrefix + '/new',
           icon: 'fonticon-plus-circled'
         },{
           title: 'New View',
-          url: newurlPrefix + '/new_view',
+          url: newUrlPrefix + '/new_view',
           icon: 'fonticon-plus-circled'
         }]);
     },
@@ -169,33 +179,35 @@ function(app, FauxtonAPI, Components, Documents, Databases) {
     },
 
     serialize: function(){
-      var ddocName = this.model.id.replace(/^_design\//,"");
+      var ddocName = this.model.id.replace(/^_design\//,""),
+          docSafe = app.utils.safeURLName(ddocName),
+          databaseName = this.collection.database.safeID();
+
       return{
-        database: this.collection.database,
+        designDocMetaUrl: FauxtonAPI.urls('designDocs', 'app', databaseName, docSafe),
         designDoc: ddocName,
-        ddoc_clean: app.utils.removeSpecialCharacters(ddocName),
-        ddoc_encoded: app.utils.safeURLName(ddocName),
-        database_encoded: app.utils.safeURLName(this.model.database.id),
+        ddoc_clean: docSafe,
       };
     },
 
-    getSidebarLinks: function () {
+    getSidebarLinks: function () {  //these are for each Design doc '+' links
       var ddocName = this.model.id.replace(/^_design\//,""),
-          docSafe = app.utils.safeURLName(ddocName), 
-          database = this.collection.database;
+          docSafe = app.utils.safeURLName(ddocName),
+          databaseName = this.collection.database.id,
+          newUrlPrefix = FauxtonAPI.urls('databaseBaseURL','app', databaseName);
 
-      return _.reduce(FauxtonAPI.getExtensions('sidebar:links'), function (menuLinks, link) {
 
+      return _.reduce(FauxtonAPI.getExtensions('sidebar:links'), function (menuLinks, link) {
         menuLinks.push({
           title: link.title,
-          url: "#" + database.url('app') + "/" + link.url + "/" + docSafe,
+          url: '#' + newUrlPrefix + '/' + link.url + '/' + docSafe,
           icon: 'fonticon-plus-circled'
         });
 
         return menuLinks; 
      }, [{
       title: 'New View',
-      url: "#" + database.url('app') + "/new_view/" + docSafe,
+      url: '#' + FauxtonAPI.urls('new', 'addView', databaseName, docSafe),
       icon: 'fonticon-plus-circled'
      }]);
 
@@ -246,8 +258,8 @@ function(app, FauxtonAPI, Components, Documents, Databases) {
       this.name = options.name;
 
       this.indexTypeMap = {
-        views:   { icon: 'fonticon-sidenav-map-reduce', urlFolder: '_view' },
-        indexes: { icon: 'fonticon-sidenav-search', urlFolder: '_indexes' }
+        views:   { icon: 'fonticon-sidenav-map-reduce', urlFolder: '_view', type: 'view' },
+        indexes: { icon: 'fonticon-sidenav-search', urlFolder: '_indexes', type: 'search' }
       };
     },
 
@@ -261,7 +273,8 @@ function(app, FauxtonAPI, Components, Documents, Databases) {
         ddoc: this.ddoc,
         database: this.database,
         selected: this.selected,
-        collection: this.collection
+        collection: this.collection,
+        href: FauxtonAPI.urls(this.indexTypeMap[this.selector].type, 'app', this.database, this.ddoc)
       };
     },
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/templates/changes.html
----------------------------------------------------------------------
diff --git a/app/addons/documents/templates/changes.html b/app/addons/documents/templates/changes.html
index a9bfbaf..e06e34b 100644
--- a/app/addons/documents/templates/changes.html
+++ b/app/addons/documents/templates/changes.html
@@ -36,7 +36,7 @@ the License.
             <% if (change.deleted) { %>
               <%- change.id %>
             <% } else { %>
-              <a href="#<%- database.url('app') %>/<%- safeURL(change.id) %>"><%- change.id %></a>
+              <a href="#<%- href(database.id, change.id) %>"><%- change.id %></a>
             <% } %>    </div>
           <div class="span2 text-right">
             <a class="js-copy" data-clipboard-text="<%- change.id %>" data-bypass="true" href="#">

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/templates/design_doc_menu.html
----------------------------------------------------------------------
diff --git a/app/addons/documents/templates/design_doc_menu.html b/app/addons/documents/templates/design_doc_menu.html
index 8180f48..120c553 100644
--- a/app/addons/documents/templates/design_doc_menu.html
+++ b/app/addons/documents/templates/design_doc_menu.html
@@ -12,21 +12,21 @@ License for the specific language governing permissions and limitations under
 the License.
 -->
 <li class="nav-header">
-	
-	<div  class="js-collapse-toggle accordion-header" data-toggle="collapse" data-target="#<%- ddoc_clean %>" id="nav-header-<%- ddoc_clean %>" >
-		<div class="accordion-list-item">
-			<div class="fonticon-play"></div>
-			<p>_design/<%- designDoc%></p>
-		</div>
-		<div class="new-button add-dropdown"></div>
-	</div>
-	<ul class="accordion-body collapse" id="<%= ddoc_clean %>">
-		<li>
-			<a id="<%- ddoc_clean %>_metadata" href="#/database/<%- database_encoded %>/_design/<%- ddoc_encoded %>/metadata" class="toggle-view accordion-header">
-			<span class="fonticon-sidenav-info fonticon"></span>
-			  Design Doc Metadata
-			</a>
-		</li>
 
-	</ul>
+<div  class="js-collapse-toggle accordion-header" data-toggle="collapse" data-target="#<%- ddoc_clean %>" id="nav-header-<%- ddoc_clean %>" >
+  <div class="accordion-list-item">
+    <div class="fonticon-play"></div>
+    <p>_design/<%- designDoc%></p>
+  </div>
+  <div class="new-button add-dropdown"></div>
+</div>
+<ul class="accordion-body collapse" id="<%- ddoc_clean %>">
+  <li>
+  <a id="<%- ddoc_clean %>_metadata" href="#/<%- designDocMetaUrl %>" class="toggle-view accordion-header">
+    <span class="fonticon-sidenav-info fonticon"></span>
+    Design Doc Metadata
+  </a>
+  </li>
+
+</ul>
 </li>

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/templates/index_menu_item.html
----------------------------------------------------------------------
diff --git a/app/addons/documents/templates/index_menu_item.html b/app/addons/documents/templates/index_menu_item.html
index f7f9e57..da055b8 100644
--- a/app/addons/documents/templates/index_menu_item.html
+++ b/app/addons/documents/templates/index_menu_item.html
@@ -19,7 +19,11 @@ the License.
   <ul class="accordion-body collapse" id="<%- removeSpecialCharacters(ddoc) + ddocType %>">
   <% _.each(collection, function (item, index) { %>
   <li>
-  <a data-ddoctype="<%- ddocType %>" id="<%- removeSpecialCharacters(ddoc) %>_<%- removeSpecialCharacters(index) %>" href="#/database/<%- safeURL(database) %>/_design/<%= safeURL(ddoc)%>/<%-urlFolder%>/<%= safeURL(index) %>" class="toggle-view">
+  <a
+    data-ddoctype="<%- ddocType %>"
+    id="<%- removeSpecialCharacters(ddoc) %>_<%- removeSpecialCharacters(index) %>"
+    href="#/<%- href%><%- index%>"
+    class="toggle-view">
     <%- index %>
   </a>
   </li>

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/templates/sidebar.html
----------------------------------------------------------------------
diff --git a/app/addons/documents/templates/sidebar.html b/app/addons/documents/templates/sidebar.html
index 9019d9f..857aa0a 100644
--- a/app/addons/documents/templates/sidebar.html
+++ b/app/addons/documents/templates/sidebar.html
@@ -13,17 +13,17 @@ the License.
 -->
 
 <ul class="nav nav-list">
-  <li><a id="permissions" href="<%= permissions_url %>">Permissions</a><li>
-  <li><a id="changes" href="<%= changes_url %>">Changes</a><li>
+  <li><a id="permissions" href="<%- permissions_url %>">Permissions</a><li>
+  <li><a id="changes" href="<%- changes_url %>">Changes</a><li>
   <% _.each(docLinks, function (link) { %>
-  <li><a id="docLink_<%=link.url%>" href="<%= database_url + '/' + link.url %>"><%= link.title %></a></li>
+  <li><a id="docLink_<%-link.url%>" href="<%- base + link.url %>"><%- link.title %></a></li>
   <% }); %>
   <li class="active"> 
-      <a id="all-docs" href="#<%= database.url('index') %>" class="toggle-view"> All Documents</a> 
+      <a id="all-docs" href="#/<%- databaseUrl %>" class="toggle-view"> All Documents</a> 
       <div id="new-all-docs-button" class="add-dropdown"> </div>
    </li>
   <li>
-      <a id="design-docs" href='#<%= database.url("index") %>?startkey="_design"&endkey="_design0"'  class="toggle-view"> All Design Docs</a>
+      <a id="design-docs" href='#/<%- databaseUrl %>?startkey="_design"&endkey="_design0"'  class="toggle-view"> All Design Docs</a>
       <div id="new-design-docs-button" class="add-dropdown"> </div>
     </li>
 </ul>

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/tests/actionsSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/actionsSpec.js b/app/addons/documents/tests/actionsSpec.js
index 68b2172..a37c769 100644
--- a/app/addons/documents/tests/actionsSpec.js
+++ b/app/addons/documents/tests/actionsSpec.js
@@ -15,7 +15,8 @@ define([
   'addons/documents/index-editor/actions',
   'addons/documents/resources',
   'addons/documents/index-editor/actiontypes',
-  'testUtils'
+  'testUtils',
+  'addons/documents/base'
 ], function (FauxtonAPI, Actions, Documents, ActionTypes, testUtils) {
   var assert = testUtils.assert;
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/tests/nightwatch/editDocumentsFromView.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/nightwatch/editDocumentsFromView.js b/app/addons/documents/tests/nightwatch/editDocumentsFromView.js
index 21b6d56..4f1a69b 100644
--- a/app/addons/documents/tests/nightwatch/editDocumentsFromView.js
+++ b/app/addons/documents/tests/nightwatch/editDocumentsFromView.js
@@ -49,7 +49,7 @@ module.exports = {
     var waitTime = 10000;
 
     client
-      .clickWhenVisible('#doc-editor-actions-panel .js-back')
+      .clickWhenVisible('#dashboard a[href="#database/fauxton-selenium-tests/_design/abc/_view/evens"]')
       .clickWhenVisible('#toggle-query')
       .clickWhenVisible('#query-options-tray label[for="qoReduce"]')
       .clickWhenVisible('#button-options button[type="submit"]')

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/views-changes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/views-changes.js b/app/addons/documents/views-changes.js
index b58a78d..32c379d 100644
--- a/app/addons/documents/views-changes.js
+++ b/app/addons/documents/views-changes.js
@@ -85,7 +85,10 @@ function(app, FauxtonAPI, Components, prettify, ZeroClipboard) {
 
       return {
         changes: filteredData,
-        database: this.model
+        database: this.model,
+        href: function (db, id) {
+          return FauxtonAPI.urls('document', 'app', db, id);
+        }
       };
     },
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/views-doceditor.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/views-doceditor.js b/app/addons/documents/views-doceditor.js
index 86ffbc3..a4b604f 100644
--- a/app/addons/documents/views-doceditor.js
+++ b/app/addons/documents/views-doceditor.js
@@ -225,7 +225,7 @@ function (app, FauxtonAPI, Components, Documents, Databases, prettify) {
     },
 
     goBack: function () {
-      FauxtonAPI.navigate(this.previousPage);
+      FauxtonAPI.navigate(FauxtonAPI.urls('allDocs', 'app', this.database.id, '?limit=20'));
     },
 
     destroy: function () {
@@ -248,7 +248,7 @@ function (app, FauxtonAPI, Components, Documents, Databases, prettify) {
           msg: 'Your document has been successfully deleted.',
           clear: true
         });
-        FauxtonAPI.navigate(database.url('index'));
+        FauxtonAPI.navigate(FauxtonAPI.urls('allDocs', 'app', database.id, '?limit=20'));
       }, function () {
         FauxtonAPI.addNotification({
           msg: 'Failed to delete your document!',
@@ -294,7 +294,7 @@ function (app, FauxtonAPI, Components, Documents, Databases, prettify) {
 
         this.model.save().then(function () {
           editor.editSaved();
-          FauxtonAPI.navigate('/database/' + that.database.safeID() + '/' + that.model.id);
+          FauxtonAPI.navigate(FauxtonAPI.urls('document', 'app', that.database.safeID(), that.model.id));
         }).fail(function (xhr) {
           var responseText = JSON.parse(xhr.responseText).reason;
           FauxtonAPI.addNotification({

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/documents/views.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/views.js b/app/addons/documents/views.js
index f472b46..cdef0d1 100644
--- a/app/addons/documents/views.js
+++ b/app/addons/documents/views.js
@@ -178,8 +178,10 @@ function (app, FauxtonAPI, Components, Documents,
         clear: true
       });
 
+      this.database.url = FauxtonAPI.urls('databaseBaseURL', 'server', this.database.id, '');
+
       this.database.destroy().then(function () {
-        FauxtonAPI.navigate('#/_all_dbs');
+        FauxtonAPI.navigate(FauxtonAPI.urls('allDBs', 'app'));
         FauxtonAPI.addNotification({
           msg: 'The database <code>' + _.escape(databaseName) + '</code> has been deleted.',
           clear: true,

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/fauxton/components.js
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/components.js b/app/addons/fauxton/components.js
index 43d406e..9ec992a 100644
--- a/app/addons/fauxton/components.js
+++ b/app/addons/fauxton/components.js
@@ -648,19 +648,14 @@ function(app, FauxtonAPI, ace, spin, ZeroClipboard) {
       this.database = options.database;
       _.bindAll(this);
     },
-    source: function(query, process) {
-      var url = [
-        app.host,
-        "/",
-        this.database.id,
-        "/_all_docs?startkey=%22",
-        query,
-        "%22&endkey=%22",
-        query,
-        "\u9999",
-        "%22&limit=",
-        this.docLimit
-      ].join('');
+    source: function(id, process) {
+      var query = '?' + $.param({
+        startkey: JSON.stringify(id),
+        endkey: JSON.stringify(id + "\u9999"),
+        limit: this.docLimit
+      });
+
+      var url = FauxtonAPI.urls('allDocs', 'server', this.database.safeID(), query);
 
       if (this.ajaxReq) { this.ajaxReq.abort(); }
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/addons/replication/base.js
----------------------------------------------------------------------
diff --git a/app/addons/replication/base.js b/app/addons/replication/base.js
index a0de0de..5e0c717 100644
--- a/app/addons/replication/base.js
+++ b/app/addons/replication/base.js
@@ -20,5 +20,12 @@ function(app, FauxtonAPI, replication) {
 	replication.initialize = function() {
     FauxtonAPI.addHeaderLink({ title: 'Replication', href: '#/replication', icon: 'fonticon-replicate' });
   };
+
+  FauxtonAPI.registerUrls( 'replication', {
+    app: function (db) {
+      return '#/replication/' + db;
+    }
+  });
+
   return replication;
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/core/api.js
----------------------------------------------------------------------
diff --git a/app/core/api.js b/app/core/api.js
index 8916b8c..a2771fd 100644
--- a/app/core/api.js
+++ b/app/core/api.js
@@ -54,6 +54,44 @@ function(FauxtonAPI, Layout, Router, RouteObject, utils, Store, Flux) {
     FauxtonAPI.router.triggerRouteEvent('route:' + routeEvent, args);
   };
 
+  var urlPaths = {};
+
+  FauxtonAPI.registerUrls = function (namespace, urls) {
+    urlPaths[namespace] = urls;
+  };
+
+  //This is a little rough and needs some improvement. But the basic concept is there
+  FauxtonAPI.urls = function (name, context) {
+    var interceptors = FauxtonAPI.getExtensions('urls:interceptors');
+    var url;
+
+    var args = arguments;
+    _.first(interceptors, function (interceptor) {
+      var out = interceptor.apply(null, args);
+
+      if (out) {
+        url = out;
+        return true;
+      }
+      return false;
+    });
+    
+    if (!_.isUndefined(url)) { return url; }
+
+    if (!urlPaths[name]) {
+      console.log('could not find name ', name);
+      return '';
+    }
+
+    if (!urlPaths[name][context]) {
+      console.log('could not find context ', context);
+      return '';
+    }
+
+    args = Array.prototype.slice.call(arguments, 2);
+    url = urlPaths[name][context].apply(null, args);
+    return url;
+  };
 
   return FauxtonAPI;
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/92834eae/app/core/tests/apiSpec.js
----------------------------------------------------------------------
diff --git a/app/core/tests/apiSpec.js b/app/core/tests/apiSpec.js
new file mode 100644
index 0000000..2fc3624
--- /dev/null
+++ b/app/core/tests/apiSpec.js
@@ -0,0 +1,50 @@
+// 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',
+      'testUtils'
+], function (FauxtonAPI, testUtils) {
+  var assert = testUtils.assert;
+
+  describe('URLs', function () {
+
+    it('can register and get url', function () {
+      var testUrl = 'this_is_a_test_url';
+
+      FauxtonAPI.registerUrls('testURL', {
+        server: function () {
+          return testUrl;
+        }
+      });
+
+      assert.equal(FauxtonAPI.urls('testURL', 'server'), testUrl);
+
+    });
+
+    it('can register interceptor to change url', function () {
+      var testUrl = 'interceptor_url';
+
+      FauxtonAPI.registerExtension('urls:interceptors', function (name, context) {
+        if (name === 'testURL' && context === 'intercept') {
+          return testUrl;
+        }
+
+        return false;
+      });
+
+      assert.equal(FauxtonAPI.urls('testURL', 'intercept'), testUrl);
+    });
+
+  });
+
+});
+