Return-Path: X-Original-To: apmail-couchdb-commits-archive@www.apache.org Delivered-To: apmail-couchdb-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 710C010145 for ; Wed, 12 Feb 2014 06:24:28 +0000 (UTC) Received: (qmail 1822 invoked by uid 500); 12 Feb 2014 06:20:05 -0000 Delivered-To: apmail-couchdb-commits-archive@couchdb.apache.org Received: (qmail 1400 invoked by uid 500); 12 Feb 2014 06:19:59 -0000 Mailing-List: contact commits-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list commits@couchdb.apache.org Received: (qmail 1297 invoked by uid 99); 12 Feb 2014 06:19:56 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 12 Feb 2014 06:19:56 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 1DE60553A7; Wed, 12 Feb 2014 06:19:55 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: davisp@apache.org To: commits@couchdb.apache.org Date: Wed, 12 Feb 2014 06:19:59 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [05/52] [abbrv] fauxton commit: updated refs/heads/import-master to d11b90b Fauxton: move modules to addons Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/5f9a88f6 Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/5f9a88f6 Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/5f9a88f6 Branch: refs/heads/import-master Commit: 5f9a88f6913951fcc83214e9a1c94a7fdb988e79 Parents: 27542b1 Author: Garren Smith Authored: Mon Jan 6 12:33:00 2014 +0200 Committer: Garren Smith Committed: Mon Jan 13 10:51:51 2014 +0200 ---------------------------------------------------------------------- app/addons/activetasks/resources.js | 2 +- app/addons/compaction/routes.js | 2 +- app/addons/databases/base.js | 37 + app/addons/databases/resources.js | 193 ++ app/addons/databases/routes.js | 69 + app/addons/databases/templates/item.html | 24 + app/addons/databases/templates/list.html | 35 + app/addons/databases/templates/newdatabase.html | 17 + app/addons/databases/templates/sidebar.html | 31 + app/addons/databases/views.js | 255 +++ app/addons/documents/base.js | 24 + app/addons/documents/resources.js | 646 ++++++ app/addons/documents/routes.js | 409 ++++ .../documents/templates/advanced_options.html | 97 + .../documents/templates/all_docs_item.html | 26 + .../documents/templates/all_docs_layout.html | 20 + .../documents/templates/all_docs_list.html | 43 + .../documents/templates/all_docs_number.html | 21 + app/addons/documents/templates/changes.html | 38 + app/addons/documents/templates/ddoc_info.html | 28 + .../templates/design_doc_selector.html | 35 + app/addons/documents/templates/doc.html | 55 + .../documents/templates/doc_field_editor.html | 74 + .../templates/doc_field_editor_tabs.html | 19 + .../templates/duplicate_doc_modal.html | 36 + app/addons/documents/templates/edit_tools.html | 44 + .../documents/templates/index_menu_item.html | 17 + .../documents/templates/index_row_docular.html | 26 + .../documents/templates/index_row_tabular.html | 25 + app/addons/documents/templates/jumpdoc.html | 19 + app/addons/documents/templates/search.html | 15 + app/addons/documents/templates/sidebar.html | 67 + app/addons/documents/templates/tabs.html | 18 + .../documents/templates/upload_modal.html | 42 + app/addons/documents/templates/view_editor.html | 87 + app/addons/documents/tests/resourcesSpec.js | 84 + app/addons/documents/views.js | 1855 ++++++++++++++++++ app/addons/fauxton/base.js | 271 +++ app/addons/fauxton/components.js | 337 ++++ app/addons/fauxton/layout.js | 98 + app/addons/fauxton/templates/api_bar.html | 30 + app/addons/fauxton/templates/breadcrumbs.html | 24 + app/addons/fauxton/templates/footer.html | 15 + .../fauxton/templates/index_pagination.html | 24 + app/addons/fauxton/templates/nav_bar.html | 75 + app/addons/fauxton/templates/notification.html | 18 + app/addons/fauxton/templates/pagination.html | 31 + app/addons/permissions/routes.js | 2 +- app/addons/pouchdb/base.js | 47 + app/addons/pouchdb/pouch.collate.js | 115 ++ app/addons/pouchdb/pouchdb.mapreduce.js | 324 +++ app/addons/replication/views.js | 2 +- app/addons/stats/resources.js | 2 +- app/addons/verifyinstall/resources.js | 4 +- app/api.js | 2 +- app/app.js | 8 +- app/modules/databases/base.js | 37 - app/modules/databases/resources.js | 193 -- app/modules/databases/routes.js | 69 - app/modules/databases/views.js | 255 --- app/modules/documents/base.js | 24 - app/modules/documents/resources.js | 646 ------ app/modules/documents/routes.js | 409 ---- app/modules/documents/tests/resourcesSpec.js | 84 - app/modules/documents/views.js | 1855 ------------------ app/modules/fauxton/base.js | 275 --- app/modules/fauxton/components.js | 337 ---- app/modules/fauxton/layout.js | 98 - app/modules/pouchdb/base.js | 47 - app/modules/pouchdb/pouch.collate.js | 115 -- app/modules/pouchdb/pouchdb.mapreduce.js | 324 --- app/router.js | 39 +- settings.json.default | 3 + 73 files changed, 5961 insertions(+), 4813 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/activetasks/resources.js ---------------------------------------------------------------------- diff --git a/app/addons/activetasks/resources.js b/app/addons/activetasks/resources.js index ca732fb..3ac0898 100644 --- a/app/addons/activetasks/resources.js +++ b/app/addons/activetasks/resources.js @@ -13,7 +13,7 @@ define([ "app", "backbone", - "modules/fauxton/base", + "addons/fauxton/base", "d3" ], http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/compaction/routes.js ---------------------------------------------------------------------- diff --git a/app/addons/compaction/routes.js b/app/addons/compaction/routes.js index 2a33e07..ff15c88 100644 --- a/app/addons/compaction/routes.js +++ b/app/addons/compaction/routes.js @@ -17,7 +17,7 @@ define([ // Modules "addons/compaction/views", - "modules/databases/resources" + "addons/databases/resources" ], function(app, FauxtonAPI, Compaction, Databases) { http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/databases/base.js ---------------------------------------------------------------------- diff --git a/app/addons/databases/base.js b/app/addons/databases/base.js new file mode 100644 index 0000000..1a3dc66 --- /dev/null +++ b/app/addons/databases/base.js @@ -0,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); + + return ["/database/", dbname, "/_all_docs?limit=" + Databases.DocLimit].join(''); + }; + + return Databases; +}); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/databases/resources.js ---------------------------------------------------------------------- diff --git a/app/addons/databases/resources.js b/app/addons/databases/resources.js new file mode 100644 index 0000000..b6d6536 --- /dev/null +++ b/app/addons/databases/resources.js @@ -0,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")); + }, + safeID: function() { + return app.mixins.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), + name: database + }; + }); + } + }); + + return Databases; +}); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/databases/routes.js ---------------------------------------------------------------------- diff --git a/app/addons/databases/routes.js b/app/addons/databases/routes.js new file mode 100644 index 0000000..c413018 --- /dev/null +++ b/app/addons/databases/routes.js @@ -0,0 +1,69 @@ +// 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/resources", + // TODO:: fix the include flow modules so we don't have to require views here + "addons/databases/views" +], + +function(app, FauxtonAPI, Databases, Views) { + + var AllDbsRouteObject = FauxtonAPI.RouteObject.extend({ + layout: "one_pane", + + crumbs: [ + {"name": "Databases", "link": "/_all_dbs"} + ], + + routes: { + "": "allDatabases", + "index.html": "allDatabases", + "_all_dbs(:params)": "allDatabases" + }, + + apiUrl: function() { + return [this.databases.url("apiurl"), this.databases.documentation()]; + }, + + selectedHeader: "Databases", + + initialize: function() { + this.databases = new Databases.List(); + this.deferred = FauxtonAPI.Deferred(); + }, + + allDatabases: function() { + var params = app.getParams(), + dbPage = params.page; + + this.databasesView = this.setView("#dashboard-content", new Views.List({ + collection: this.databases + })); + + this.databasesView.setPage(dbPage); + }, + + establish: function() { + return [this.databases.fetch()]; + } + }); + + Databases.RouteObjects = [AllDbsRouteObject]; + + return Databases; +}); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/databases/templates/item.html ---------------------------------------------------------------------- diff --git a/app/addons/databases/templates/item.html b/app/addons/databases/templates/item.html new file mode 100644 index 0000000..e2f8071 --- /dev/null +++ b/app/addons/databases/templates/item.html @@ -0,0 +1,24 @@ + + + + <%= database.get("name") %> + +<%= database.status.humanSize() %> +<%= database.status.numDocs() %> +<%= database.status.updateSeq() %> + + " href="#/replication/new/<%=encoded%>"> + " href="#/database/<%=encoded%>/permissions"> + http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/databases/templates/list.html ---------------------------------------------------------------------- diff --git a/app/addons/databases/templates/list.html b/app/addons/databases/templates/list.html new file mode 100644 index 0000000..31c0977 --- /dev/null +++ b/app/addons/databases/templates/list.html @@ -0,0 +1,35 @@ + + +
+
+ + + +
+ + + + + + + + + + +
NameSize# of DocsUpdate SeqActions
+
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/databases/templates/newdatabase.html ---------------------------------------------------------------------- diff --git a/app/addons/databases/templates/newdatabase.html b/app/addons/databases/templates/newdatabase.html new file mode 100644 index 0000000..b357e0b --- /dev/null +++ b/app/addons/databases/templates/newdatabase.html @@ -0,0 +1,17 @@ + + +Add New Database + + http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/databases/templates/sidebar.html ---------------------------------------------------------------------- diff --git a/app/addons/databases/templates/sidebar.html b/app/addons/databases/templates/sidebar.html new file mode 100644 index 0000000..a8bbd89 --- /dev/null +++ b/app/addons/databases/templates/sidebar.html @@ -0,0 +1,31 @@ + + +
+ +
+
+
+ +
+ +
+ + + +
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/databases/views.js ---------------------------------------------------------------------- diff --git a/app/addons/databases/views.js b/app/addons/databases/views.js new file mode 100644 index 0000000..80d64ed --- /dev/null +++ b/app/addons/databases/views.js @@ -0,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")), + 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){ + // 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(''); + 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; + 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-fauxton/blob/5f9a88f6/app/addons/documents/base.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/base.js b/app/addons/documents/base.js new file mode 100644 index 0000000..cb68a31 --- /dev/null +++ b/app/addons/documents/base.js @@ -0,0 +1,24 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +define([ + "app", + + "api", + + // Modules + "addons/documents/routes" +], + +function(app, FauxtonAPI, Documents) { + return Documents; +}); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/documents/resources.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/resources.js b/app/addons/documents/resources.js new file mode 100644 index 0000000..5254302 --- /dev/null +++ b/app/addons/documents/resources.js @@ -0,0 +1,646 @@ +// 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); + } 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); + }else{ + return app.mixins.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); + } + + }); + + Documents.ViewRow = Backbone.Model.extend({ + // this is a hack so that backbone.collections doesn't group + // these by id and reduce the number of items returned. + idAttribute: "_id", + + docType: function() { + if (!this.id) return "reduction"; + + 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); + }, + + 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, params) { + if (params) { + this.params = params; + } else { + this.params = {reduce: false}; + } + + this.params.limit = num; + 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 url = [startOfUrl, this.database.safeID(), "_design", design, this.idxType, view]; + return url.join("/") + query; + }, + + urlNextPage: function (num, lastId) { + if (!lastId) { + lastDoc = this.last(); + } + + var id = lastDoc.get("id"); + if (id) { + this.params.startkey_docid = id; + } + + this.params.startkey = JSON.stringify(lastDoc.get('key')); + this.params.limit = num + 1; + return this.url('app'); + }, + + urlPreviousPage: function (num, params) { + if (params) { + this.params = params; + } else { + this.params = {reduce: false}; + } + + this.params.limit = num; + 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() { + if (this.params.reduce) { return "unknown_reduce";} + + 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-fauxton/blob/5f9a88f6/app/addons/documents/routes.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/routes.js b/app/addons/documents/routes.js new file mode 100644 index 0000000..d120feb --- /dev/null +++ b/app/addons/documents/routes.js @@ -0,0 +1,409 @@ +// 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.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); + + 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.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; + + this.documentsView && this.documentsView.remove(); + + if (event.allDocs) { + this.data.database.buildAllDocs(docOptions); + this.documentsView = this.setView("#dashboard-lower-content", new Documents.Views.AllDocsList({ + collection: this.data.database.allDocs + })); + 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; +}); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/documents/templates/advanced_options.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/advanced_options.html b/app/addons/documents/templates/advanced_options.html new file mode 100644 index 0000000..8e96574 --- /dev/null +++ b/app/addons/documents/templates/advanced_options.html @@ -0,0 +1,97 @@ + +
+
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+
+
+
+ + + <% if (hasReduce) { %> + + +
+ + <% } else{ %> +
+ <% } %> + +
+ + + + +
+ +
+ + + + +
+
+
+ +
+
+
+ + <% if (showPreview) { %> + + <% } %> +
+
+
+
+ + http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/documents/templates/all_docs_item.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/all_docs_item.html b/app/addons/documents/templates/all_docs_item.html new file mode 100644 index 0000000..bfedaaa --- /dev/null +++ b/app/addons/documents/templates/all_docs_item.html @@ -0,0 +1,26 @@ + + + + +
+
<%- doc.prettyJSON() %>
+ <% if (doc.isEditable()) { %> + + <% } %> +
+ http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/documents/templates/all_docs_layout.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/all_docs_layout.html b/app/addons/documents/templates/all_docs_layout.html new file mode 100644 index 0000000..526c200 --- /dev/null +++ b/app/addons/documents/templates/all_docs_layout.html @@ -0,0 +1,20 @@ + + +
+
+
+
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/documents/templates/all_docs_list.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/all_docs_list.html b/app/addons/documents/templates/all_docs_list.html new file mode 100644 index 0000000..335b040 --- /dev/null +++ b/app/addons/documents/templates/all_docs_list.html @@ -0,0 +1,43 @@ + + +
+ <% if (!viewList) { %> +
+
+ + + <% if (expandDocs) { %> + + <% } else { %> + + <% } %> +
+
+ <% } %> +

+ +

+ + <% if (requestDuration) { %> + + View request duration: <%= requestDuration %> + + <% } %> +

+ + +
+
+
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/documents/templates/all_docs_number.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/all_docs_number.html b/app/addons/documents/templates/all_docs_number.html new file mode 100644 index 0000000..c4ea8f6 --- /dev/null +++ b/app/addons/documents/templates/all_docs_number.html @@ -0,0 +1,21 @@ + +<% if (totalRows === "unknown"){ %> + Showing 0 documents. Create your first document. +<% } else { %> + Showing <%=offset%> - <%= numModels %> of <%= totalRows %> rows +<%}%> +<% if (updateSeq) { %> + -- Update Sequence: <%= updateSeq %> +<% } %> http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/documents/templates/changes.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/changes.html b/app/addons/documents/templates/changes.html new file mode 100644 index 0000000..9408979 --- /dev/null +++ b/app/addons/documents/templates/changes.html @@ -0,0 +1,38 @@ + + + + + + + + + + + <% _.each(changes, function (change) { %> + + + <% if (change.deleted) { %> + + <% } else { %> + + <% } %> + + + + <% }); %> + +
seq id changes deleted?
<%= change.seq %> <%= change.id %> <%= change.id %> +
  <%- JSON.stringify({changes: change.changes, doc: change.doc}, null, " ") %> 
+
<%= change.deleted ? "true" : "false" %>
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/documents/templates/ddoc_info.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/ddoc_info.html b/app/addons/documents/templates/ddoc_info.html new file mode 100644 index 0000000..ed0aed6 --- /dev/null +++ b/app/addons/documents/templates/ddoc_info.html @@ -0,0 +1,28 @@ + +
+

Design Doc MetaData

+
+ <% i=0; _.map(view_index, function (val, key) { %> + <% if(i%2==0){%> +
+ <% }; %> +
<%= key %> : <%= val %>
+ <% if(i%2==1){%> +
+ <% }; %> + <% ++i; + }); %> +
+
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/documents/templates/design_doc_selector.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/design_doc_selector.html b/app/addons/documents/templates/design_doc_selector.html new file mode 100644 index 0000000..7bbe310 --- /dev/null +++ b/app/addons/documents/templates/design_doc_selector.html @@ -0,0 +1,35 @@ + +
+ + +
+ + http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/documents/templates/doc.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/doc.html b/app/addons/documents/templates/doc.html new file mode 100644 index 0000000..10bbf8b --- /dev/null +++ b/app/addons/documents/templates/doc.html @@ -0,0 +1,55 @@ + + +
+
+ +
+
+ + +
+ +
+ <% if (attachments) { %> +
+ + View Attachments + + + +
+ <% } %> + + +
+ + + + +
+
+
+ +
<%- JSON.stringify(doc.attributes, null, " ") %>
+ +
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/documents/templates/doc_field_editor.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/doc_field_editor.html b/app/addons/documents/templates/doc_field_editor.html new file mode 100644 index 0000000..77d9278 --- /dev/null +++ b/app/addons/documents/templates/doc_field_editor.html @@ -0,0 +1,74 @@ + + +
+
+ +
+ + + +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + <% _.each(doc, function(value, key) { %> + + + + + + <% }); %> + + + + <%_.each(attachments, function (att) { %> + + + + + <% }) %> + +
+ KeyValue
+ +
+ Attachments +
+ <%= att.fileName %> + <%= att.contentType %>, <%= formatSize(att.size)%> +
+ New field + +
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/documents/templates/doc_field_editor_tabs.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/doc_field_editor_tabs.html b/app/addons/documents/templates/doc_field_editor_tabs.html new file mode 100644 index 0000000..766647c --- /dev/null +++ b/app/addons/documents/templates/doc_field_editor_tabs.html @@ -0,0 +1,19 @@ + + + http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5f9a88f6/app/addons/documents/templates/duplicate_doc_modal.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/duplicate_doc_modal.html b/app/addons/documents/templates/duplicate_doc_modal.html new file mode 100644 index 0000000..3f374b6 --- /dev/null +++ b/app/addons/documents/templates/duplicate_doc_modal.html @@ -0,0 +1,36 @@ + + +