couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gar...@apache.org
Subject [7/7] git commit: updated refs/heads/fauxton-modularise to 752819c
Date Mon, 06 Jan 2014 14:16:36 GMT
Fauxton: Split less files and rename mixin.js


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

Branch: refs/heads/fauxton-modularise
Commit: 752819c1a6635971081a00fe3aeafb010ac450e9
Parents: fae1de2 bf4bacb
Author: Garren Smith <garren.smith@gmail.com>
Authored: Mon Jan 6 15:11:19 2014 +0200
Committer: Garren Smith <garren.smith@gmail.com>
Committed: Mon Jan 6 15:11:19 2014 +0200

----------------------------------------------------------------------
 src/fauxton/app/addons/auth/resources.js        |   6 +-
 .../app/addons/config/assets/less/config.less   |  43 ++++
 .../app/addons/config/templates/item.html       |   2 +-
 .../addons/databases/assets/less/database.less  | 245 +++++++++++++++++++
 src/fauxton/app/addons/databases/base.js        |   2 +-
 src/fauxton/app/addons/databases/resources.js   |   6 +-
 src/fauxton/app/addons/databases/views.js       |   8 +-
 src/fauxton/app/addons/documents/resources.js   |  14 +-
 src/fauxton/app/addons/documents/routes.js      |   4 +-
 src/fauxton/app/addons/documents/views.js       |  20 +-
 .../app/addons/logs/assets/less/logs.less       |  24 ++
 src/fauxton/app/addons/permissions/resources.js |   2 +-
 .../app/addons/verifyinstall/resources.js       |  11 +-
 src/fauxton/app/api.js                          |   2 +-
 src/fauxton/app/app.js                          |   6 +-
 src/fauxton/app/helpers.js                      |   3 +-
 src/fauxton/app/mixins.js                       |  65 -----
 src/fauxton/app/resizeColumns.js                |  10 +-
 src/fauxton/app/utils.js                        |  65 +++++
 src/fauxton/assets/less/config.less             |  46 ----
 src/fauxton/assets/less/database.less           | 245 -------------------
 src/fauxton/assets/less/fauxton.less            |   3 -
 src/fauxton/assets/less/logs.less               |  24 --
 23 files changed, 423 insertions(+), 433 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb/blob/752819c1/src/fauxton/app/addons/config/assets/less/config.less
----------------------------------------------------------------------
diff --cc src/fauxton/app/addons/config/assets/less/config.less
index 86d9bf1,0000000..3cd57d0
mode 100644,000000..100644
--- a/src/fauxton/app/addons/config/assets/less/config.less
+++ b/src/fauxton/app/addons/config/assets/less/config.less
@@@ -1,13 -1,0 +1,56 @@@
++/*  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.
++ */
++
++.config-item {
++  height: 41px;
++
++  .edit-button {
++    float: right;
++    display:none;
++    padding: 3px;
++  }
++
++  td:hover .edit-button {
++    display: block;
++  }
++
++  .value-input {
++    width: 98%;
++  }
++
++  #delete-value {
++    cursor: pointer;
++  }
++}
++
++.button-margin {
++  margin-bottom: 15px;
++}
++
++#add-section-modal {
++  width: 400px;
++}
++
 +table.config {
 +  #config-trash {
 +    width: 5%;
 +  }
 +  
 +  #delete-value {
 +    text-align: center;
 +  } 
 +}
 +
 +button#add-section {
 +  float: right;
 +}

http://git-wip-us.apache.org/repos/asf/couchdb/blob/752819c1/src/fauxton/app/addons/config/templates/item.html
----------------------------------------------------------------------
diff --cc src/fauxton/app/addons/config/templates/item.html
index 3e6e4ee,3e6e4ee..1c808b9
--- a/src/fauxton/app/addons/config/templates/item.html
+++ b/src/fauxton/app/addons/config/templates/item.html
@@@ -20,7 -20,7 +20,7 @@@ the License
  <td> <%= option.name %> </td>
  <td>
    <div id="show-value">
--    <%= option.value %> <button class="edit-button"> Edit </button>
++    <%= option.value %> <button class="edit-button btn-mini btn"> Edit </button>
    </div>
    <div id="edit-value-form" style="display:none">
      <input class="value-input" type="text" value="<%= option.value %>" />

http://git-wip-us.apache.org/repos/asf/couchdb/blob/752819c1/src/fauxton/app/addons/databases/assets/less/database.less
----------------------------------------------------------------------
diff --cc src/fauxton/app/addons/databases/assets/less/database.less
index 0000000,0000000..377b136
new file mode 100644
--- /dev/null
+++ b/src/fauxton/app/addons/databases/assets/less/database.less
@@@ -1,0 -1,0 +1,245 @@@
++/*  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.
++ */
++
++/* =database
++   ---------------------------------------------------------------------- */
++#db-tools {
++    position: absolute;
++    top: -7px;
++    right: 0;
++    width: 390px;
++
++    .btn-group {
++        position: absolute;
++        left: 0;
++        top: 6px;
++    }
++
++    form {
++        position: absolute;
++        right: 0;
++        top: 0;
++    }
++}
++
++.tools .nav {
++    margin-bottom: 10px;
++}
++
++#sidenav {
++    padding-top: 10px;
++
++    h3 {
++        margin: 10px 0;
++    }
++
++    li a span.divider {
++        background: none;
++        color: #ccc;
++        padding: 0 2px;
++    }
++
++    li.nav-header a {
++        display: inline
++    }
++
++    div.btn-group {
++        display: inline-block;
++    }
++
++    li.nav-header, #sidenav li a {
++        padding-left: 4px;
++    }
++
++    li.active a {
++        background-color: #ddd;
++        color: #333;
++        text-shadow: none;
++    }
++}
++
++.edit {
++    display: none;
++
++    form {
++        margin-bottom: 0;
++    }
++
++    h3 {
++        border-bottom: 1px solid #ccc;
++        font-size: 100%;
++        line-height: 1;
++        margin-bottom: 18px;
++    }
++
++    textarea {
++        height: 100px;
++        width: 95%;
++    }
++
++    .btn-toolbar {
++        margin-bottom: 0;
++    }
++
++    .preview {
++        width: 100px;
++    }
++
++    .save {
++    }
++}
++
++#new-view-index {
++    .confirm {
++        display: none;
++    }
++
++    .confirm .progress {
++        display: none;
++        margin: 20px;
++    }
++
++    textarea {
++        height: 100px;
++        width: 95%;
++    }
++}
++
++.view {
++    display: none;
++
++    .result-tools {
++        float: left;
++        width: 100%;
++        margin-bottom: 10px;
++    }
++
++    table td div  {
++        position: relative;
++    }
++
++    table td div div {
++        display: none;
++        line-height: 1;
++        position: absolute;
++        right: 4px;
++        top: 4px;
++    }
++
++    table td div:hover div a.edits {
++        padding-left: 16px;
++        padding-right: 16px;
++    }
++
++    table td div:hover div {
++        display: block;
++    }
++
++}
++.view.show {
++    display: block;
++}
++.view.show.hidden-by-params {
++    display: none;
++}
++#database .view table tr td {
++    padding: 0;
++}
++
++.loading {display: none;}
++
++.view-request-duration {
++  padding-right: 10px;
++  float: right;
++}
++
++table.active-tasks{
++    th {
++        cursor: pointer;
++    }
++}
++
++.well{
++    .row-fluid{
++        margin: 0;
++    }
++    .row-fluid .row-fluid:last-child .well-item {
++        border: none;
++    }
++    .well-item{
++        color: #666;
++        font-size: 12px;
++        border-bottom: 1px solid #e5e5e5;
++        padding: 8px 4px;
++        strong {
++            font-size: 16px;
++        }  
++    } 
++}
++
++
++#doc {
++    .dropdown-menu{
++        width: auto;
++    }
++}
++// #tabs {
++//     height: 40px;
++// }
++
++.databases{
++    a.db-actions,
++    a.db-actions:visited{
++        color: @red; 
++        border: 1px solid #e3e3e3;
++        padding: 5px 7px;
++        .border-radius(6px);
++        text-decoration: none;
++        font-size: 19px;
++    }
++}
++.btn-group{
++    ul.dropdown-menu li a:before{
++        margin-right: 10px;
++    }
++}
++
++.design-doc-group{
++    .span3 { margin: 0;}
++    #new-ddoc-section {
++        margin-top: 10px;
++        label{ width: 100px}
++        .controls{
++            margin-left: 100px;
++        }
++    }
++}
++table#changes-table {
++
++  #changes {
++    width: 50%;
++  }
++
++  #seq, #deleted {
++    width: 5%;
++  }
++
++}
++
++.doc-editor-buttons {
++    margin-bottom: 15px;
++    a.button.btn-large.gray {
++        padding: 9px 10px;
++        vertical-align: middle;
++    }
++}

http://git-wip-us.apache.org/repos/asf/couchdb/blob/752819c1/src/fauxton/app/addons/databases/base.js
----------------------------------------------------------------------
diff --cc src/fauxton/app/addons/databases/base.js
index 1a3dc66,0000000..ea1719c
mode 100644,000000..100644
--- a/src/fauxton/app/addons/databases/base.js
+++ b/src/fauxton/app/addons/databases/base.js
@@@ -1,37 -1,0 +1,37 @@@
 +// Licensed under the Apache License, Version 2.0 (the "License"); you may not
 +// use this file except in compliance with the License. You may obtain a copy of
 +// the License at
 +//
 +//   http://www.apache.org/licenses/LICENSE-2.0
 +//
 +// Unless required by applicable law or agreed to in writing, software
 +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 +// License for the specific language governing permissions and limitations under
 +// the License.
 +
 +define([
 +  "app",
 +
 +  "api",
 +
 +  // Modules
 +  "addons/databases/routes",
 +  // Views
 +  "addons/databases/views"
 +
 +],
 +
 +function(app, FauxtonAPI, Databases, Views) {
 +  Databases.Views = Views;
 +
 +  // Utility functions
 +  Databases.databaseUrl = function(database) {
 +    var name = _.isObject(database) ? database.id : database,
-         dbname = app.mixins.safeURLName(name);
++        dbname = app.utils.safeURLName(name);
 +
 +    return ["/database/", dbname, "/_all_docs?limit=" + Databases.DocLimit].join('');
 +  };
 +
 +  return Databases;
 +});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/752819c1/src/fauxton/app/addons/databases/resources.js
----------------------------------------------------------------------
diff --cc src/fauxton/app/addons/databases/resources.js
index b6d6536,0000000..3510154
mode 100644,000000..100644
--- a/src/fauxton/app/addons/databases/resources.js
+++ b/src/fauxton/app/addons/databases/resources.js
@@@ -1,193 -1,0 +1,193 @@@
 +// Licensed under the Apache License, Version 2.0 (the "License"); you may not
 +// use this file except in compliance with the License. You may obtain a copy of
 +// the License at
 +//
 +//   http://www.apache.org/licenses/LICENSE-2.0
 +//
 +// Unless required by applicable law or agreed to in writing, software
 +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 +// License for the specific language governing permissions and limitations under
 +// the License.
 +
 +define([
 +  "app",
 +
 +  "api",
 +
 +  // Modules
 +  "addons/documents/resources"
 +],
 +
 +function(app, FauxtonAPI, Documents) {
 +  var Databases = FauxtonAPI.addon();
 +
 +  Databases.DocLimit = 20;
 +
 +  Databases.Model = Backbone.Model.extend({
 +    initialize: function(options) {
 +      this.status = new Databases.Status({
 +        database: this
 +      });
 +    },
 +
 +    documentation: function(){
 +      return "all_dbs";
 +    },
 +    
 +    buildAllDocs: function(params) {
 +      this.allDocs = new Documents.AllDocs(null, {
 +        database: this,
 +        params: params
 +      });
 +
 +      return this.allDocs;
 +    },
 +
 +    isNew: function(){
 +      // Databases are never new, to make Backbone do a PUT
 +      return false;
 +    },
 +
 +    url: function(context) {
 +      if (context === "index") {
 +        return "/database/" + this.safeID() + "/_all_docs";
 +      } else if (context === "web-index") {
 +        return "#/database/"+ this.safeID() + "/_all_docs?limit=" + Databases.DocLimit;
 +      } 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";
 +      } else if (context === "changes-apiurl") { 
 +        return window.location.origin + "/database/" + this.safeID() + "/_changes?descending=true&limit=100&include_docs=true";
 +      } else if (context === "app") {
 +        return "/database/" + this.safeID();
 +      } else {
 +        return app.host + "/" + this.safeID();
 +      }
 +    },
 +    safeName: function(){
-       return app.mixins.safeURLName(this.get("name"));
++      return app.utils.safeURLName(this.get("name"));
 +    },
 +    safeID: function() {
-       return app.mixins.safeURLName(this.id);
++      return app.utils.safeURLName(this.id);
 +    },
 +    buildChanges: function (params) {
 +      this.changes = new Databases.Changes({
 +        database: this,
 +        params: params
 +      });
 +
 +      return this.changes;
 +    }
 +  });
 +
 +  Databases.Changes = Backbone.Collection.extend({
 +
 +    initialize: function(options) {
 +      this.database = options.database;
 +      this.params = options.params;
 +    },
 +    documentation: function(){
 +      return "changes";
 +    },
 +    url: function (context) {
 +      var query = "";
 +      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;
 +      }
 +    },
 +
 +    parse: function (resp) {
 +      this.last_seq = resp.last_seq;
 +      return resp.results;
 +    }
 +  });
 +
 +  Databases.Status = Backbone.Model.extend({
 +    url: function() {
 +      return app.host + "/" + this.database.safeID();
 +    },
 +
 +    initialize: function(options) {
 +      this.database = options.database;
 +    },
 +
 +    numDocs: function() {
 +      return this.get("doc_count");
 +    },
 +
 +    updateSeq: function(full) {
 +      var updateSeq = this.get("update_seq");
 +      if (full || (typeof(updateSeq) === 'number')) {
 +        return updateSeq;
 +      } else if (updateSeq) {
 +        return updateSeq.split('-')[0];
 +      } else {
 +        return 0;
 +      }
 +    },
 +
 +    humanSize: function() {
 +      // cribbed from http://stackoverflow.com/questions/10420352/converting-file-size-in-bytes-to-human-readable
 +      var i = -1;
 +      var byteUnits = [' kB', ' MB', ' GB', ' TB', 'PB', 'EB', 'ZB', 'YB'];
 +      var fileSizeInBytes = this.dataSize();
 +
 +      if (!fileSizeInBytes) {
 +        return 0;
 +      }
 +
 +      do {
 +          fileSizeInBytes = fileSizeInBytes / 1024;
 +          i++;
 +      } while (fileSizeInBytes > 1024);
 +
 +      return Math.max(fileSizeInBytes, 0.1).toFixed(1) + byteUnits[i];
 +    },
 +    diskSize: function () {
 +      return this.get("disk_size");
 +    },
 +
 +    dataSize: function () {
 +      if (this.get("other")){
 +        return this.get("other").data_size;
 +      }else{
 +        return 0;
 +      }  
 +    }
 +  });
 +
 +  // TODO: shared databases - read from the user doc
 +  Databases.List = Backbone.Collection.extend({
 +    model: Databases.Model,
 +    documentation: function(){
 +      return "all_dbs";
 +    },
 +    url: function(context) {
 +      if (context === "apiurl") { 
 +        return window.location.origin + "/_all_dbs";
 +      } else {
 +        return app.host + "/_all_dbs";
 +      }
 +    },
 +
 +    parse: function(resp) {
 +      // TODO: pagination!
 +      return _.map(resp, function(database) {
 +        return {
-           id: app.mixins.safeURLName(database),
++          id: app.utils.safeURLName(database),
 +          name: database
 +        };
 +      });
 +    }
 +  });
 +
 +  return Databases;
 +});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/752819c1/src/fauxton/app/addons/databases/views.js
----------------------------------------------------------------------
diff --cc src/fauxton/app/addons/databases/views.js
index 80d64ed,0000000..0068305
mode 100644,000000..100644
--- a/src/fauxton/app/addons/databases/views.js
+++ b/src/fauxton/app/addons/databases/views.js
@@@ -1,255 -1,0 +1,255 @@@
 +// Licensed under the Apache License, Version 2.0 (the "License"); you may not
 +// use this file except in compliance with the License. You may obtain a copy of
 +// the License at
 +//
 +//   http://www.apache.org/licenses/LICENSE-2.0
 +//
 +// Unless required by applicable law or agreed to in writing, software
 +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 +// License for the specific language governing permissions and limitations under
 +// the License.
 +
 +define([
 +  "app",
 +  
 +  "addons/fauxton/components",
 +  "api",
 +  "addons/databases/resources"
 +],
 +
 +function(app, Components, FauxtonAPI, Databases) {
 +  var Views = {};
 +
 +  Views.Item = FauxtonAPI.View.extend({
 +    template: "templates/databases/item",
 +    tagName: "tr",
 +    establish: function(){
 +      return [this.model.fetch()];
 +    },
 +    serialize: function() {
 +      return {
-         encoded: app.mixins.safeURLName(this.model.get("name")),
++        encoded: app.utils.safeURLName(this.model.get("name")),
 +        database: this.model,
 +        docLimit: Databases.DocLimit
 +      };
 +    }
 +  });
 +
 +  Views.List = FauxtonAPI.View.extend({
 +    dbLimit: 20,
 +    perPage: 20,
 +    template: "templates/databases/list",
 +    events: {
 +      "click button.all": "selectAll",
 +      "submit form#jump-to-db": "switchDatabase"
 +    },
 +
 +    initialize: function(options) {
 +      var params = app.getParams();
 +      this.page = params.page ? parseInt(params.page, 10) : 1;
 +    },
 +
 +    serialize: function() {
 +      return {
 +        databases: this.collection
 +      };
 +    },
 +    establish: function(){
 +      var currentDBs = this.paginated();
 +      var deferred = FauxtonAPI.Deferred();
 +
 +      FauxtonAPI.when(currentDBs.map(function(database) {
 +        return database.status.fetch();
 +      })).always(function(resp) {
 +        //make this always so that even if a user is not allowed access to a database
 +        //they will still see a list of all databases
 +        deferred.resolve();
 +      });
 +      return [deferred];
 +    },
 +    switchDatabase: function(event, selectedName) {
 +      event && event.preventDefault();
 +
 +      var dbname = this.$el.find("[name='search-query']").val().trim();
 +
 +      if (selectedName) {
 +        dbname = selectedName;
 +      }
 +
-       if (dbname && this.collection.where({"id":app.mixins.safeURLName(dbname)}).length > 0){
++      if (dbname && this.collection.where({"id":app.utils.safeURLName(dbname)}).length > 0){
 +          // 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.mixins.safeURLName(dbname), "/_all_docs?limit=" + Databases.DocLimit].join('');
++          var url = ["/database/", app.utils.safeURLName(dbname), "/_all_docs?limit=" + Databases.DocLimit].join('');
 +          FauxtonAPI.navigate(url);
 +      } else {
 +        FauxtonAPI.addNotification({
 +          msg: 'Database does not exist.',
 +          type: 'error'
 +        });
 +      }
 +    },
 +
 +    paginated: function() {
 +      var start = (this.page - 1) * this.perPage;
 +      var end = this.page * this.perPage;
 +      return this.collection.slice(start, end);
 +    },
 +
 +    beforeRender: function() {
 +
 +      this.insertView("#newButton", new Views.NewDatabaseButton({
 +        collection: this.collection
 +      }));
 +
 +      _.each(this.paginated(), function(database) {
 +        this.insertView("table.databases tbody", new Views.Item({
 +          model: database
 +        }));
 +      }, this);
 +
 +      this.insertView("#database-pagination", new Components.Pagination({
 +        page: this.page,
 +        perPage: this.perPage,
 +        total: this.collection.length,
 +        urlFun: function(page) {
 +          return "#/_all_dbs?page=" + page;
 +        }
 +      }));
 +    },
 +
 +    setPage: function(page) {
 +      this.page = page || 1;
 +    },
 +
 +    afterRender: function() {
 +      var that = this;
 +      this.dbSearchTypeahead = new Components.DbSearchTypeahead({
 +        dbLimit: this.dbLimit,
 +        el: "input.search-autocomplete",
 +        onUpdate: function (item) {
 +          that.switchDatabase(null, item);
 +        }
 +      });
 +
 +      this.dbSearchTypeahead.render();
 +    },
 +
 +    selectAll: function(evt){
 +      $("input:checkbox").attr('checked', !$(evt.target).hasClass('active'));
 +    }
 +  });
 +
 +
 +  Views.NewDatabaseButton = FauxtonAPI.View.extend({
 +    template: "templates/databases/newdatabase",
 +    events: {
 +      "click a#new": "newDatabase"
 +    },
 +    newDatabase: function() {
 +      var notification;
 +      var db;
 +      // TODO: use a modal here instead of the prompt
 +      var name = prompt('Name of database', 'newdatabase');
 +      if (name === null) {
 +        return;
 +      } else if (name.length === 0) {
 +        notification = FauxtonAPI.addNotification({
 +          msg: "Please enter a valid database name",
 +          type: "error",
 +          clear: true
 +        });
 +        return;
 +      }
 +      db = new this.collection.model({
 +        id: name,
 +        name: name
 +      });
 +      notification = FauxtonAPI.addNotification({msg: "Creating database."});
 +      db.save().done(function() {
 +        notification = FauxtonAPI.addNotification({
 +          msg: "Database created successfully",
 +          type: "success",
 +          clear: true
 +        });
-         var route = "#/database/" +  app.mixins.safeURLName(name) + "/_all_docs?limit=" + Databases.DocLimit;
++        var route = "#/database/" +  app.utils.safeURLName(name) + "/_all_docs?limit=" + Databases.DocLimit;
 +        app.router.navigate(route, { trigger: true });
 +      }
 +      ).error(function(xhr) {
 +        var responseText = JSON.parse(xhr.responseText).reason;
 +        notification = FauxtonAPI.addNotification({
 +          msg: "Create database failed: " + responseText,
 +          type: "error",
 +          clear: true
 +        });
 +      }
 +      );
 +    }
 +  });
 +
 +  Views.Sidebar = FauxtonAPI.View.extend({
 +    template: "templates/databases/sidebar",
 +    events: {
 +      "click a#new": "newDatabase",
 +      "click a#owned": "showMine",
 +      "click a#shared": "showShared"
 +    },
 +
 +    newDatabase: function() {
 +      var notification;
 +      var db;
 +      // TODO: use a modal here instead of the prompt
 +      var name = prompt('Name of database', 'newdatabase');
 +      if (name === null) {
 +        return;
 +      } else if (name.length === 0) {
 +        notification = FauxtonAPI.addNotification({
 +          msg: "Please enter a valid database name",
 +          type: "error",
 +          clear: true
 +        });
 +        return;
 +      }
 +      db = new this.collection.model({
 +        id: encodeURIComponent(name),
 +        name: name
 +      });
 +      notification = FauxtonAPI.addNotification({msg: "Creating database."});
 +      db.save().done(function() {
 +        notification = FauxtonAPI.addNotification({
 +          msg: "Database created successfully",
 +          type: "success",
 +          clear: true
 +        });
 +        var route = "#/database/" +  name + "/_all_docs?limit=" + Databases.DocLimit;
 +        app.router.navigate(route, { trigger: true });
 +      }
 +      ).error(function(xhr) {
 +        var responseText = JSON.parse(xhr.responseText).reason;
 +        notification = FauxtonAPI.addNotification({
 +          msg: "Create database failed: " + responseText,
 +          type: "error",
 +          clear: true
 +        });
 +      }
 +      );
 +    },
 +
 +    showMine: function(){
 +      $.contribute(
 +        'Show unshared databases',
 +        'app/addons/databases/views.js'
 +      );
 +    },
 +
 +    showShared: function(){
 +      $.contribute(
 +        'Show shared databases (e.g. continuous replications to/from the database)',
 +        'app/addons/databases/views.js'
 +      );
 +    }
 +  });
 +
 +  return Views;
 +});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/752819c1/src/fauxton/app/addons/documents/resources.js
----------------------------------------------------------------------
diff --cc src/fauxton/app/addons/documents/resources.js
index d87c2c9,0000000..7d2ce0a
mode 100644,000000..100644
--- a/src/fauxton/app/addons/documents/resources.js
+++ b/src/fauxton/app/addons/documents/resources.js
@@@ -1,638 -1,0 +1,638 @@@
 +// Licensed under the Apache License, Version 2.0 (the "License"); you may not
 +// use this file except in compliance with the License. You may obtain a copy of
 +// the License at
 +//
 +//   http://www.apache.org/licenses/LICENSE-2.0
 +//
 +// Unless required by applicable law or agreed to in writing, software
 +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 +// License for the specific language governing permissions and limitations under
 +// the License.
 +
 +define([
 +  "app",
 +  "api"
 +],
 +
 +function(app, FauxtonAPI) {
 +  var Documents = FauxtonAPI.addon();
 +
 +  Documents.Doc = Backbone.Model.extend({
 +    idAttribute: "_id",
 +    documentation: function(){
 +      return "docs";
 +    },
 +    url: function(context) {
 +      if (context === "app") {
 +        return this.getDatabase().url("app") + "/" + this.safeID();
 +      } else if (context === "web-index") {
-         return this.getDatabase().url("app") + "/" + app.mixins.safeURLName(this.id);
++        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();
 +      }
 +    },
 +
 +    initialize: function(_attrs, options) {
 +      if (this.collection && this.collection.database) {
 +        this.database = this.collection.database;
 +      } else if (options.database) {
 +        this.database = options.database;
 +      }
 +    },
 +
 +    // HACK: the doc needs to know about the database, but it may be
 +    // set directly or indirectly in all docs
 +    getDatabase: function() {
 +      return this.database ? this.database : this.collection.database;
 +    },
 +
 +    validate: function(attrs, options) {
 +      if (this.id && this.id !== attrs._id && this.get('_rev') ) {
 +        return "Cannot change a documents id.";
 +      }
 +    },
 +
 +    docType: function() {
 +      return this.id.match(/^_design/) ? "design doc" : "doc";
 +    },
 +
 +    isEditable: function() {
 +      return this.docType() != "reduction";
 +    },
 +
 +    isDdoc: function() {
 +      return this.docType() === "design doc";
 +    },
 +
 +    hasViews: function() {
 +      if (!this.isDdoc()) return false;
 +      var doc = this.get('doc');
 +      if (doc) {
 +        return doc && doc.views && _.keys(doc.views).length > 0;
 +      }
 +
 +      var views = this.get('views');
 +      return views && _.keys(views).length > 0;
 +    },
 +
 +    hasAttachments: function () {
 +      return !!this.get('_attachments');
 +    },
 +
 +    getDdocView: function(view) {
 +      if (!this.isDdoc() || !this.hasViews()) return false;
 +
 +      var doc = this.get('doc');
 +      if (doc) {
 +        return doc.views[view];
 +      }
 +
 +      return this.get('views')[view];
 +    },
 +
 +    setDdocView: function (view, map, reduce) {
 +      if (!this.isDdoc()) return false;
 +      var views = this.get('views');
 +          tempView = views[view] || {};
 +
 +      if (reduce) {
 +        tempView.reduce=reduce;
 +      } else {
 +        delete tempView.reduce;
 +      }
 +      tempView.map= map;
 +
 +      views[view] = tempView;
 +      this.set({views: views});
 +
 +      return true;
 +    },
 +
 +    removeDdocView: function (viewName) {
 +      if (!this.isDdoc()) return false;
 +      var views = this.get('views');
 +
 +      delete views[viewName];
 +      this.set({views: views});
 +    },
 +
 +    dDocModel: function () {
 +      if (!this.isDdoc()) return false;
 +      var doc = this.get('doc');
 +
 +      if (doc) {
 +        return new Documents.Doc(doc, {database: this.database});
 +      } 
 +
 +      return this;
 +    },
 +
 +    viewHasReduce: function(viewName) {
 +      var view = this.getDdocView(viewName);
 +
 +      return view && view.reduce;
 +    },
 +
 +    // Need this to work around backbone router thinking _design/foo
 +    // is a separate route. Alternatively, maybe these should be
 +    // treated separately. For instance, we could default into the
 +    // json editor for docs, or into a ddoc specific page.
 +    safeID: function() {
 +      if (this.isDdoc()){
 +        var ddoc = this.id.replace(/^_design\//,"");
-         return "_design/"+app.mixins.safeURLName(ddoc);
++        return "_design/"+app.utils.safeURLName(ddoc);
 +      }else{
-         return app.mixins.safeURLName(this.id);
++        return app.utils.safeURLName(this.id);
 +      }
 +    },
 +
 +    destroy: function() {
 +      var url = this.url() + "?rev=" + this.get('_rev');
 +      return $.ajax({
 +        url: url,
 +        dataType: 'json',
 +        type: 'DELETE'
 +      });
 +    },
 +
 +    parse: function(resp) {
 +      if (resp.rev) {
 +        resp._rev = resp.rev;
 +        delete resp.rev;
 +      }
 +      if (resp.id) {
 +        if (typeof(this.id) === "undefined") {
 +          resp._id = resp.id;
 +        }
 +        delete resp.id;
 +      }
 +      if (resp.ok) {
 +        delete resp.ok;
 +      }
 +      return resp;
 +    },
 +
 +    prettyJSON: function() {
 +      var data = this.get("doc") ? this.get("doc") : this;
 +
 +      return JSON.stringify(data, null, "  ");
 +    },
 +
 +    copy: function (copyId) {
 +      return $.ajax({
 +        type: 'COPY',
 +        url: '/' + this.database.safeID() + '/' + this.safeID(),
 +        headers: {Destination: copyId}
 +      });
 +    },
 +
 +    isNewDoc: function () {
 +      return this.get('_rev') ? false : true;
 +    }
 +  });
 +
 +  Documents.DdocInfo = Backbone.Model.extend({
 +    idAttribute: "_id",
 +    documentation: function(){
 +      return "docs";
 +    },
 +    initialize: function (_attrs, options) {
 +      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';
 +      }
 +    },
 +
 +    // Need this to work around backbone router thinking _design/foo
 +    // is a separate route. Alternatively, maybe these should be
 +    // treated separately. For instance, we could default into the
 +    // json editor for docs, or into a ddoc specific page.
 +    safeID: function() {
 +      var ddoc = this.id.replace(/^_design\//,"");
-       return "_design/"+app.mixins.safeURLName(ddoc);
++      return "_design/"+app.utils.safeURLName(ddoc);
 +    }
 +
 +  });
 +
 +  Documents.ViewRow = Backbone.Model.extend({
 +    docType: function() {
 +      if (!this.id) return "reduction";
 +
 +      return this.id.match(/^_design/) ? "design doc" : "doc";
 +    },
 +    documentation: function(){
 +      return "docs";
 +    },
 +    url: function(context) {
 +      if (!this.isEditable()) return false;
 +
 +      return this.collection.database.url(context) + "/" + this.safeID();
 +    },
 +
 +    isEditable: function() {
 +      return this.docType() != "reduction";
 +    },
 +    safeID: function() {
-       return app.mixins.safeURLName(this.id);
++      return app.utils.safeURLName(this.id);
 +    },
 +
 +    prettyJSON: function() {
 +      //var data = this.get("doc") ? this.get("doc") : this;
 +      return JSON.stringify(this, null, "  ");
 +    }
 +  });
 +
 +  Documents.NewDoc = Documents.Doc.extend({
 +    fetch: function() {
 +      var uuid = new FauxtonAPI.UUID();
 +      var deferred = this.deferred = $.Deferred();
 +      var that = this;
 +
 +      uuid.fetch().done(function() {
 +        that.set("_id", uuid.next());
 +        deferred.resolve();
 +      });
 +
 +      return deferred.promise();
 +    }
 +
 +  });
 +
 +  Documents.AllDocs = Backbone.Collection.extend({
 +    model: Documents.Doc,
 +    documentation: function(){
 +      return "docs";
 +    },
 +    initialize: function(_models, options) {
 +      this.database = options.database;
 +      this.params = options.params;
 +      this.skipFirstItem = false;
 +
 +      this.on("remove",this.decrementTotalRows , this);
 +    },
 +
 +    url: function(context) {
 +      var query = "";
 +      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;
 +      }
 +    },
 +
 +    simple: function () {
 +      var docs = this.map(function (item) {
 +        return {
 +          _id: item.id,
 +          _rev: item.get('_rev'),
 +        };
 +      });
 +
 +      return new Documents.AllDocs(docs, {
 +        database: this.database,
 +        params: this.params
 +      });
 +    },
 +
 +    urlNextPage: function (num, lastId) {
 +      if (!lastId) {
 +        var doc = this.last();
 +
 +        if (doc) {
 +          lastId = doc.id;
 +        } else {
 +          lastId = '';
 +        }
 +      }
 +
 +      this.params.startkey_docid = '"' + lastId + '"';
 +      this.params.startkey = '"' + lastId + '"';
 +      // when paginating forward, fetch 21 and don't show
 +      // the first item as it was the last item in the previous list
 +      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 + '"';
 +      } else {
 +        delete this.params.startkey;
 +        delete this.params.startkey_docid;
 +      }
 +      return this.url('app');
 +    },
 +
 +    totalRows: function() {
 +      return this.viewMeta.total_rows || "unknown";
 +    },
 +
 +    decrementTotalRows: function () {
 +      if (this.viewMeta.total_rows) {
 +        this.viewMeta.total_rows = this.viewMeta.total_rows -1;
 +        this.trigger('totalRows:decrement');
 +      }
 +    },
 +
 +    updateSeq: function() {
 +      return this.viewMeta.update_seq || false;
 +    },
 +
 +    recordStart: function () {
 +      if (this.viewMeta.offset === 0) {
 +        return 1;
 +      }
 +
 +      if (this.skipFirstItem) {
 +        return this.viewMeta.offset + 2;
 +      }
 +
 +      return this.viewMeta.offset + 1;
 +    },
 +
 +    parse: function(resp) {
 +      var rows = resp.rows;
 +
 +      this.viewMeta = {
 +        total_rows: resp.total_rows,
 +        offset: resp.offset,
 +        update_seq: resp.update_seq
 +      };
 +
 +      //Paginating, don't show first item as it was the last
 +      //item in the previous page
 +      if (this.skipFirstItem) {
 +        rows = rows.splice(1);
 +      }
 +      return _.map(rows, function(row) {
 +        return {
 +          _id: row.id,
 +          _rev: row.value.rev,
 +          value: row.value,
 +          key: row.key,
 +          doc: row.doc || undefined
 +        };
 +      });
 +    }
 +  });
 +
 +  Documents.IndexCollection = Backbone.Collection.extend({
 +    model: Documents.ViewRow,
 +    documentation: function(){
 +      return "docs";
 +    },
 +    initialize: function(_models, options) {
 +      this.database = options.database;
 +      this.params = _.extend({limit: 20, reduce: false}, options.params);
 +      this.idxType = "_view";
 +      this.view = options.view;
 +      this.design = options.design.replace('_design/','');
 +      this.skipFirstItem = false;
 +    },
 +
 +    url: function(context) {
 +      var query = "";
 +      if (this.params) {
 +        query = "?" + $.param(this.params);
 +      }
 +      
 +      var startOfUrl = app.host;
 +      if (context === 'app') {
 +        startOfUrl = 'database';
 +      } else if (context === "apiurl"){
 +        startOfUrl = window.location.origin;
 +      }
-       var design = app.mixins.safeURLName(this.design),
-           view = app.mixins.safeURLName(this.view);
++      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;
 +    },
 +
 +    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');
 +    },
 +
 +    recordStart: function () {
 +      if (this.viewMeta.offset === 0) {
 +        return 1;
 +      }
 +
 +      if (this.skipFirstItem) {
 +        return this.viewMeta.offset + 2;
 +      }
 +
 +      return this.viewMeta.offset + 1;
 +    },
 +
 +    totalRows: function() {
 +      return this.viewMeta.total_rows || "unknown";
 +    },
 +
 +    updateSeq: function() {
 +      return this.viewMeta.update_seq || false;
 +    },
 +
 +    simple: function () {
 +      var docs = this.map(function (item) {
 +        return {
 +          _id: item.id,
 +          key: item.get('key'),
 +          value: item.get('value')
 +        };
 +      });
 +
 +      return new Documents.IndexCollection(docs, {
 +        database: this.database,
 +        params: this.params,
 +        view: this.view,
 +        design: this.design
 +      });
 +    },
 +
 +    parse: function(resp) {
 +      var rows = resp.rows;
 +      this.endTime = new Date().getTime();
 +      this.requestDuration = (this.endTime - this.startTime);
 +
 +      if (this.skipFirstItem) {
 +        rows = rows.splice(1);
 +      }
 +
 +      this.viewMeta = {
 +        total_rows: resp.total_rows,
 +        offset: resp.offset,
 +        update_seq: resp.update_seq
 +      };
 +      return _.map(rows, function(row) {
 +        return {
 +          value: row.value,
 +          key: row.key,
 +          doc: row.doc,
 +          id: row.id
 +        };
 +      });
 +    },
 +
 +    buildAllDocs: function(){
 +      this.fetch();
 +    },
 +
 +    // We implement our own fetch to store the starttime so we that
 +    // we can get the request duration
 +    fetch: function () {
 +      this.startTime = new Date().getTime();
 +      return Backbone.Collection.prototype.fetch.call(this);
 +    },
 +
 +    allDocs: function(){
 +      return this.models;
 +    },
 +
 +    // This is taken from futon.browse.js $.timeString
 +    requestDurationInString: function () {
 +      var ms, sec, min, h, timeString, milliseconds = this.requestDuration;
 +
 +      sec = Math.floor(milliseconds / 1000.0);
 +      min = Math.floor(sec / 60.0);
 +      sec = (sec % 60.0).toString();
 +      if (sec.length < 2) {
 +         sec = "0" + sec;
 +      }
 +
 +      h = (Math.floor(min / 60.0)).toString();
 +      if (h.length < 2) {
 +        h = "0" + h;
 +      }
 +
 +      min = (min % 60.0).toString();
 +      if (min.length < 2) {
 +        min = "0" + min;
 +      }
 +
 +      timeString = h + ":" + min + ":" + sec;
 +
 +      ms = (milliseconds % 1000.0).toString();
 +      while (ms.length < 3) {
 +        ms = "0" + ms;
 +      }
 +      timeString += "." + ms;
 +
 +      return timeString;
 +    }
 +  });
 +
 +  
 +  Documents.PouchIndexCollection = Backbone.Collection.extend({
 +    model: Documents.ViewRow,
 +    documentation: function(){
 +      return "docs";
 +    },
 +    initialize: function(_models, options) {
 +      this.database = options.database;
 +      this.rows = options.rows;
 +      this.view = options.view;
 +      this.design = options.design.replace('_design/','');
 +      this.params = _.extend({limit: 20, reduce: false}, options.params);
 +      this.idxType = "_view";
 +    },
 +
 +    url: function () {
 +      return '';
 +    },
 +
 +    simple: function () {
 +      var docs = this.map(function (item) {
 +        return {
 +          _id: item.id,
 +          key: item.get('key'),
 +          value: item.get('value')
 +        };
 +      });
 +
 +      return new Documents.PouchIndexCollection(docs, {
 +        database: this.database,
 +        params: this.params,
 +        view: this.view,
 +        design: this.design,
 +        rows: this.rows
 +      });
 +
 +    },
 +
 +    fetch: function() {
 +      var deferred = FauxtonAPI.Deferred();
 +      this.reset(this.rows, {silent: true});
 +
 +      this.viewMeta = {
 +        total_rows: this.rows.length,
 +        offset: 0,
 +        update_seq: false
 +      };
 +
 +      deferred.resolve();
 +      return deferred;
 +    },
 +
 +    recordStart: function () {
 +      return 1;
 +    },
 +
 +    totalRows: function() {
 +      return this.viewMeta.total_rows || "unknown";
 +    },
 +
 +    updateSeq: function() {
 +      return this.viewMeta.update_seq || false;
 +    },
 +
 +    buildAllDocs: function(){
 +      this.fetch();
 +    },
 +
 +    allDocs: function(){
 +      return this.models;
 +    }
 +  });
 +
 +
 +
 +  return Documents;
 +});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/752819c1/src/fauxton/app/addons/documents/routes.js
----------------------------------------------------------------------
diff --cc src/fauxton/app/addons/documents/routes.js
index b1c16ef,0000000..9f66619
mode 100644,000000..100644
--- a/src/fauxton/app/addons/documents/routes.js
+++ b/src/fauxton/app/addons/documents/routes.js
@@@ -1,408 -1,0 +1,408 @@@
 +// Licensed under the Apache License, Version 2.0 (the "License"); you may not
 +// use this file except in compliance with the License. You may obtain a copy of
 +// the License at
 +//
 +//   http://www.apache.org/licenses/LICENSE-2.0
 +//
 +// Unless required by applicable law or agreed to in writing, software
 +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 +// License for the specific language governing permissions and limitations under
 +// the License.
 +
 +define([
 +       "app",
 +
 +       "api",
 +
 +       // Modules
 +       "addons/documents/views",
 +       "addons/databases/base"
 +],
 +
 +function(app, FauxtonAPI, Documents, Databases) {
 +
 +  var DocEditorRouteObject = FauxtonAPI.RouteObject.extend({
 +    layout: "one_pane",
 +    disableLoader: true,
 +    selectedHeader: "Databases",
 +    initialize: function(route, masterLayout, options) {
 +      var databaseName = options[0];
 +      this.docID = options[1]||'new';
 +
 +      this.database = this.database || new Databases.Model({id: databaseName});
 +      this.doc = new Documents.Doc({
 +        _id: this.docID
 +      }, {
 +        database: this.database
 +      });
 +
 +      this.tabsView = this.setView("#tabs", new Documents.Views.FieldEditorTabs({
 +        disableLoader: true,
 +        selected: "code_editor",
 +        model: this.doc
 +      }));
 +
 +    },
 +
 +    routes: {
 +      // We are hiding the field_editor for this first release
 +      // "database/:database/:doc/field_editor": "field_editor",
 +      "database/:database/:doc/code_editor": "code_editor",
 +      "database/:database/:doc": "code_editor"
 +    },
 +
 +    events: {
 +      "route:reRenderDoc": "reRenderDoc",
 +      "route:duplicateDoc": "duplicateDoc"
 +    },
 +
 +    crumbs: function() {
 +      return [
 +        {"name": this.database.id, "link": Databases.databaseUrl(this.database)},
 +        {"name": this.docID, "link": "#"}
 +      ];
 +    },
 +
 +    code_editor: function (database, doc) {
 +      this.tabsView.updateSelected('code_editor');
 +
 +      this.docView = this.setView("#dashboard-content", new Documents.Views.Doc({
 +        model: this.doc,
 +        database: this.database
 +      }));
 +    },
 +
 +    reRenderDoc: function () {
 +      this.docView.forceRender();
 +    },
 +
 +    field_editor: function(events) {
 +      this.tabsView.updateSelected('field_editor');
 +      this.docView = this.setView("#dashboard-content", new Documents.Views.DocFieldEditor({
 +        model: this.doc
 +      }));
 +    },
 +
 +    duplicateDoc: function (newId) {
 +      var doc = this.doc,
 +      docView = this.docView,
 +      database = this.database;
 +
 +      doc.copy(newId).then(function () {
 +        doc.set({_id: newId}); 
 +        docView.forceRender();
-         FauxtonAPI.navigate('/database/' + database.safeID() + '/' + app.mixins.safeURLName(newId), {trigger: true});
++        FauxtonAPI.navigate('/database/' + database.safeID() + '/' + app.utils.safeURLName(newId), {trigger: true});
 +        FauxtonAPI.addNotification({
 +          msg: "Document has been duplicated."
 +        });
 +
 +      }, function (error) {
 +        var errorMsg = "Could not duplicate document, reason: " + error.responseText + ".";
 +        FauxtonAPI.addNotification({
 +          msg: errorMsg,
 +          type: "error"
 +        });
 +      });
 +    },
 +
 +    apiUrl: function() {
 +      return [this.doc.url("apiurl"), this.doc.documentation()];
 +    }
 +  });
 +
 +  var NewDocEditorRouteObject = DocEditorRouteObject.extend({
 +    initialize: function (route, masterLayout, options) {
 +      var databaseName = options[0];
 +
 +      this.database = this.database || new Databases.Model({id: databaseName});
 +      this.doc = new Documents.NewDoc(null,{
 +        database: this.database
 +      });
 +
 +      this.tabsView = this.setView("#tabs", new Documents.Views.FieldEditorTabs({
 +        selected: "code_editor",
 +        model: this.doc
 +      }));
 +
 +    },
 +    crumbs: function() {
 +      return [
 +        {"name": this.database.id, "link": Databases.databaseUrl(this.database)},
 +        {"name": "New", "link": "#"}
 +      ];
 +    },
 +    routes: {
 +      "database/:database/new": "code_editor"
 +    },
 +    selectedHeader: "Databases",
 +
 +  });
 +
 +  var DocumentsRouteObject = FauxtonAPI.RouteObject.extend({
 +    layout: "with_tabs_sidebar",
 +    selectedHeader: "Databases",
 +    routes: {
 +      "database/:database/_all_docs(:extra)": "allDocs", 
 +      "database/:database/_design/:ddoc/_view/:view": {
 +        route: "viewFn",
 +        roles: ['_admin']
 +      },
 +      "database/:database/new_view": "newViewEditor"
 +    },
 +
 +    events: {
 +      "route:updateAllDocs": "updateAllDocsFromView",
 +      "route:updatePreviewDocs": "updateAllDocsFromPreview",
 +      "route:reloadDesignDocs": "reloadDesignDocs",
 +      "route:paginate": "paginate"
 +    },
 +
 +    initialize: function (route, masterLayout, options) {
 +      var docOptions = app.getParams();
 +      docOptions.include_docs = true;
 +
 +      this.databaseName = options[0];
 +
 +      this.data = {
 +        database: new Databases.Model({id:this.databaseName})
 +      };
 +
 +      this.data.designDocs = new Documents.AllDocs(null, {
 +        database: this.data.database,
 +        params: {startkey: '"_design"',
 +          endkey: '"_design1"',
 +          include_docs: true}
 +      });
 +
 +      this.sidebar = this.setView("#sidebar-content", new Documents.Views.Sidebar({
 +        collection: this.data.designDocs,
 +        database: this.data.database
 +      }));
 +    },
 +
 +    establish: function () {
 +      return this.data.designDocs.fetch();
 +    },
 +
 +    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) {
 +        this.sidebar.setSelectedTab('design-docs');
 +      } else {
 +        this.sidebar.setSelectedTab('all-docs');
 +      }
 +
 +      if (this.viewEditor) { this.viewEditor.remove(); }
 +
 +      this.toolsView = this.setView("#dashboard-upper-menu", new Documents.Views.JumpToDoc({
 +        database: this.data.database,
 +        collection: this.data.database.allDocs
 +      }));
 +
 +      this.setView("#dashboard-upper-content", new Documents.Views.AllDocsLayout({
 +        database: this.data.database,
 +        collection: this.data.database.allDocs,
 +        params: docOptions
 +      }));
 +
 +      this.documentsView = this.setView("#dashboard-lower-content", new Documents.Views.AllDocsList({
 +        collection: this.data.database.allDocs
 +      }));
 +
 +      this.crumbs = [
 +        {"name": this.data.database.id, "link": Databases.databaseUrl(this.data.database)}
 +      ];
 +
 +      this.apiUrl = [this.data.database.allDocs.url("apiurl"), this.data.database.allDocs.documentation() ];
 +    },
 +
 +    viewFn: function (databaseName, ddoc, view) {
 +      var params = app.getParams(),
 +          decodeDdoc = decodeURIComponent(ddoc);
 +
 +      view = view.replace(/\?.*$/,'');
 +
 +      this.data.indexedDocs = new Documents.IndexCollection(null, {
 +        database: this.data.database,
 +        design: decodeDdoc,
 +        view: view,
 +        params: params
 +      });
 +
 +
 +
 +      var ddocInfo = {
 +        id: "_design/" + decodeDdoc,
 +        currView: view,
 +        designDocs: this.data.designDocs
 +      };
 +
 +      this.viewEditor = this.setView("#dashboard-upper-content", new Documents.Views.ViewEditor({
 +        model: this.data.database,
 +        ddocs: this.data.designDocs,
 +        viewName: view,
 +        params: params,
 +        newView: false,
 +        database: this.data.database,
 +        ddocInfo: ddocInfo
 +      }));
 +
 +      if (this.toolsView) { this.toolsView.remove(); }
 +
 +      this.documentsView = this.setView("#dashboard-lower-content", new Documents.Views.AllDocsList({
 +        database: this.data.database,
 +        collection: this.data.indexedDocs,
 +        nestedView: Documents.Views.Row,
 +        viewList: true,
 +        ddocInfo: ddocInfo
 +      }));
 +
-       this.sidebar.setSelectedTab(app.mixins.removeSpecialCharacters(ddoc) + '_' + app.mixins.removeSpecialCharacters(view));
++      this.sidebar.setSelectedTab(app.utils.removeSpecialCharacters(ddoc) + '_' + app.utils.removeSpecialCharacters(view));
 +
 +      this.crumbs = function () {
 +        return [
 +          {"name": this.data.database.id, "link": Databases.databaseUrl(this.data.database)},
 +        ];
 +      };
 +
 +      this.apiUrl = [this.data.indexedDocs.url("apiurl"), "docs"];
 +    },
 +
 +    newViewEditor: function () {
 +      var params = app.getParams();
 +
 +      if (this.toolsView) {
 +        this.toolsView.remove();
 +      }
 +
 +      this.viewEditor = this.setView("#dashboard-upper-content", new Documents.Views.ViewEditor({
 +        ddocs: this.data.designDocs,
 +        params: params,
 +        database: this.data.database,
 +        newView: true
 +      }));
 +
 +      this.sidebar.setSelectedTab('new-view');
 +      this.crumbs = function () {
 +        return [
 +          {"name": this.data.database.id, "link": Databases.databaseUrl(this.data.database)},
 +        ];
 +      };
 +    },
 +
 +    updateAllDocsFromView: function (event) {
 +      var view = event.view,
 +          docOptions = app.getParams(),
 +          ddoc = event.ddoc;
 +
 +      if (event.allDocs) {
 +        docOptions.include_docs = true;
 +        this.data.database.buildAllDocs(docOptions);
 +        return;
 +      }
 +
 +      this.data.indexedDocs = new Documents.IndexCollection(null, {
 +        database: this.data.database,
 +        design: ddoc,
 +        view: view,
 +        params: app.getParams()
 +      });
 +
 +      this.documentsView = this.setView("#dashboard-lower-content", new Documents.Views.AllDocsList({
 +        database: this.data.database,
 +        collection: this.data.indexedDocs,
 +        nestedView: Documents.Views.Row,
 +        viewList: true
 +      }));
 +    },
 +
 +    updateAllDocsFromPreview: function (event) {
 +      var view = event.view,
 +      rows = event.rows,
 +      ddoc = event.ddoc;
 +
 +      this.data.indexedDocs = new Documents.PouchIndexCollection(null, {
 +        database: this.data.database,
 +        design: ddoc,
 +        view: view,
 +        rows: rows
 +      });
 +
 +      this.documentsView = this.setView("#dashboard-lower-content", new Documents.Views.AllDocsList({
 +        database: this.data.database,
 +        collection: this.data.indexedDocs,
 +        nestedView: Documents.Views.Row,
 +        viewList: true
 +      }));
 +    },
 +
 +    paginate: function (direction) {
 +      _.extend(this.documentsView.collection.params, app.getParams());
 +      this.documentsView.forceRender();
 +      if (direction === 'next') {
 +        this.documentsView.collection.skipFirstItem = true;
 +      } else {
 +        this.documentsView.collection.skipFirstItem = false;
 +      }
 +    },
 +
 +    reloadDesignDocs: function (event) {
 +      this.sidebar.forceRender();
 +
 +      if (event && event.selectedTab) {
 +        this.sidebar.setSelectedTab(event.selectedTab);
 +      }
 +    }
 +
 +  });
 +
 +  var ChangesRouteObject = FauxtonAPI.RouteObject.extend({
 +    layout: "with_tabs",
 +    selectedHeader: "Databases",
 +    crumbs: function () {
 +      return [
 +        {"name": this.database.id, "link": Databases.databaseUrl(this.database)},
 +        {"name": "_changes", "link": "/_changes"}
 +      ];
 +    },
 +
 +    routes: {
 +      "database/:database/_changes(:params)": "changes"
 +    },
 +
 +    initialize: function (route, masterLayout, options) {
 +      this.databaseName = options[0];
 +      this.database = new Databases.Model({id: this.databaseName});
 +
 +      var docOptions = app.getParams();
 +
 +      this.database.buildChanges(docOptions);
 +
 +      this.setView("#tabs", new Documents.Views.Tabs({
 +        collection: this.designDocs,
 +        database: this.database,
 +        active_id: 'changes'
 +      }));
 +    },
 +
 +    changes: function (event) {
 +      this.setView("#dashboard-content", new Documents.Views.Changes({
 +        model: this.database
 +      }));
 +    },
 +
 +    apiUrl: function() {
 +      return [this.database.url("apiurl"), this.database.documentation()];
 +    }
 +
 +  });
 +
 +  Documents.RouteObjects = [DocEditorRouteObject, NewDocEditorRouteObject, DocumentsRouteObject, ChangesRouteObject];
 +
 +  return Documents;
 +});


Mime
View raw message