// 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.
/*
* Page class for browse/index.html
*/
function CouchIndexPage() {
page = this;
this.addDatabase = function() {
$.showDialog("_create_database.html", {
submit: function(data, callback) {
if (!data.name || data.name.length == 0) {
callback({name: "Please enter a name."});
return;
}
$.couch.db(data.name).create({
error: function(status, id, reason) { callback({name: reason}) },
success: function(resp) {
location.href = "database.html?" + encodeURIComponent(data.name);
callback();
}
});
}
});
return false;
}
this.updateDatabaseListing = function(offset) {
offset |= 0;
$(document.body).addClass("loading");
var maxPerPage = parseInt($("#perpage").val(), 10);
$.couch.allDbs({
success: function(dbs) {
$("#paging a").unbind();
$("#databases tbody.content").empty();
if (dbs.length == 0) {
$(document.body).removeClass("loading");
}
var dbsOnPage = dbs.slice(offset, offset + maxPerPage);
$.each(dbsOnPage, function(idx, dbName) {
$("#databases tbody.content").append("
")
.find("strong").text(key !== null ? prettyPrintJSON(key, 0, "") : "null").end()
.appendTo(tr);
}
var value = row.value;
$("
").text(
value !== null ? prettyPrintJSON(value, 0, "") : "null"
).appendTo(tr).dblclick(function() {
location.href = this.previousSibling.firstChild.href;
});
tr.appendTo("#documents tbody.content");
}
var firstNum = 1;
var lastNum = totalNum = resp.rows.length;
if (resp.total_rows != null) {
if (decending_reverse) {
lastNum = Math.min(resp.total_rows, resp.total_rows - resp.offset);
firstNum = lastNum - resp.rows.length + 1;
} else {
firstNum = Math.min(resp.total_rows, resp.offset + 1);
lastNum = firstNum + resp.rows.length - 1;
}
totalNum = resp.total_rows;
$("#paging").show();
} else {
$("#paging").hide();
}
$("#documents tbody.footer td span").text(
"Showing " + firstNum + "-" + lastNum + " of " + totalNum +
" row" + (firstNum != lastNum ? "s" : ""));
$("#documents tbody tr:odd").addClass("odd");
$(document.body).removeClass("loading");
}
options.error = function(status, error, reason) {
alert("Error: " + error + "\n\n" + reason);
$(document.body).removeClass("loading");
}
if (!viewName) {
$("#switch select").get(0).selectedIndex = 0;
db.allDocs(options);
} else {
if (viewName == "_slow_view") {
$("#viewcode").show().removeClass("collapsed");
var mapFun = $("#viewcode_map").val();
$.cookies.set(db.name + ".map", mapFun);
var reduceFun = $("#viewcode_reduce").val() || null;
if (reduceFun != null) {
$.cookies.set(db.name + ".reduce", reduceFun);
} else {
$.cookies.remove(db.name + ".reduce");
}
db.query(mapFun, reduceFun, null, options);
} else if (viewName == "_design_docs") {
options.startkey = options.descending ? "_design/ZZZZ" : "_design/";
options.endkey = options.descending ? "_design/" : "_design/ZZZZ";
db.allDocs(options);
} else {
$("#viewcode").show();
var currentMapCode = $("#viewcode_map").val();
var currentReduceCode = $("#viewcode_reduce").val() || null;
if (page.isDirty) {
db.query(currentMapCode, currentReduceCode, null, options);
} else {
db.view(viewName.substr(8), options);
}
}
}
}
window.onbeforeunload = function() {
$("#switch select").val(viewName);
if (page.isDirty) {
return "You've made changes to the view code that have not been " +
"saved yet.";
}
}
}
/*
* Page class for browse/database.html
*/
function CouchDocumentPage() {
var urlParts = location.search.substr(1).split("/");
var dbName = decodeURIComponent(urlParts.shift());
var idParts = urlParts.join("/").split("@", 2);
var docId = decodeURIComponent(idParts[0]);
var docRev = (idParts.length > 1) ? idParts[1] : null;
var db = $.couch.db(dbName);
this.dbName = dbName;
this.db = db;
this.docId = docId;
this.doc = null;
this.isDirty = false;
page = this;
this.addField = function() {
if (!$("#fields tbody.content:visible").length) {
$("#tabs li.tabular a").click(); // switch to tabular view
}
var fieldName = "unnamed";
var fieldIdx = 1;
while (page.doc.hasOwnProperty(fieldName)) {
fieldName = "unnamed " + fieldIdx++;
}
page.doc[fieldName] = null;
var row = _addRowForField(page.doc, fieldName);
page.isDirty = true;
_editKey(page.doc, row.find("th"), fieldName);
}
var _sortFields = function(a, b) {
var a0 = a.charAt(0), b0 = b.charAt(0);
if (a0 == "_" && b0 != "_") {
return -1;
} else if (a0 != "_" && b0 == "_") {
return 1;
} else if (a == "_attachments" || b == "_attachments") {
return a0 == "_attachments" ? 1 : -1;
} else {
return a < b ? -1 : a != b ? 1 : 0;
}
}
this.updateFieldListing = function() {
$(document.body).addClass("loading");
$("#fields tbody.content").empty();
function handleResult(doc, revs) {
page.doc = doc;
var propNames = [];
for (var prop in doc) {
if (!doc.hasOwnProperty(prop)) continue;
propNames.push(prop);
}
// Order properties alphabetically, but put internal fields first
propNames.sort(_sortFields);
for (var pi = 0; pi < propNames.length; pi++) {
_addRowForField(doc, propNames[pi]);
}
if (revs.length > 1) {
var currentIndex = 0;
for (var i = 0; i < revs.length; i++) {
if (revs[i].rev == doc._rev) {
currentIndex = i;
break;
}
}
if (currentIndex < revs.length - 1) {
var prevRev = revs[currentIndex + 1].rev;
$("#paging a.prev").attr("href", "?" + encodeURIComponent(dbName) +
"/" + encodeDocId(docId) + "@" + prevRev);
}
if (currentIndex > 0) {
var nextRev = revs[currentIndex - 1].rev;
$("#paging a.next").attr("href", "?" + encodeURIComponent(dbName) +
"/" + encodeDocId(docId) + "@" + nextRev);
}
$("#fields tbody.footer td span").text("Showing revision " +
(revs.length - currentIndex) + " of " + revs.length);
}
$(document.body).removeClass("loading");
}
db.openDoc(docId, {revs_info: true,
success: function(doc) {
var revs = doc._revs_info;
delete doc._revs_info;
if (docRev != null) {
db.openDoc(docId, {rev: docRev,
error: function(status, error, reason) {
alert("The requested revision was not found. " +
"You will be redirected back to the latest revision.");
location.href = "?" + encodeURIComponent(dbName) +
"/" + encodeDocId(docId);
},
success: function(doc) {
handleResult(doc, revs);
}
});
} else {
handleResult(doc, revs);
}
}
});
}
this.deleteDocument = function() {
$.showDialog("_delete_document.html", {
submit: function(data, callback) {
db.removeDoc(page.doc, {
success: function(resp) {
callback();
location.href = "database.html?" + encodeURIComponent(dbName);
}
});
}
});
}
this.saveDocument = function() {
$(document.body).addClass("loading");
db.saveDoc(page.doc, {
success: function(resp) {
page.isDirty = false;
location.href = "?" + encodeURIComponent(dbName) +
"/" + encodeDocId(docId);
}
});
}
this.uploadAttachment = function() {
if (page.isDirty) {
alert("You need to save or revert any changes you have made to the " +
"document before you can attach a new file.");
return false;
}
$.showDialog("_upload_attachment.html", {
load: function(elem) {
$("input[name='_rev']", elem).val(page.doc._rev);
},
submit: function(data, callback) {
if (!data._attachments || data._attachments.length == 0) {
callback({_attachments: "Please select a file to upload."});
return;
}
var form = $("#upload-form");
form.find("#progress").css("visibility", "visible");
form.ajaxSubmit({
url: db.uri + encodeDocId(page.docId),
success: function(resp) {
form.find("#progress").css("visibility", "hidden");
page.isDirty = false;
location.href = "?" + encodeURIComponent(dbName) +
"/" + encodeDocId(docId);
}
});
}
});
}
window.onbeforeunload = function() {
if (page.isDirty) {
return "You've made changes to this document that have not been " +
"saved yet.";
}
}
function _addRowForField(doc, fieldName) {
var row = $("
").find("th").append($("")
.text(fieldName)).end().appendTo("#fields tbody.content");
if (fieldName == "_attachments") {
row
.find("td").append(_renderAttachmentList(doc[fieldName]));
} else {
var value = _renderValue(doc[fieldName]);
row
.find("th b").dblclick(function() {
_editKey(doc, this, $(this).text());
}).end()
.find("td").append(value).dblclick(function() {
_editValue(doc, this, $(this).prev("th").text());
}).end();
if (fieldName != "_id" && fieldName != "_rev") {
row.find("th, td").attr("title", "Double click to edit");
_initKey(doc, row, fieldName);
_initValue(value);
}
}
$("#fields tbody tr").removeClass("odd").filter(":odd").addClass("odd");
return row;
}
function _editKey(doc, cell, fieldName) {
if (fieldName == "_id" || fieldName == "_rev") return;
var th = $(cell);
th.empty();
var input = $("");
input.dblclick(function() { return false; }).keydown(function(evt) {
switch (evt.keyCode) {
case 13: applyChange(); break;
case 27: cancelChange(); break;
}
});
var tools = $("");
function applyChange() {
input.nextAll().remove();
var newName = input.val();
if (!newName.length || newName == fieldName) {
cancelChange();
return;
}
doc[newName] = doc[fieldName];
delete doc[fieldName];
th.children().remove();
th.append($("").text(newName));
_initKey(doc, th.parent("tr"), fieldName);
page.isDirty = true;
}
function cancelChange() {
th.children().remove();
th.append($("").text(fieldName));
_initKey(doc, th.parent("tr"), fieldName);
}
$("").click(function() {
applyChange();
}).appendTo(tools);
$("").click(function() {
cancelChange();
}).appendTo(tools);
tools.appendTo(th);
input.val(fieldName).appendTo(th);
input.each(function() { this.focus(); this.select(); });
}
function _editValue(doc, cell, fieldName) {
if (!fieldName || fieldName == "_id" || fieldName == "_rev") return;
var td = $(cell);
var value = doc[fieldName];
var needsTextarea = $("dl", td).length > 0 || $("code", td).text().length > 60;
td.empty();
if (needsTextarea) {
var input = $("");
} else {
var input = $("");
}
input.dblclick(function() { return false; }).keydown(function(evt) {
switch (evt.keyCode) {
case 13: if (!needsTextarea) applyChange(); break;
case 27: cancelChange(); break;
}
});
var tools = $("");
function applyChange() {
input.nextAll().remove();
try {
var newValue = input.val() || "null";
if (newValue == doc[fieldName]) {
cancelChange();
return;
}
doc[fieldName] = JSON.parse(newValue);
td.children().remove();
page.isDirty = true;
var value = _renderValue(doc[fieldName]);
td.append(value);
_initValue(value);
} catch (err) {
input.addClass("invalid");
var msg = err.message;
if (msg == "parseJSON") {
msg = "Please enter a valid JSON value (for example, \"string\").";
}
$("").text(msg).insertAfter(input);
}
}
function cancelChange() {
td.children().remove();
var value = _renderValue(doc[fieldName]);
td.append(value);
_initValue(value);
}
$("").click(function() {
applyChange();
}).appendTo(tools);
$("").click(function() {
cancelChange();
}).appendTo(tools);
tools.appendTo(td);
input.val(prettyPrintJSON(value)).appendTo(td);
input.each(function() { this.focus(); this.select(); });
if (needsTextarea) input.makeResizable({vertical: true});
}
function _initKey(doc, row, fieldName) {
if (fieldName != "_id" && fieldName != "_rev") {
$("").click(function() {
delete doc[fieldName];
row.remove();
page.isDirty = true;
$("#fields tbody tr").removeClass("odd").filter(":odd").addClass("odd");
}).prependTo(row.find("th"));
}
}
function _initValue(value) {
value.find("dd:has(dl)").hide().prev("dt").addClass("collapsed");
value.find("dd:not(:has(dl))").addClass("inline").prev().addClass("inline");
value.find("dt.collapsed").click(function() {
$(this).toggleClass("collapsed").next().toggle();
});
}
function _renderValue(value) {
var type = typeof(value);
if (type == "object" && value !== null) {
var list = $("
");
for (var i in value) {
if (!value.hasOwnProperty(i)) continue;
$("").text(i).appendTo(list);
$("").append(_renderValue(value[i])).appendTo(list);
}
return list;
} else {
return $("").addClass(type).text(
value !== null ? JSON.stringify(value) : "null"
);
}
}
function _renderAttachmentList(attachments) {
var ul = $("
").addClass("attachments");
$.each(attachments, function(idx, attachment) {
_renderAttachmentItem(idx, attachment).appendTo(ul);
});
return ul;
}
function _renderAttachmentItem(name, attachment) {
var attachmentHref = db.uri + encodeDocId(docId)
+ "/" + encodeAttachment(name);
var li = $("");
$("").text(name)
.attr("href", attachmentHref)
.wrapInner("").appendTo(li);
$("()").text("" + prettyPrintSize(attachment.length) +
", " + attachment.content_type).addClass("info").appendTo(li);
if (name == "tests.js") {
li.find('span.info').append(', open in test runner');
}
_initAttachmentItem(name, attachment, li);
return li;
}
function _initAttachmentItem(name, attachment, li) {
$("").click(function() {
delete page.doc._attachments[name];
li.remove();
page.isDirty = true;
return false;
}).prependTo($("a", li));
}
}
// Ideally these would be module-private. Maybe there's a helper they can go on.
function encodeDocId(docid) {
var encoded, parts = docid.split('/');
if (parts[0] == '_design') {
parts.shift();
encoded = encodeURIComponent(parts.join('/'));
return '_design/'+encoded;
} else {
return encodeURIComponent(docid);
}
};
function encodeAttachment(name) {
var encoded = [], parts = name.split('/');
for (var i=0; i < parts.length; i++) {
encoded.push(encodeURIComponent(parts[i]));
};
return encoded.join('/');
}