summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Branca <chewbranca@gmail.com>2013-03-15 09:53:26 -0700
committerRussell Branca <chewbranca@gmail.com>2013-03-15 09:53:26 -0700
commitc26433204577d52d1148bb9d5f9d7ca960423f68 (patch)
treeb46830562bcdf8a5e46f11b5c1fdbcfee28e560b
parent2e75c7a4495df47c5fc23a8cf8545ea0999ee590 (diff)
parent2a0c0b2b0d7b73b3877272308c7aadbb57002cac (diff)
downloadcouchdb-c26433204577d52d1148bb9d5f9d7ca960423f68.tar.gz
Merge remote-tracking branch 'github/pr/52' into fauxton
-rw-r--r--src/fauxton/.gitignore11
-rw-r--r--src/fauxton/app/addons/contribute/base.js4
-rw-r--r--src/fauxton/app/initialize.js2
-rw-r--r--src/fauxton/app/modules/databases/resources.js2
-rw-r--r--src/fauxton/app/modules/documents/resources.js27
-rw-r--r--src/fauxton/app/modules/documents/routes.js10
-rw-r--r--src/fauxton/app/modules/documents/views.js106
-rw-r--r--src/fauxton/app/modules/pouchdb/base.js57
-rw-r--r--src/fauxton/app/modules/pouchdb/pouch.collate.js115
-rw-r--r--src/fauxton/app/modules/pouchdb/pouchdb.mapreduce.js286
-rw-r--r--src/fauxton/app/router.js11
-rw-r--r--src/fauxton/app/templates/databases/sidebar.html5
-rw-r--r--src/fauxton/app/templates/documents/all_docs_list.html177
-rw-r--r--src/fauxton/app/templates/documents/sidebar.html4
-rw-r--r--src/fauxton/app/templates/documents/tabs.html6
-rw-r--r--src/fauxton/app/templates/documents/view_editor.html135
-rw-r--r--src/fauxton/app/templates/fauxton/api_bar.html9
-rw-r--r--src/fauxton/assets/index.underscore2
-rw-r--r--src/fauxton/couchapp.js11
-rw-r--r--src/fauxton/grunt.js75
-rw-r--r--src/fauxton/settings.json.default11
21 files changed, 849 insertions, 217 deletions
diff --git a/src/fauxton/.gitignore b/src/fauxton/.gitignore
new file mode 100644
index 000000000..56d0703ae
--- /dev/null
+++ b/src/fauxton/.gitignore
@@ -0,0 +1,11 @@
+node_modules
+dist
+build
+app/load_addons.js
+!app/addons/
+app/addons/*
+!app/addons/config
+!app/addons/logs
+!app/addons/contribute
+settings.json*
+!settings.json.default \ No newline at end of file
diff --git a/src/fauxton/app/addons/contribute/base.js b/src/fauxton/app/addons/contribute/base.js
index 50a12cba0..1bc9fd3b0 100644
--- a/src/fauxton/app/addons/contribute/base.js
+++ b/src/fauxton/app/addons/contribute/base.js
@@ -5,13 +5,17 @@ define([
],
function($, _){
$.contribute = function(message, file){
+ /*
var JST = window.JST = window.JST || {};
var template = JST['app/addons/contribute/templates/modal.html'];
console.log(template);
var compiled = template({message: message, file: file});
+ */
console.log('contribute!contribute!monorail!contribute!');
+ /*
console.log(compiled);
var elem = $(compiled);
elem.modal('show');
+ */
};
});
diff --git a/src/fauxton/app/initialize.js b/src/fauxton/app/initialize.js
index eb4a29234..6e4a652a0 100644
--- a/src/fauxton/app/initialize.js
+++ b/src/fauxton/app/initialize.js
@@ -28,7 +28,7 @@ function(app, _, Bootstrap) {
// TODO: pick this up wither at build time or from the browser
root: "/_utils/fauxton/",
// Is this sufficient?
- host: window.location.origin,
+ host: window.location.protocol + "//" + window.location.host,
renderView: function(baseView, selector, view, options, callback) {
baseView.setView(selector, new view(options)).render().then(callback);
diff --git a/src/fauxton/app/modules/databases/resources.js b/src/fauxton/app/modules/databases/resources.js
index 2b8f3ec7c..5549a709a 100644
--- a/src/fauxton/app/modules/databases/resources.js
+++ b/src/fauxton/app/modules/databases/resources.js
@@ -46,7 +46,7 @@ function(app, FauxtonAPI, Documents) {
url: function(context) {
if (context === "index") {
return "/database/" + this.id + "/_all_docs";
- } else if (context === "changes") {
+ } else if (context === "changes") {
return "/database/" + this.id + "/_changes?descending=true&limit=100";
} else if (context === "app") {
return "/database/" + this.id;
diff --git a/src/fauxton/app/modules/documents/resources.js b/src/fauxton/app/modules/documents/resources.js
index 6cd5d65e6..372436976 100644
--- a/src/fauxton/app/modules/documents/resources.js
+++ b/src/fauxton/app/modules/documents/resources.js
@@ -160,7 +160,21 @@ function(app, FauxtonAPI, Views) {
return app.host + "/" + this.database.id + "/_all_docs" + query;
},
+ totalRows: function() {
+ return this.viewMeta.total_rows || "unknown";
+ },
+
+ updateSeq: function() {
+ return this.viewMeta.update_seq || false;
+ },
+
parse: function(resp) {
+ that = this;
+ this.viewMeta = {
+ total_rows: resp.total_rows,
+ offest: resp.offest,
+ update_seq: resp.update_seq
+ };
return _.map(resp.rows, function(row) {
return {
_id: row.id,
@@ -193,8 +207,21 @@ function(app, FauxtonAPI, Views) {
return url.join("/") + query;
},
+ totalRows: function() {
+ return this.viewMeta.total_rows || "unknown";
+ },
+
+ updateSeq: function() {
+ return this.viewMeta.update_seq || false;
+ },
+
parse: function(resp) {
that = this;
+ this.viewMeta = {
+ total_rows: resp.total_rows,
+ offest: resp.offest,
+ update_seq: resp.update_seq
+ };
return _.map(resp.rows, function(row) {
return {
value: row.value,
diff --git a/src/fauxton/app/modules/documents/routes.js b/src/fauxton/app/modules/documents/routes.js
index 801fa607d..34b00d846 100644
--- a/src/fauxton/app/modules/documents/routes.js
+++ b/src/fauxton/app/modules/documents/routes.js
@@ -209,6 +209,10 @@ function(app, FauxtonAPI, Documents, Databases) {
"database/:database/:doc/code_editor": codeEditorCallback,
"database/:database/:doc": codeEditorCallback,
+ "database/:database/_design%2F:doc": function(database, doc) {
+ var docID = "_design/"+doc;
+ return codeEditorCallback(database, docID);
+ },
// HACK
// The ordering of routes is different in this object that the
@@ -268,7 +272,7 @@ function(app, FauxtonAPI, Documents, Databases) {
};
},
- "database/:database/_:handler": function(databaseName, page) {
+ "database/:database/_all_docs(:extra)": function(databaseName, page) {
var data = {
database: new Databases.Model({id:databaseName})
};
@@ -378,6 +382,7 @@ function(app, FauxtonAPI, Documents, Databases) {
var ddocInfo = {
id: "_design/" + ddoc,
+ currView: view,
designDocs: data.designDocs
};
@@ -396,7 +401,8 @@ function(app, FauxtonAPI, Documents, Databases) {
}),
"#sidebar-content": new Documents.Views.Sidebar({
- collection: data.designDocs
+ collection: data.designDocs,
+ ddocInfo: ddocInfo
}),
"#tabs": new Documents.Views.Tabs({
diff --git a/src/fauxton/app/modules/documents/views.js b/src/fauxton/app/modules/documents/views.js
index 7bae3e9ab..6f370cc73 100644
--- a/src/fauxton/app/modules/documents/views.js
+++ b/src/fauxton/app/modules/documents/views.js
@@ -240,18 +240,28 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
Views.IndexItem = FauxtonAPI.View.extend({
template: "templates/documents/index_menu_item",
tagName: "li",
+
initialize: function(options){
this.index = options.index;
this.ddoc = options.ddoc;
this.database = options.database;
+ this.selected = !! options.selected;
},
serialize: function() {
return {
index: this.index,
ddoc: this.ddoc,
- database: this.database
+ database: this.database,
+ selected: this.selected
};
+ },
+
+ afterRender: function() {
+ if (this.selected) {
+ $("#sidenav ul.nav-list li").removeClass("active");
+ this.$el.addClass("active");
+ }
}
});
@@ -320,7 +330,8 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
database: this.collection,
viewList: this.viewList,
hasReduce: false,
- params: this.params
+ params: this.params,
+ ddocs: this.designDocs
};
if (this.ddoc) {
data.ddoc = this.ddoc;
@@ -363,14 +374,14 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
return FauxtonAPI.addNotification({
msg: "JSON Parse Error on field: "+param.name,
type: "error",
- selector: ".view.show .errors-container"
+ selector: ".view.show .all-docs-list.errors-container"
});
});
FauxtonAPI.addNotification({
msg: "Make sure that strings are properly quoted and any other values are valid JSON structures",
type: "warning",
- selector: ".view.show .errors-container"
+ selector: ".view.show .all-docs-list.errors-container"
});
return false;
@@ -401,7 +412,7 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
var notification = FauxtonAPI.addNotification({
msg: "include_docs has been disabled as you cannot include docs on a reduced view",
type: "warn",
- selector: ".view.show .errors-container"
+ selector: ".view.show .all-docs-list.errors-container"
});
}
$form.find("input[name=include_docs]").prop("disabled", true);
@@ -451,6 +462,14 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
},
beforeRender: function() {
+ this.setDdocInfo();
+ if (this.viewList) {
+ this.viewEditorView = this.insertView("#edit-index-container", new Views.ViewEditor({
+ model: this.ddoc,
+ ddocs: this.designDocs,
+ viewCollection: this.collection
+ }));
+ }
this.collection.each(function(doc) {
this.rows[doc.id] = this.insertView("table.all-docs tbody", new this.nestedView({
model: doc
@@ -470,6 +489,9 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
$form.find("select[name='"+key+"']").val(val);
break;
case "include_docs":
+ case "stale":
+ case "descending":
+ case "inclusive_end":
$form.find("input[name='"+key+"']").prop('checked', true);
break;
case "reduce":
@@ -515,6 +537,7 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
var json, notification;
if (this.hasValidCode()) {
json = JSON.parse(this.editor.getValue());
+ this.model.clear({silent:true});
this.model.set(json);
notification = FauxtonAPI.addNotification({msg: "Saving document."});
this.model.save().error(function(xhr) {
@@ -619,9 +642,11 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
Views.ViewEditor = FauxtonAPI.View.extend({
template: "templates/documents/view_editor",
+ builtinReduces: ['_sum', '_count', '_stats'],
events: {
"click button.save": "saveView",
+ "click button.preview": "previewView",
"change select#reduce-function-selector": "updateReduce"
},
@@ -636,6 +661,9 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
initialize: function(options) {
this.ddocs = options.ddocs;
+ this.viewCollection = options.viewCollection;
+ this.reduceFunStr = this.model.viewHasReduce(this.viewCollection.view);
+ this.newView = false;
},
updateValues: function() {
@@ -661,7 +689,22 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
},
establish: function() {
- return [this.ddocs.fetch(), this.model.fetch()];
+ //return [this.ddocs.fetch(), this.model.fetch()];
+ return [];
+ },
+
+ previewView: function(event) {
+ FauxtonAPI.addNotification({
+ msg: "<strong>Warning!</strong> Preview executes the Map/Reduce functions in your browser, and may behave differently from CouchDB.",
+ type: "warning",
+ selector: "#define-view .errors-container",
+ fade: false
+ });
+ FauxtonAPI.addNotification({
+ msg: "Preview Functionality Coming Soon",
+ type: "warning",
+ selector: "#define-view .errors-container"
+ });
},
saveView: function(event) {
@@ -669,10 +712,17 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
if (this.hasValidCode()) {
var mapVal = this.mapEditor.getValue();
var reduceVal = this.reduceEditor.getValue();
+ /*
notification = FauxtonAPI.addNotification({
msg: "Saving document.",
selector: "#define-view .errors-container"
});
+ */
+ FauxtonAPI.addNotification({
+ msg: "Save Functionality Coming Soon",
+ type: "warning",
+ selector: "#define-view .errors-container"
+ });
/*
this.model.save().error(function(xhr) {
var responseText = JSON.parse(xhr.responseText).reason;
@@ -745,18 +795,28 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
serialize: function() {
return {
- database: this.model,
- ddocs: this.ddocs
+ //database: this.model,
+ ddocs: this.ddocs,
+ ddoc: this.model,
+ viewCollection: this.viewCollection,
+ reduceFunStr: this.reduceFunStr,
+ isCustomReduce: this.hasCustomReduce(),
+ newView: this.newView
};
},
+ hasCustomReduce: function() {
+ return this.reduceFunStr && ! _.contains(this.builtinReduces, this.reduceFunStr);
+ },
+
afterRender: function() {
- this.model.on("sync", this.updateValues, this);
var that = this;
var mapFun = $("#map-function");
- mapFun.val(this.langTemplates[this.defaultLang].map);
var reduceFun = $("#reduce-function");
- reduceFun.val(this.langTemplates[this.defaultLang].reduce);
+ if (this.newView) {
+ mapFun.val(this.langTemplates[this.defaultLang].map);
+ reduceFun.val(this.langTemplates[this.defaultLang].reduce);
+ }
this.mapEditor = Codemirror.fromTextArea(mapFun.get()[0], {
mode: "javascript",
lineNumbers: true,
@@ -766,7 +826,7 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
that.runJSHint("mapEditor");
},
extraKeys: {
- "Ctrl-S": function(instance) { that.saveDoc(); },
+ "Ctrl-S": function(instance) { that.saveView(); },
"Ctrl-/": "undo"
}
});
@@ -779,24 +839,30 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
that.runJSHint("reduceEditor");
},
extraKeys: {
- "Ctrl-S": function(instance) { that.saveDoc(); },
+ "Ctrl-S": function(instance) { that.saveView(); },
"Ctrl-/": "undo"
}
});
// HACK: this should be in the html
// but CodeMirror's head explodes and it won't set the hight properly.
// So render it first, set the editor, then hide.
- $(".control-group.reduce-function").hide();
+ if ( ! this.hasCustomReduce()) {
+ $(".control-group.reduce-function").hide();
+ }
}
});
Views.Sidebar = FauxtonAPI.View.extend({
template: "templates/documents/sidebar",
events: {
- "click a.new#index": "newIndex",
- // "click .nav-list.views a.toggle-view": "toggleView",
- "click .nav-list a.toggle-view#all-docs": "toggleView",
- "click .nav-list a.toggle-view#design-docs": "toggleView"
+ "click a.new#index": "newIndex"
+ },
+
+ initialize: function(options) {
+ if (options.ddocInfo) {
+ this.ddocID = options.ddocInfo.id;
+ this.currView = options.ddocInfo.currView;
+ }
},
establish: function() {
@@ -836,10 +902,12 @@ function(app, FauxtonAPI, Codemirror, JSHint) {
buildIndexList: function(collection, selector, design){
_.each(_.keys(collection), function(key){
+ var selected = this.ddocID == "_design/"+design;
this.insertView("ul.nav." + selector, new Views.IndexItem({
ddoc: design,
index: key,
- database: this.collection.database.id
+ database: this.collection.database.id,
+ selected: selected && key == this.currView
}));
}, this);
},
diff --git a/src/fauxton/app/modules/pouchdb/base.js b/src/fauxton/app/modules/pouchdb/base.js
new file mode 100644
index 000000000..2b7cfc927
--- /dev/null
+++ b/src/fauxton/app/modules/pouchdb/base.js
@@ -0,0 +1,57 @@
+// 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.
+
+
+/*
+ * NOTE:
+ * This temporarily uses the PouchDB map reduce implementation
+ * These files are modified locally until we make a more general version and
+ * push it back upstream.
+ */
+
+define([
+ "app",
+
+ "api",
+
+ // Modules
+ "modules/pouchdb/pouchdb.mapreduce.js"
+],
+
+function(app, FauxtonAPI, MapReduce) {
+ var Pouch = {};
+ Pouch.MapReduce = MapReduce;
+
+ Pouch.runViewQuery = function(fun, docs) {
+ docs = [
+ {_id: 'test_doc_1', foo: 'bar-1'},
+ {_id: 'test_doc_2', foo: 'bar-2'},
+ {_id: 'test_doc_3', foo: 'bar-3'},
+ {_id: 'test_doc_4', foo: 'bar-4'},
+ {_id: 'test_doc_5', foo: 'bar-5'},
+ {_id: 'test_doc_6', foo: 'bar-6'},
+ {_id: 'test_doc_7', foo: 'bar-7'},
+ {_id: 'test_doc_8', foo: 'bar-8'},
+ {_id: 'test_doc_9', foo: 'bar-9'},
+ {_id: 'test_doc_10', foo: 'bar-10'}
+ ];
+
+ var deferred = FauxtonAPI.Deferred();
+ var complete = function(resp) {
+ console.log("COMPLETE TRIGGERED", arguments);
+ };
+
+ return Pouch.MapReduce.query(fun, {docs: docs, complete:complete});
+ };
+
+ return Pouch;
+});
diff --git a/src/fauxton/app/modules/pouchdb/pouch.collate.js b/src/fauxton/app/modules/pouchdb/pouch.collate.js
new file mode 100644
index 000000000..7cc5f9cfe
--- /dev/null
+++ b/src/fauxton/app/modules/pouchdb/pouch.collate.js
@@ -0,0 +1,115 @@
+/*
+ * NOTE:
+ * This temporarily uses the PouchDB map reduce implementation
+ * These files are modified locally until we make a more general version and
+ * push it back upstream.
+ * Original file:
+ * https://github.com/daleharvey/pouchdb/blob/master/src/pouch.collate.js
+ */
+
+/*
+(function() {
+ // a few hacks to get things in the right place for node.js
+ if (typeof module !== 'undefined' && module.exports) {
+ module.exports = Pouch;
+ }
+*/
+
+define([
+ "app",
+
+ "api",
+
+ // Modules
+ "modules/pouchdb/pouch.collate.js"
+],
+
+function(app, FauxtonAPI, Collate) {
+ var Pouch = {};
+
+ Pouch.collate = function(a, b) {
+ var ai = collationIndex(a);
+ var bi = collationIndex(b);
+ if ((ai - bi) !== 0) {
+ return ai - bi;
+ }
+ if (a === null) {
+ return 0;
+ }
+ if (typeof a === 'number') {
+ return a - b;
+ }
+ if (typeof a === 'boolean') {
+ return a < b ? -1 : 1;
+ }
+ if (typeof a === 'string') {
+ return stringCollate(a, b);
+ }
+ if (Array.isArray(a)) {
+ return arrayCollate(a, b);
+ }
+ if (typeof a === 'object') {
+ return objectCollate(a, b);
+ }
+ };
+
+ var stringCollate = function(a, b) {
+ // See: https://github.com/daleharvey/pouchdb/issues/40
+ // This is incompatible with the CouchDB implementation, but its the
+ // best we can do for now
+ return (a === b) ? 0 : ((a > b) ? 1 : -1);
+ };
+
+ var objectCollate = function(a, b) {
+ var ak = Object.keys(a), bk = Object.keys(b);
+ var len = Math.min(ak.length, bk.length);
+ for (var i = 0; i < len; i++) {
+ // First sort the keys
+ var sort = Pouch.collate(ak[i], bk[i]);
+ if (sort !== 0) {
+ return sort;
+ }
+ // if the keys are equal sort the values
+ sort = Pouch.collate(a[ak[i]], b[bk[i]]);
+ if (sort !== 0) {
+ return sort;
+ }
+
+ }
+ return (ak.length === bk.length) ? 0 :
+ (ak.length > bk.length) ? 1 : -1;
+ };
+
+ var arrayCollate = function(a, b) {
+ var len = Math.min(a.length, b.length);
+ for (var i = 0; i < len; i++) {
+ var sort = Pouch.collate(a[i], b[i]);
+ if (sort !== 0) {
+ return sort;
+ }
+ }
+ return (a.length === b.length) ? 0 :
+ (a.length > b.length) ? 1 : -1;
+ };
+
+ // The collation is defined by erlangs ordered terms
+ // the atoms null, true, false come first, then numbers, strings,
+ // arrays, then objects
+ var collationIndex = function(x) {
+ var id = ['boolean', 'number', 'string', 'object'];
+ if (id.indexOf(typeof x) !== -1) {
+ if (x === null) {
+ return 1;
+ }
+ return id.indexOf(typeof x) + 2;
+ }
+ if (Array.isArray(x)) {
+ return 4.5;
+ }
+ };
+
+ return Pouch;
+
+//}).call(this);
+
+});
diff --git a/src/fauxton/app/modules/pouchdb/pouchdb.mapreduce.js b/src/fauxton/app/modules/pouchdb/pouchdb.mapreduce.js
new file mode 100644
index 000000000..b97eb7fc3
--- /dev/null
+++ b/src/fauxton/app/modules/pouchdb/pouchdb.mapreduce.js
@@ -0,0 +1,286 @@
+/*
+ * NOTE:
+ * This temporarily uses the PouchDB map reduce implementation
+ * These files are modified locally until we make a more general version and
+ * push it back upstream.
+ * Original file:
+ * https://github.com/daleharvey/pouchdb/blob/master/src/plugins/pouchdb.mapreduce.js
+ */
+
+/*global Pouch: true */
+
+//"use strict";
+
+// This is the first implementation of a basic plugin, we register the
+// plugin object with pouch and it is mixin'd to each database created
+// (regardless of adapter), adapters can override plugins by providing
+// their own implementation. functions on the plugin object that start
+// with _ are reserved function that are called by pouchdb for special
+// notifications.
+
+// If we wanted to store incremental views we can do it here by listening
+// to the changes feed (keeping track of our last update_seq between page loads)
+// and storing the result of the map function (possibly using the upcoming
+// extracted adapter functions)
+
+define([
+ "app",
+
+ "api",
+
+ // Modules
+ "modules/pouchdb/pouch.collate.js"
+],
+
+function(app, FauxtonAPI, Collate) {
+ var Pouch = {};
+ Pouch.collate = Collate.collate;
+
+ //var MapReduce = function(db) {
+ var MapReduce = function() {
+
+ function viewQuery(fun, options) {
+ console.log("IN VIEW QUERY");
+ if (!options.complete) {
+ return;
+ }
+
+ function sum(values) {
+ return values.reduce(function(a, b) { return a + b; }, 0);
+ }
+
+ var results = [];
+ var current = null;
+ var num_started= 0;
+ var completed= false;
+
+ var emit = function(key, val) {
+ console.log("IN EMIT: ", key, val, current);
+ var viewRow = {
+ id: current.doc._id,
+ key: key,
+ value: val
+ };
+ console.log("VIEW ROW: ", viewRow);
+
+ if (options.startkey && Pouch.collate(key, options.startkey) < 0) return;
+ if (options.endkey && Pouch.collate(key, options.endkey) > 0) return;
+ if (options.key && Pouch.collate(key, options.key) !== 0) return;
+ num_started++;
+ if (options.include_docs) {
+ // TODO:: FIX
+ throw({error: "Include Docs not supported"});
+ /*
+
+ //in this special case, join on _id (issue #106)
+ if (val && typeof val === 'object' && val._id){
+ db.get(val._id,
+ function(_, joined_doc){
+ if (joined_doc) {
+ viewRow.doc = joined_doc;
+ }
+ results.push(viewRow);
+ checkComplete();
+ });
+ return;
+ } else {
+ viewRow.doc = current.doc;
+ }
+ */
+ }
+ console.log("EMITTING: ", viewRow);
+ results.push(viewRow);
+ };
+
+ // ugly way to make sure references to 'emit' in map/reduce bind to the
+ // above emit
+ eval('fun.map = ' + fun.map.toString() + ';');
+ if (fun.reduce) {
+ eval('fun.reduce = ' + fun.reduce.toString() + ';');
+ }
+
+ // exclude _conflicts key by default
+ // or to use options.conflicts if it's set when called by db.query
+ var conflicts = ('conflicts' in options ? options.conflicts : false);
+
+ //only proceed once all documents are mapped and joined
+ var checkComplete= function(){
+ if (completed && results.length == num_started){
+ results.sort(function(a, b) {
+ return Pouch.collate(a.key, b.key);
+ });
+ if (options.descending) {
+ results.reverse();
+ }
+ if (options.reduce === false) {
+ return options.complete(null, {rows: results});
+ }
+
+ var groups = [];
+ results.forEach(function(e) {
+ var last = groups[groups.length-1] || null;
+ if (last && Pouch.collate(last.key[0][0], e.key) === 0) {
+ last.key.push([e.key, e.id]);
+ last.value.push(e.value);
+ return;
+ }
+ groups.push({key: [[e.key, e.id]], value: [e.value]});
+ });
+ groups.forEach(function(e) {
+ e.value = fun.reduce(e.key, e.value) || null;
+ e.key = e.key[0][0];
+ });
+ options.complete(null, {rows: groups});
+ }
+ };
+
+ if (options.docs) {
+ console.log("RUNNING MR ON DOCS: ", options.docs);
+ _.each(options.docs, function(doc) {
+ current = {doc: doc};
+ fun.map.call(this, doc);
+ }, this);
+ return options.complete(null, {rows: results});
+ } else {
+ console.log("COULD NOT FIND DOCS");
+ return false;
+ }
+
+ /*
+ db.changes({
+ conflicts: conflicts,
+ include_docs: true,
+ onChange: function(doc) {
+ if (!('deleted' in doc)) {
+ current = {doc: doc.doc};
+ fun.map.call(this, doc.doc);
+ }
+ },
+ complete: function() {
+ completed= true;
+ checkComplete();
+ }
+ });
+ */
+ }
+
+ /*
+ function httpQuery(fun, opts, callback) {
+
+ // List of parameters to add to the PUT request
+ var params = [];
+ var body = undefined;
+ var method = 'GET';
+
+ // If opts.reduce exists and is defined, then add it to the list
+ // of parameters.
+ // If reduce=false then the results are that of only the map function
+ // not the final result of map and reduce.
+ if (typeof opts.reduce !== 'undefined') {
+ params.push('reduce=' + opts.reduce);
+ }
+ if (typeof opts.include_docs !== 'undefined') {
+ params.push('include_docs=' + opts.include_docs);
+ }
+ if (typeof opts.limit !== 'undefined') {
+ params.push('limit=' + opts.limit);
+ }
+ if (typeof opts.descending !== 'undefined') {
+ params.push('descending=' + opts.descending);
+ }
+ if (typeof opts.startkey !== 'undefined') {
+ params.push('startkey=' + encodeURIComponent(JSON.stringify(opts.startkey)));
+ }
+ if (typeof opts.endkey !== 'undefined') {
+ params.push('endkey=' + encodeURIComponent(JSON.stringify(opts.endkey)));
+ }
+ if (typeof opts.key !== 'undefined') {
+ params.push('key=' + encodeURIComponent(JSON.stringify(opts.key)));
+ }
+
+ // If keys are supplied, issue a POST request to circumvent GET query string limits
+ // see http://wiki.apache.org/couchdb/HTTP_view_API#Querying_Options
+ if (typeof opts.keys !== 'undefined') {
+ method = 'POST';
+ body = JSON.stringify({keys:opts.keys});
+ }
+
+ // Format the list of parameters into a valid URI query string
+ params = params.join('&');
+ params = params === '' ? '' : '?' + params;
+
+ // We are referencing a query defined in the design doc
+ if (typeof fun === 'string') {
+ var parts = fun.split('/');
+ db.request({
+ method: method,
+ url: '_design/' + parts[0] + '/_view/' + parts[1] + params,
+ body: body
+ }, callback);
+ return;
+ }
+
+ // We are using a temporary view, terrible for performance but good for testing
+ var queryObject = JSON.parse(JSON.stringify(fun, function(key, val) {
+ if (typeof val === 'function') {
+ return val + ''; // implicitly `toString` it
+ }
+ return val;
+ }));
+
+ db.request({
+ method:'POST',
+ url: '_temp_view' + params,
+ body: queryObject
+ }, callback);
+ }
+ */
+
+ function query(fun, opts, callback) {
+ if (typeof opts === 'function') {
+ callback = opts;
+ opts = {};
+ }
+
+ if (callback) {
+ opts.complete = callback;
+ }
+
+ /*
+ if (db.type() === 'http') {
+ return httpQuery(fun, opts, callback);
+ }
+ */
+
+ if (typeof fun === 'object') {
+ console.log("RUNNING VIEW QUERY", fun, opts, arguments);
+ return viewQuery(fun, opts);
+ }
+
+ throw({error: "Shouldn't have gotten here"});
+
+ /*
+ var parts = fun.split('/');
+ db.get('_design/' + parts[0], function(err, doc) {
+ if (err) {
+ if (callback) callback(err);
+ return;
+ }
+ viewQuery({
+ map: doc.views[parts[1]].map,
+ reduce: doc.views[parts[1]].reduce
+ }, opts);
+ });
+ */
+ }
+
+ return {'query': query};
+ };
+
+ // Deletion is a noop since we dont store the results of the view
+ MapReduce._delete = function() { };
+
+ //Pouch.plugin('mapreduce', MapReduce);
+
+ return MapReduce();
+});
diff --git a/src/fauxton/app/router.js b/src/fauxton/app/router.js
index 94b72f66a..2e994e547 100644
--- a/src/fauxton/app/router.js
+++ b/src/fauxton/app/router.js
@@ -32,6 +32,7 @@ define([
// Routes return the module that they define routes for
"modules/databases/base",
"modules/documents/base",
+ "modules/pouchdb/base",
// this needs to be added as a plugin later
@@ -41,7 +42,7 @@ define([
"load_addons"
],
-function(req, app, Initialize, FauxtonAPI, Fauxton, Layout, Databases, Documents, LoadAddons) {
+function(req, app, Initialize, FauxtonAPI, Fauxton, Layout, Databases, Documents, Pouch, LoadAddons) {
var defaultLayout = 'with_sidebar';
// TODO: auto generate this list if possible
@@ -70,7 +71,13 @@ function(req, app, Initialize, FauxtonAPI, Fauxton, Layout, Databases, Documents
_.each(settings.views, function(view, selector) {
masterLayout.setView(selector, view);
- $.when.apply(null, view.establish()).done(function(resp) {
+ $.when.apply(null, view.establish()).then(function(resp) {
+ masterLayout.renderView(selector);
+ }, function(resp) {
+ view.establishError = {
+ error: true,
+ reason: resp
+ };
masterLayout.renderView(selector);
});
diff --git a/src/fauxton/app/templates/databases/sidebar.html b/src/fauxton/app/templates/databases/sidebar.html
index af4c438cc..1b78aba24 100644
--- a/src/fauxton/app/templates/databases/sidebar.html
+++ b/src/fauxton/app/templates/databases/sidebar.html
@@ -13,16 +13,15 @@ the License.
-->
<div class="row-fluid">
-<a class="btn new span4" id="new"><i class="icon-plus"></i> New database</a>
+<a class="btn new" id="new"><i class="icon-plus"></i> New database</a>
</div>
<hr>
<ul class="nav nav-list">
<!-- <li class="nav-header">Database types</li> -->
<li class="active"><a class="toggle-view" id="owned">Your databases</a></li>
- <li class=""><a class="toggle-view" id="shared">Shared databases</a></li>
</ul>
<hr>
<div class="well">
<p>Here be news.</p>
</div>
-<img src="img/couchdblogo.png"/>
+<a href="http://couchdb.org" target="_blank"><img src="img/couchdblogo.png"/></a>
diff --git a/src/fauxton/app/templates/documents/all_docs_list.html b/src/fauxton/app/templates/documents/all_docs_list.html
index 715c9795e..2f63af038 100644
--- a/src/fauxton/app/templates/documents/all_docs_list.html
+++ b/src/fauxton/app/templates/documents/all_docs_list.html
@@ -13,88 +13,129 @@ the License.
-->
<div class="view show">
- <div class="row">
- <div class="btn-toolbar span6">
- <button type="button" class="btn all" data-toggle="button">✓ All</button>
- <button class="btn btn-small disabled bulk-delete"><i class="icon-trash"></i></button>
- </div>
- <div class="btn-toolbar pull-right">
- <a href="#new-view-index" class="btn btn-small toggle-edit disabled"><i class="icon-wrench"></i> Edit index</a>
- <a href="#params" class="btn btn-small toggle-params"><i class="icon-plus"></i> API preview</a>
+ <% if (!viewList) { %>
+ <div class="row">
+ <div class="btn-toolbar span6">
+ <button type="button" class="btn all" data-toggle="button">✓ All</button>
+ <button class="btn btn-small disabled bulk-delete"><i class="icon-trash"></i></button>
+ </div>
+ <!-- TODO::REENABLE
+ <div class="btn-toolbar pull-right">
+ <a href="#new-view-index" class="btn btn-small toggle-edit disabled"><i class="icon-wrench"></i> Edit index</a>
+ <a href="#params" class="btn btn-small toggle-params"><i class="icon-plus"></i> API preview</a>
+ </div>
+ -->
</div>
- </div>
+ <% } %>
<div class="row">
- <div class="errors-container"></div>
- <div class="accordion" id="advanced-options-accordion">
- <div class="accordion-group">
- <div class="accordion-heading">
- <a class="accordion-toggle" data-bypass="true" data-toggle="collapse" data-parent="#advanced-options-accordion" href="#collapse-advanced-options">
- Advanced Options
- </a>
- </div>
- <div id="collapse-advanced-options" class="accordion-body collapse in">
- <div class="accordion-inner">
- <form class="view-query-update">
- <div class="controls controls-row">
- <label class="span3 inline">
- Limit:
- <select name="limit" class="input-small">
- <option>5</option>
- <option selected="selected">10</option>
- <option>25</option>
- <option>50</option>
- <option>100</option>
- </select>
- </label>
- <label class="span3 checkbox inline">
- <input name="include_docs" type="checkbox" value="true"> Include Docs
- </label>
- <% if (hasReduce) { %>
+ <div class="all-docs-list errors-container"></div>
+ <div id="edit-index-container"></div>
+ <% if (viewList) { %>
+ <div class="accordion" id="advanced-options-accordion">
+ <div class="accordion-group">
+ <div class="accordion-heading">
+ <a class="accordion-toggle" data-bypass="true" data-toggle="collapse" data-parent="#advanced-options-accordion" href="#collapse-advanced-options">
+ <i class="icon-plus"></i> Advanced Options
+ </a>
+ </div>
+ <div id="collapse-advanced-options" class="accordion-body collapse">
+ <div class="accordion-inner">
+ <form class="view-query-update">
+ <div class="controls controls-row">
+ <label class="span3 inline">
+ Limit:
+ <select name="limit" class="input-small">
+ <option>5</option>
+ <option selected="selected">10</option>
+ <option>25</option>
+ <option>50</option>
+ <option>100</option>
+ </select>
+ </label>
+ <label class="span3 checkbox inline">
+ <input name="include_docs" type="checkbox" value="true"> Include Docs
+ </label>
+ <% if (hasReduce) { %>
+ <label class="span2 checkbox inline">
+ <input name="reduce" type="checkbox" value="true"> Reduce
+ </label>
+ <label class="span4 inline">
+ Group Level:
+ <select disabled name="group_level" class="input-small">
+ <option value="0">None</option>
+ <option value="1">1</option>
+ <option value="2">2</option>
+ <option value="3">3</option>
+ <option value="4">4</option>
+ <option value="5">5</option>
+ <option value="6">6</option>
+ <option value="7">7</option>
+ <option value="8">8</option>
+ <option value="9">9</option>
+ <option value="999" selected="selected">exact</option>
+ </select>
+ </label>
+ <% } %>
+ </div>
+
+ <div class="controls controls-row">
+ <input name="key" class="span4" type="text" placeholder="Key">
+ <input name="keys" class="span8" type="text" placeholder="Keys">
+ </div>
+ <div class="controls controls-row">
+ <input name="startkey" class="span6" type="text" placeholder="Start Key">
+ <input name="endkey" class="span6" type="text" placeholder="End Key">
+ </div>
+ <div class="controls controls-row">
<label class="span2 checkbox inline">
- <input name="reduce" type="checkbox" value="true"> Reduce
+ <input name="stale" type="checkbox" value="ok"> Stale
</label>
- <label class="span4 inline">
- Group Level:
- <select disabled name="group_level" class="input-small">
- <option value="0">None</option>
- <option value="1">1</option>
- <option value="2">2</option>
- <option value="3">3</option>
- <option value="4">4</option>
- <option value="5">5</option>
- <option value="6">6</option>
- <option value="7">7</option>
- <option value="8">8</option>
- <option value="9">9</option>
- <option value="999" selected="selected">exact</option>
- </select>
+ <label class="span2 checkbox inline">
+ <input name="descending" type="checkbox" value="true"> Descending
+ </label>
+ <label class="span4 checkbox inline">
+ <input name="inclusive_end" type="checkbox" value="false"> Disable Inclusive End
+ </label>
+ <label class="span4 checkbox inline">
+ <input name="update_seq" type="checkbox" value="true"> Include Update Sequence
</label>
- <% } %>
- </div>
+ </div>
+ <div class="controls controls-row">
+ <button type="submit" class="btn btn-primary">Query</button>
+ </div>
+ </form>
- <div class="controls controls-row">
- <input name="key" class="span4" type="text" placeholder="Key">
- <input name="keys" class="span8" type="text" placeholder="Keys">
- </div>
- <div class="controls controls-row">
- <input name="startkey" class="span6" type="text" placeholder="Start Key">
- <input name="endkey" class="span6" type="text" placeholder="End Key">
- </div>
- <div class="controls controls-row">
- <button type="submit" class="btn btn-primary">Query</button>
- </div>
- </form>
-
+ </div>
</div>
- </div>
+ </div>
</div>
- </div>
+ <% } %>
</div>
+ <p>
+ Showing 1-<%= database.models.length %> of <%= database.totalRows() %> rows
+ <% if (database.updateSeq()) { %>
+ -- Update Sequence: <%= database.updateSeq() %>
+ <% } %>
+ </p>
<table class="all-docs table table-striped table-condensed">
<tbody></tbody>
</table>
+ <!--
+ <div class="pagination pagination-centered">
+ <ul>
+ <li class="disabled"><a href="#">&laquo;</a></li>
+ <li class="active"><a href="#">1</a></li>
+ <li><a href="#">2</a></li>
+ <li><a href="#">3</a></li>
+ <li><a href="#">4</a></li>
+ <li><a href="#">5</a></li>
+ <li><a href="#">&raquo;</a></li>
+ </ul>
+ </div>
+ -->
+
</div>
diff --git a/src/fauxton/app/templates/documents/sidebar.html b/src/fauxton/app/templates/documents/sidebar.html
index 4dbe062e3..7a0ecdf95 100644
--- a/src/fauxton/app/templates/documents/sidebar.html
+++ b/src/fauxton/app/templates/documents/sidebar.html
@@ -19,8 +19,8 @@ the License.
</div>
<hr>
<ul class="nav nav-list">
- <li class="active"><a id="all-docs" href="/_all_docs" class="toggle-view"><i class="icon-list"></i> All documents</a></li>
- <li><a id="design-docs" href='/_all_docs?start_key="_design"&end_key="_e"' class="toggle-view"><i class="icon-list"></i> All design docs</a></li>
+ <li class="active"><a id="all-docs" href="#<%= database.url('index') %>?limit=100" class="toggle-view"><i class="icon-list"></i> All documents</a></li>
+ <li><a id="design-docs" href='#<%= database.url("index") %>?limit=100&start_key="_design"&end_key="_e"' class="toggle-view"><i class="icon-list"></i> All design docs</a></li>
</ul>
<ul class="nav nav-list views">
<li class="nav-header">Secondary Indexes</li>
diff --git a/src/fauxton/app/templates/documents/tabs.html b/src/fauxton/app/templates/documents/tabs.html
index bf2968e0c..57e6cb180 100644
--- a/src/fauxton/app/templates/documents/tabs.html
+++ b/src/fauxton/app/templates/documents/tabs.html
@@ -14,11 +14,14 @@ the License.
<ul class="nav nav-tabs">
<li class="active"><a href="<%= db_url %>">Docs</a></li>
+ <!-- TODO::REENABLE
<li><a href="#">Permissions</a></li>
<li><a href="#">Stats</a></li>
+ -->
<li id="changes"><a href="<%= changes_url %>">Changes</a></li>
+ <!-- TODO::REENABLE
<div id="search" class="navbar-search span4 nav pull-right input-prepend" style="height:20px;"></div>
- <!-- TODO: put this styling into less -->
+ <!-- TODO: put this styling into less --//>
<ul class="nav pull-right" style="margin:5px 10px 0px 10px;">
<li>
<div class="btn-group">
@@ -32,4 +35,5 @@ the License.
</div>
</li>
</ul>
+ -->
</ul>
diff --git a/src/fauxton/app/templates/documents/view_editor.html b/src/fauxton/app/templates/documents/view_editor.html
index 635d85f6a..4a8668e29 100644
--- a/src/fauxton/app/templates/documents/view_editor.html
+++ b/src/fauxton/app/templates/documents/view_editor.html
@@ -12,68 +12,81 @@ License for the specific language governing permissions and limitations under
the License.
-->
-<div id="define-view" class="ddoc-alert well">
- <div class="errors-container">
- <div class="alert">
- <button type="button" class="close" data-dismiss="alert">&times;</button>
- <strong>Warning!</strong> Preview executes the Map/Reduce functions in your browser, and may behave differently from CouchDB.
+<div class="accordion" id="edit-index-accordion">
+ <div class="accordion-group">
+ <div class="accordion-heading">
+ <a class="accordion-toggle" data-bypass="true" data-toggle="collapse" data-parent="#edit-index-accordion" href="#collapse-edit-index">
+ <i class="icon-wrench"></i> Edit Index
+ </a>
</div>
- </div>
- <form class="form-horizontal">
- <h3>Define your index</h3>
- <div class="control-group">
- <label class="control-label" for="ddoc">Design document <a target="_couch_docs" href="http://docs.couchdb.org/en/latest/ddocs/#design-docs"><i class="icon-question-sign"></i></a></label>
- <div class="controls">
- <select id="ddoc">
- <optgroup label="Select a document">
- <option>New document</option>
- <% ddocs.each(function(ddoc) { %>
- <option><%= ddoc.id %></option>
- <% }); %>
- <option selected="selected">_design/views101</option>
- </optgroup>
- </select>
- </div>
- </div>
- <div class="control-group">
- <label class="control-label" for="index-name">Index name <a target="_couch_docs" href="http://docs.couchdb.org/en/latest/ddocs/#view-functions"><i class="icon-question-sign"></i></a></label>
- <div class="controls">
- <input type="text" id="index-name" value="" placeholder="Index name" />
- </div>
- </div>
- <div class="control-group">
- <label class="control-label" for="map-function">Map function <a target="_couch_docs" href="http://docs.couchdb.org/en/latest/ddocs/#map-functions"><i class="icon-question-sign"></i></a></label>
- <div class="controls">
- <textarea class="js-editor" id="map-function"></textarea>
- </div>
- </div>
- <div class="control-group">
- <label class="control-label" for="reduce-function-selector">Reduce function <a target="_couch_docs" href="http://docs.couchdb.org/en/latest/ddocs/#reduce-and-rereduce-functions"><i class="icon-question-sign"></i></a></label>
- <div class="controls">
- <select id="reduce-function-selector">
- <option value="" selected="selected">None</option>
- <option value="_sum">_sum</option>
- <option value="_count">_count</option>
- <option value="_stats">_stats</option>
- <option value="CUSTOM">Custom reduce</option>
- </select>
- <span class="help-block">Reduce functions are optional.</span>
+ <div id="collapse-edit-index" class="accordion-body collapse">
+ <div class="accordion-inner">
+ <div id="define-view" class="ddoc-alert well">
+ <div class="errors-container"></div>
+ <form class="form-horizontal">
+ <h3>Define your index</h3>
+ <div class="control-group">
+ <label class="control-label" for="ddoc">Design document <a target="_couch_docs" href="http://docs.couchdb.org/en/latest/ddocs/#design-docs"><i class="icon-question-sign"></i></a></label>
+ <div class="controls">
+ <select id="ddoc">
+ <optgroup label="Select a document">
+ <option>New document</option>
+ <% ddocs.each(function(ddoc) { %>
+ <% if (ddoc.id == "_design/"+viewCollection.design) { %>
+ <option selected="selected"><%= ddoc.id %></option>
+ <% } else { %>
+ <option><%= ddoc.id %></option>
+ <% } %>
+ <% }); %>
+ <option selected="selected">_design/views101</option>
+ </optgroup>
+ </select>
+ </div>
+ </div>
+ <div class="control-group">
+ <label class="control-label" for="index-name">Index name <a target="_couch_docs" href="http://docs.couchdb.org/en/latest/ddocs/#view-functions"><i class="icon-question-sign"></i></a></label>
+ <div class="controls">
+ <input type="text" id="index-name" value="<%= viewCollection.view %>" placeholder="Index name" />
+ </div>
+ </div>
+ <div class="control-group">
+ <label class="control-label" for="map-function">Map function <a target="_couch_docs" href="http://docs.couchdb.org/en/latest/ddocs/#map-functions"><i class="icon-question-sign"></i></a></label>
+ <div class="controls">
+ <textarea class="js-editor" id="map-function"><%= ddoc.get('doc').views[viewCollection.view].map %></textarea>
+ </div>
+ </div>
+ <div class="control-group">
+ <label class="control-label" for="reduce-function-selector">Reduce function <a target="_couch_docs" href="http://docs.couchdb.org/en/latest/ddocs/#reduce-and-rereduce-functions"><i class="icon-question-sign"></i></a></label>
+ <div class="controls">
+ <select id="reduce-function-selector">
+ <option value="" <%= !reduceFunStr ? 'selected="selected"' : '' %>>None</option>
+ <% _.each(["_sum", "_count", "_stats"], function(reduce) { %>
+ <option value="<%= reduce %>" <% if (reduce == reduceFunStr) { %>selected<% } %>><%= reduce %></option>
+ <% }) %>
+ <option value="CUSTOM" <% if (isCustomReduce) { %>selected<% } %>>Custom reduce</option>
+ </select>
+ <span class="help-block">Reduce functions are optional.</span>
+ </div>
+ </div>
+ <div class="control-group reduce-function">
+ <label class="control-label" for="reduce-function">Custom Reduce</label>
+ <div class="controls">
+ <textarea class="js-editor" id="reduce-function"><%= ddoc.get('doc').views[viewCollection.view].reduce %></textarea>
+ </div>
+ </div>
+ <div class="control-group">
+ <hr />
+ <div class="controls">
+ <button class="btn btn-small btn-inverse cancel">Cancel</button>
+ <button class="btn btn-small btn-info preview">Preview</button>
+ <button class="btn btn-primary save">Save</button>
+ </div>
+ </div>
+ <div class="clearfix"></div>
+ </form>
+ </div>
</div>
</div>
- <div class="control-group reduce-function">
- <label class="control-label" for="reduce-function">Custom Reduce</label>
- <div class="controls">
- <textarea class="js-editor" id="reduce-function"></textarea>
- </div>
- </div>
- <div class="control-group">
- <hr />
- <div class="controls">
- <button class="btn btn-small btn-inverse cancel">Cancel</button>
- <button class="btn btn-small btn-info preview">Preview</button>
- <button class="btn btn-primary save">Save</button>
- </div>
- </div>
- <div class="clearfix"></div>
- </form>
+
+ </div>
</div>
diff --git a/src/fauxton/app/templates/fauxton/api_bar.html b/src/fauxton/app/templates/fauxton/api_bar.html
index 3bf9daf82..0ca6c69ca 100644
--- a/src/fauxton/app/templates/fauxton/api_bar.html
+++ b/src/fauxton/app/templates/fauxton/api_bar.html
@@ -16,7 +16,14 @@ the License.
<div class="navbar-inner">
<div class="container">
<div class="input-prepend input-append">
- <span class="add-on">API reference <i class="icon-question-sign"></i></span><input type="text" class="input-xxlarge" value="<%= endpoint %>"><a href="<%= endpoint %>" target="_blank" class="btn">Show me</a>
+ <span class="add-on">
+ API reference
+ <a href="http://docs.couchdb.org/en/latest/" target="_blank">
+ <i class="icon-question-sign"></i>
+ </a>
+ </span>
+ <input type="text" class="input-xxlarge" value="<%= endpoint %>">
+ <a href="<%= endpoint %>" target="_blank" class="btn">Show me</a>
</div>
</div>
</div>
diff --git a/src/fauxton/assets/index.underscore b/src/fauxton/assets/index.underscore
index 1179ffbc0..8a620062b 100644
--- a/src/fauxton/assets/index.underscore
+++ b/src/fauxton/assets/index.underscore
@@ -30,7 +30,9 @@
padding-bottom: 40px;
}
</style>
+ <% if (base) { %>
<base href="<%= base %>"></base>
+ <% } %>
</head>
<body id="home">
diff --git a/src/fauxton/couchapp.js b/src/fauxton/couchapp.js
index 95d75b3c7..4711ae242 100644
--- a/src/fauxton/couchapp.js
+++ b/src/fauxton/couchapp.js
@@ -1,10 +1,17 @@
-var couchapp = require('couchapp'),
+var couchapp = require('couchapp'),
path = require('path'),
ddoc;
ddoc = {
_id: '_design/fauxton',
- rewrites: {},
+ rewrites: [
+ { "from": "_db" , "to" : "../.." },
+ { "from": "_db/*" , "to" : "../../*" },
+ { "from": "_ddoc" , "to" : "" },
+ { "from": "_ddoc/*", "to" : "*"},
+ {from: '/', to: 'index.html'},
+ {from: '/*', to: '*'}
+ ],
views: {},
shows: {},
lists: {},
diff --git a/src/fauxton/grunt.js b/src/fauxton/grunt.js
index ca10c8ef7..4c40cbe2c 100644
--- a/src/fauxton/grunt.js
+++ b/src/fauxton/grunt.js
@@ -75,6 +75,20 @@ module.exports = function(grunt) {
return theAssets;
}();
+ var templateSettings = function(){
+ var defaultSettings = {
+ "src": "assets/index.underscore",
+ "dest": "dist/debug/index.html",
+ "variables": {
+ "assets_root": "./",
+ "requirejs": "require.js",
+ "base": null
+ }
+ };
+ var settings = grunt.file.readJSON("settings.json");
+ return {template: settings.template || defaultSettings};
+ }();
+
grunt.initConfig({
// The clean task ensures all files are removed from the dist/ directory so
@@ -105,7 +119,8 @@ module.exports = function(grunt) {
// route.
jshint: {
options: {
- scripturl: true
+ scripturl: true,
+ evil: true
}
},
@@ -125,53 +140,7 @@ module.exports = function(grunt) {
// Create static html files from templates, for managing change of script
// or css name.
- template: {
- couchdb:{
- src: 'assets/index.underscore',
- dest: '../../share/www/fauxton/index.html',
- variables: {
- assets_root: '/_utils/fauxton/',
- requirejs: 'require.min.js',
- base: '/_utils/fauxton/'
- }
- },
- couchdebug:{
- src: 'assets/index.underscore',
- dest: '../../share/www/fauxton/index.html',
- variables: {
- assets_root: '/_utils/fauxton/',
- requirejs: 'require.js',
- base: '/_utils/fauxton/'
- }
- },
- release: {
- src: 'assets/index.underscore',
- dest: 'dist/release/index.html',
- variables: {
- assets_root: '/',
- requirejs: 'require.min.js',
- base: '/'
- }
- },
- debug: {
- src: 'assets/index.underscore',
- dest: 'dist/debug/index.html',
- variables: {
- assets_root: '/',
- requirejs: 'require.js',
- base: '/'
- }
- },
- couchapp: {
- src: 'assets/index.underscore',
- dest: 'dist/debug/index.html',
- variables: {
- assets_root: '/fauxton/_design/fauxton/',
- requirejs: 'require.js',
- base: '/fauxton/_design/fauxton/index.html'
- }
- }
- },
+ template: templateSettings,
// The concatenate task is used here to merge the almond require/define
// shim and the templates into the application code. It's named
@@ -373,14 +342,14 @@ module.exports = function(grunt) {
grunt.registerTask("default", "test dependencies build release install");
grunt.registerTask("dev", "debug server:debug");
// make a debug install
- grunt.registerTask("debug", "test dependencies build template:debug copy:debug concat:debug");
+ grunt.registerTask("debug", "test dependencies build template copy:debug concat:debug");
// make an install that is server by mochiweb under _utils
- grunt.registerTask("couchdebug", "debug template:couchdebug copy:couchdebug");
+ grunt.registerTask("couchdebug", "debug template copy:couchdebug");
// make an install that can be deployed as a couchapp
- grunt.registerTask("couchapp_setup", "debug template:couchapp");
- grunt.registerTask("couchdb", "test dependencies build minify template:couchdb copy:couchdb");
+ grunt.registerTask("couchapp_setup", "debug template");
+ grunt.registerTask("couchdb", "test dependencies build minify template copy:couchdb");
// build a release
- grunt.registerTask("release", "test dependencies build minify template:release copy:dist");
+ grunt.registerTask("release", "test dependencies build minify template copy:dist");
// install fauxton as couchapp
grunt.registerTask('couchapp_install', 'rmcouchdb:fauxton mkcouchdb:fauxton couchapp:fauxton');
grunt.registerTask('couchapp_deploy', 'couchapp_setup couchapp_install');
diff --git a/src/fauxton/settings.json.default b/src/fauxton/settings.json.default
index 01c04a4dc..32cd774b5 100644
--- a/src/fauxton/settings.json.default
+++ b/src/fauxton/settings.json.default
@@ -4,5 +4,14 @@
{ "name": "logs" },
{ "name": "stats" },
{ "name": "contribute" }
- ]
+ ],
+ "template": {
+ "src": "assets/index.underscore",
+ "dest": "dist/debug/index.html",
+ "variables": {
+ "assets_root": "./",
+ "requirejs": "require.js",
+ "base": null
+ }
+ }
}