diff options
Diffstat (limited to 'share/www/script/futon.browse.js')
-rw-r--r-- | share/www/script/futon.browse.js | 199 |
1 files changed, 151 insertions, 48 deletions
diff --git a/share/www/script/futon.browse.js b/share/www/script/futon.browse.js index 4d06d283..17975de2 100644 --- a/share/www/script/futon.browse.js +++ b/share/www/script/futon.browse.js @@ -62,7 +62,8 @@ .find("td.size").text($.futon.formatSize(info.disk_size)).end() .find("td.count").text(info.doc_count).end() .find("td.seq").text(info.update_seq); - } + }, + error : function() {} }); }); $("#databases tbody tr:odd").addClass("odd"); @@ -96,7 +97,10 @@ // Page class for browse/database.html CouchDatabasePage: function() { var urlParts = location.search.substr(1).split("/"); - var dbName = decodeURIComponent(urlParts.shift()); + var dbName = decodeURIComponent(urlParts.shift()) + + var dbNameRegExp = new RegExp("[^a-z0-9\_\$\(\)\+\/\-]", "g"); + dbName = dbName.replace(dbNameRegExp, ""); $.futon.storage.declareWithPrefix(dbName + ".", { desc: {}, @@ -106,7 +110,8 @@ reduce: {}, group_level: {defaultValue: 100}, per_page: {defaultValue: 10}, - view: {defaultValue: ""} + view: {defaultValue: ""}, + stale: {defaultValue: false} }); var viewName = (urlParts.length > 0) ? urlParts.join("/") : null; @@ -117,7 +122,7 @@ if (viewName) { this.redirecting = true; location.href = "database.html?" + encodeURIComponent(dbName) + - "/" + viewName; + "/" + encodeURIComponent(viewName); } } var db = $.couch.db(dbName); @@ -133,47 +138,33 @@ var templates = { javascript: "function(doc) {\n emit(null, doc);\n}", python: "def fun(doc):\n yield None, doc", - ruby: "{|doc|\n emit(nil, doc);\n}" + ruby: "lambda {|doc|\n emit(nil, doc);\n}" } this.newDocument = function() { location.href = "document.html?" + encodeURIComponent(db.name); } - this.compactDatabase = function() { - $.showDialog("dialog/_compact_database.html", { - submit: function(data, callback) { - db.compact({ - success: function(resp) { - callback(); - } - }); - } - }); - } - - this.viewCleanup = function() { - $.showDialog("dialog/_view_cleanup.html", { - submit: function(data, callback) { - db.viewCleanup({ - success: function(resp) { - callback(); - } - }); - } - }); - } - - this.compactView = function() { - var groupname = page.viewName.substring(8, - page.viewName.indexOf('/_view')); - $.showDialog("dialog/_compact_view.html", { + this.compactAndCleanup = function() { + $.showDialog("dialog/_compact_cleanup.html", { submit: function(data, callback) { - db.compactView(groupname, { - success: function(resp) { - callback(); - } - }); + switch (data.action) { + case "compact_database": + db.compact({success: function(resp) { callback() }}); + break; + case "compact_views": + var idx = page.viewName.indexOf("/_view"); + if (idx == -1) { + alert("Compact Views requires focus on a view!"); + } else { + var groupname = page.viewName.substring(8, idx); + db.compactView(groupname, {success: function(resp) { callback() }}); + } + break; + case "view_cleanup": + db.viewCleanup({success: function(resp) { callback() }}); + break; + } } }); } @@ -197,6 +188,76 @@ }); } + this.databaseSecurity = function() { + $.showDialog("dialog/_database_security.html", { + load : function(d) { + db.getDbProperty("_security", { + success: function(r) { + ["admin", "reader"].forEach(function(key) { + var names = []; + var roles = []; + + if (r && typeof r[key + "s"] === "object") { + if ($.isArray(r[key + "s"]["names"])) { + names = r[key + "s"]["names"]; + } + if ($.isArray(r[key + "s"]["roles"])) { + roles = r[key + "s"]["roles"]; + } + } + + $("input[name=" + key + "_names]", d).val(JSON.stringify(names)); + $("input[name=" + key + "_roles]", d).val(JSON.stringify(roles)); + }); + } + }); + }, + // maybe this should be 2 forms + submit: function(data, callback) { + var errors = {}; + var secObj = { + admins: { + names: [], + roles: [] + }, + readers: { + names: [], + roles: [] + } + }; + + ["admin", "reader"].forEach(function(key) { + var names, roles; + + try { + names = JSON.parse(data[key + "_names"]); + } catch(e) { } + try { + roles = JSON.parse(data[key + "_roles"]); + } catch(e) { } + + if ($.isArray(names)) { + secObj[key + "s"]["names"] = names; + } else { + errors[key + "_names"] = "The " + key + + " names must be an array of strings"; + } + if ($.isArray(roles)) { + secObj[key + "s"]["roles"] = roles; + } else { + errors[key + "_roles"] = "The " + key + + " roles must be an array of strings"; + } + }); + + if ($.isEmptyObject(errors)) { + db.setDbProperty("_security", secObj); + } + callback(errors); + } + }); + } + this.populateViewEditor = function() { if (viewName.match(/^_design\//)) { page.revertViewChanges(function() { @@ -318,7 +379,8 @@ var path = $.couch.encodeDocId(doc._id) + "/_view/" + encodeURIComponent(viewNames[j]); var option = $(document.createElement("option")) - .attr("value", path).text(viewNames[j]).appendTo(optGroup); + .attr("value", path).text(encodeURIComponent(viewNames[j])) + .appendTo(optGroup); if (path == viewName) { option[0].selected = true; } @@ -354,7 +416,7 @@ } var viewCode = resp.views[localViewName]; page.viewLanguage = resp.language || "javascript"; - $("#language").val(page.viewLanguage); + $("#language").val(encodeURIComponent(page.viewLanguage)); page.updateViewEditor(viewCode.map, viewCode.reduce || ""); $("#viewcode button.revert, #viewcode button.save").attr("disabled", "disabled"); page.storedViewCode = viewCode; @@ -366,7 +428,7 @@ page.updateViewEditor(page.storedViewCode.map, page.storedViewCode.reduce || ""); page.viewLanguage = page.storedViewLanguage; - $("#language").val(page.viewLanguage); + $("#language").val(encodeURIComponent(page.viewLanguage)); $("#viewcode button.revert, #viewcode button.save").attr("disabled", "disabled"); page.isDirty = false; if (callback) callback(); @@ -450,7 +512,8 @@ callback({ docid: "Cannot save to " + data.docid + " because its language is \"" + doc.language + - "\", not \"" + page.viewLanguage + "\"." + "\", not \"" + + encodeURIComponent(page.viewLanguage) + "\"." }); return; } @@ -620,7 +683,7 @@ if (row.id) { $("<td class='key'><a href='document.html?" + encodeURIComponent(db.name) + "/" + $.couch.encodeDocId(row.id) + "'><strong></strong><br>" + - "<span class='docid'>ID: " + row.id + "</span></a></td>") + "<span class='docid'>ID: " + $.futon.escape(row.id) + "</span></a></td>") .find("strong").text(key).end() .appendTo(tr); } else { @@ -712,6 +775,11 @@ db.query(currentMapCode, currentReduceCode, page.viewLanguage, options); } else { var viewParts = viewName.split('/'); + + if ($.futon.storage.get("stale")) { + options.stale = "ok"; + } + db.view(viewParts[1] + "/" + viewParts[3], options); } } @@ -774,7 +842,8 @@ $(this).html($("<pre></pre>").html($.futon.formatJSON(page.doc, {html: true}))) .makeEditable({allowEmpty: false, createInput: function(value) { - return $("<textarea rows='8' cols='80' spellcheck='false'></textarea>").enableTabInsertion(); + var rows = value.split("\n").length; + return $("<textarea rows='" + rows + "' cols='80' spellcheck='false'></textarea>").enableTabInsertion(); }, prepareInput: function(input) { $(input).makeResizable({vertical: true}); @@ -798,7 +867,7 @@ return true; } catch (err) { var msg = err.message; - if (msg == "parseJSON" || msg == "JSON.parse") { + if (msg == "parseJSON" || msg == "JSON.parse") { msg = "There is a syntax error in the document."; } $("<div class='error'></div>").text(msg).appendTo(this); @@ -1042,10 +1111,11 @@ row.find("td").makeEditable({acceptOnBlur: false, allowEmpty: true, createInput: function(value) { + value = doc[row.data("name")]; var elem = $(this); if (elem.find("dl").length > 0 || elem.find("code").is(".array, .object") || - elem.find("code.string").text().length > 60) { + typeof(value) == "string" && (value.length > 60 || value.match(/\n/))) { return $("<textarea rows='1' cols='40' spellcheck='false'></textarea>"); } return $("<input type='text' spellcheck='false'>"); @@ -1117,7 +1187,40 @@ html: true, escapeStrings: false }); - return $(html); + var n = $(html); + if (n.text().length > 140) { + // This code reduces a long string in to a summarized string with a link to expand it. + // Someone, somewhere, is doing something nasty with the event after it leaves these handlers. + // At this time I can't track down the offender, it might actually be a jQuery propogation issue. + var fulltext = n.text(); + var mintext = n.text().slice(0, 140); + var e = $('<a href="#expand">...</a>'); + var m = $('<a href="#min">X</a>'); + var expand = function (evt) { + n.empty(); + n.text(fulltext); + n.append(m); + evt.stopPropagation(); + evt.stopImmediatePropagation(); + evt.preventDefault(); + } + var minimize = function (evt) { + n.empty(); + n.text(mintext); + // For some reason the old element's handler won't fire after removed and added again. + e = $('<a href="#expand">...</a>'); + e.click(expand); + n.append(e); + evt.stopPropagation(); + evt.stopImmediatePropagation(); + evt.preventDefault(); + } + e.click(expand); + n.click(minimize); + n.text(mintext); + n.append(e) + } + return n; } } var elem = render(value); @@ -1179,7 +1282,7 @@ for (var i=0; i < parts.length; i++) { encoded.push(encodeURIComponent(parts[i])); }; - return encoded.join('/'); + return encoded.join('%2f'); } })(jQuery); |