From 4cd710ae4d2c813f41f8a8bb75595ec2202e7d6e Mon Sep 17 00:00:00 2001 From: Christopher Lenz Date: Wed, 9 Dec 2009 23:06:13 +0000 Subject: A couple of Futon improvements: * JSON strings are now displayed as-is in the document view, without the escaping of new-lines and quotes. That dramatically improves readability of multi-line strings. * Same goes for editing of JSON string values. When a change to a field value is submitted, and the value is not valid JSON it is assumed to be a string. This improves editing of multi-line strings a lot. * Hitting tab in textareas no longer moves focus to the next form field, but simply inserts a tab character at the current caret position. * Fixed some font declarations. git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@889013 13f79535-47bb-0310-9956-ffa450edef68 --- share/www/script/futon.browse.js | 37 ++++++++++++++++++++------------- share/www/script/futon.format.js | 19 +++++++++++++++-- share/www/script/futon.js | 20 ++++++++++++++++++ share/www/style/layout.css | 45 +++++++++++++++++++++++++++++----------- 4 files changed, 93 insertions(+), 28 deletions(-) (limited to 'share') diff --git a/share/www/script/futon.browse.js b/share/www/script/futon.browse.js index e962ee9c..d5b860e2 100644 --- a/share/www/script/futon.browse.js +++ b/share/www/script/futon.browse.js @@ -189,7 +189,8 @@ } }, 100); } - $("#viewcode textarea").bind("input", updateDirtyState); + $("#viewcode textarea").enableTabInsertion() + .bind("input", updateDirtyState); if ($.browser.msie || $.browser.safari) { $("#viewcode textarea").bind("paste", updateDirtyState) .bind("change", updateDirtyState) @@ -720,7 +721,7 @@ $(this).html($("
").html($.futon.formatJSON(page.doc, {html: true})))
             .makeEditable({allowEmpty: false,
               createInput: function(value) {
-                return $("");
+                return $("").enableTabInsertion();
               },
               prepareInput: function(input) {
                 $(input).makeResizable({vertical: true});
@@ -985,10 +986,10 @@
           return;
         }
 
-        row.find("td").makeEditable({allowEmpty: true,
+        row.find("td").makeEditable({acceptOnBlur: false, allowEmpty: true,
           createInput: function(value) {
             if ($("dl", this).length > 0 || $("code", this).text().length > 60) {
-              return $("");
+              return $("");
             }
             return $("");
           },
@@ -998,12 +999,17 @@
           },
           prepareInput: function(input) {
             if ($(input).is("textarea")) {
-              $(input).makeResizable({vertical: true});
+              var height = Math.min(input.scrollHeight, document.body.clientHeight - 100);
+              $(input).height(height).makeResizable({vertical: true}).enableTabInsertion();
             }
           },
           accept: function(newValue) {
             var fieldName = row.data("name");
-            doc[fieldName] = JSON.parse(newValue);
+            try {
+              doc[fieldName] = JSON.parse(newValue);
+            } catch (err) {
+              doc[fieldName] = newValue;
+            }
             page.isDirty = true;
             if (fieldName == "_id") {
               page.docId = page.doc._id = doc[fieldName];
@@ -1011,7 +1017,11 @@
             }
           },
           populate: function(value) {
-            return $.futon.formatJSON(doc[row.data("name")]);
+            value = doc[row.data("name")];
+            if (typeof(value) == "string") {
+              return value;
+            }
+            return $.futon.formatJSON(value);
           },
           validate: function(value) {
             $("div.error", this).remove();
@@ -1024,12 +1034,7 @@
               }
               return true;
             } catch (err) {
-              var msg = err.message;
-              if (msg == "parseJSON" || msg == "JSON.parse") {
-                msg = "Please enter a valid JSON value (for example, \"string\").";
-              }
-              $("
").text(msg).appendTo(this); - return false; + return true; } } }); @@ -1046,7 +1051,11 @@ } return list; } else { - return $($.futon.formatJSON(val, {html: true})); + var html = $.futon.formatJSON(val, { + html: true, + escapeStrings: false + }); + return $(html); } } var elem = render(value); diff --git a/share/www/script/futon.format.js b/share/www/script/futon.format.js index 7d70bfc2..674f5f8f 100644 --- a/share/www/script/futon.format.js +++ b/share/www/script/futon.format.js @@ -17,6 +17,7 @@ // JSON pretty printing formatJSON: function(val, options) { options = $.extend({ + escapeStrings: true, indent: 4, linesep: "\n", quoteKeys: true @@ -39,9 +40,14 @@ case "boolean": case "number": case "string": - var retval = JSON.stringify(val); + var retval = val; + if (type == "string" && !options.escapeStrings) { + retval = indentLines(retval, tab); + } else { + retval = escape(JSON.stringify(val)); + } if (options.html) { - retval = "" + escape(retval) + ""; + retval = "" + retval + ""; } return retval; @@ -95,6 +101,14 @@ } } + function indentLines(text, tab) { + var lines = text.split("\n"); + for (var i in lines) { + lines[i] = (i > 0 ? tab : "") + escape(lines[i]); + } + return lines.join("
"); + } + return format(val, 1); }, @@ -112,4 +126,5 @@ } }); + })(jQuery); diff --git a/share/www/script/futon.js b/share/www/script/futon.js index f6b1d9f6..31f04a90 100644 --- a/share/www/script/futon.js +++ b/share/www/script/futon.js @@ -159,6 +159,26 @@ }); } + $.fn.enableTabInsertion = function(chars) { + chars = chars || "\t"; + var width = chars.length; + return this.keydown(function(evt) { + if (evt.keyCode == 9) { + var v = this.value; + var start = this.selectionStart; + var scrollTop = this.scrollTop; + if (start !== undefined) { + this.value = v.slice(0, start) + chars + v.slice(start); + this.selectionStart = this.selectionEnd = start + width; + } else { + document.selection.createRange().text = chars; + this.caretPos += width; + } + return false; + } + }); + } + $(document) .ajaxStart(function() { $(this.body).addClass("loading"); }) .ajaxStop(function() { $(this.body).removeClass("loading"); }); diff --git a/share/www/style/layout.css b/share/www/style/layout.css index ae442f1c..0b3b6cf5 100644 --- a/share/www/style/layout.css +++ b/share/www/style/layout.css @@ -23,7 +23,7 @@ html, body { color: #000; font: normal 90% Arial,Helvetica,sans-serif; h1 { background: #333; border-right: 2px solid #111; border-bottom: 1px solid #333; color: #999; - font: 125% normal Arial,Helvetica,sans-serif; height: 32px; + font: normal 125% Arial,Helvetica,sans-serif; height: 32px; line-height: 32px; margin: 0; padding: 0 0 0 .5em; position: relative; } h1 :link, h1 :visited, h1 strong { padding: .4em .5em; } @@ -44,7 +44,9 @@ body.loading h1 strong { hr { border: 1px solid #999; border-width: 1px 0 0; } dl dt { font-weight: bold; } -code, tt, pre { font-family: "DejaVu Sans Mono",Monaco,monospace; } +code, tt, pre { + font-family: "DejaVu Sans Mono",Menlo,Courier,monospace; +} code.key { color: #333; font-weight: bold; } code.string { color: #393; } code.number, code.boolean { color: #339; } @@ -56,7 +58,10 @@ input, select, textarea { background: #fff; border: 1px solid; border-color: #999 #ddd #ddd #999; margin: 0; padding: 1px; } input.placeholder { color: #999; } -textarea { font-family: "DejaVu Sans Mono",Monaco,monospace; font-size: 100%; } +textarea { + font-family: "DejaVu Sans Mono",Menlo,Courier,monospace; + font-size: 100%; +} fieldset { border: none; font-size: 95%; margin: 0; padding: .2em 0 0; } fieldset legend { color: #666; font-weight: bold; padding: 0; } fieldset input, fieldset select { font-size: 95%; } @@ -370,7 +375,7 @@ body.fullwidth #wrap { margin-right: 0; } #documents thead th { width: 50%; } #documents tbody.content td { color: #999; - font: normal 11px "DejaVu Sans Mono",Monaco,monospace; + font: normal 11px "DejaVu Sans Mono",Menlo,Courier,monospace; } #documents tbody.content td.key { color: #333; } #documents tbody.content td.key a { display: block; } @@ -411,8 +416,13 @@ body.fullwidth #wrap { margin-right: 0; } padding-right: 48px; } #fields tbody.content td code { display: block; font-size: 11px; - padding: 2px 2px 2px 3px; + padding: 2px 2px 2px 3px; position: relative; +} +#fields tbody.content td code.string:before { color: #ccc; content: "“"; + position: absolute; left: -4px; } +#fields tbody.content td code.string:after { color: #ccc; content: "”"; } + #fields tbody.content td dl { margin: 0; padding: 0; } #fields tbody.content td dt { background: transparent url(../image/toggle-collapse.gif) 0 3px no-repeat; @@ -429,23 +439,33 @@ body.fullwidth #wrap { margin-right: 0; } float: left; margin-left: 0; padding-left: 2px; padding-right: .5em; padding-top: 2px; } -#fields tbody.content input, #fields tbody.content textarea, #fields tbody.source textarea { +#fields tbody.content td dd code.string { left: 4px; text-indent: -6px; + white-space: pre-wrap; +} +#fields tbody.content td dd code.string:before { position: static; } +#fields tbody.content input, #fields tbody.content textarea, +#fields tbody.source textarea { background: #fff; border: 1px solid; border-color: #999 #ddd #ddd #999; margin: 0; padding: 1px; width: 100%; } #fields tbody.content th input { font-family: inherit; font-size: inherit; font-weight: bold; } -#fields tbody.content td input, #fields tbody.content td textarea, #fields tbody.source textarea { - font: 11px normal "DejaVu Sans Mono",Monaco,monospace; +#fields tbody.content td input, #fields tbody.content td textarea, +#fields tbody.source textarea { + font: normal 11px "DejaVu Sans Mono",Menlo,Courier,monospace; } #fields tbody.content input.invalid, #fields tbody.content textarea.invalid, #fields tbody.source textarea.invalid { background: #f9f4f4; border-color: #b66 #ebb #ebb #b66; } -#fields tbody.content div.grippie, #fields tbody.source div.gripple { padding: 0 1px; width: 100%; } -#fields tbody.content div.error, #fields tbody.source div.error { color: #d33; } +#fields tbody.content div.grippie, #fields tbody.source div.grippie { + padding: 0 1px; width: 100%; +} +#fields tbody.content div.error, #fields tbody.source div.error { + color: #d33; +} #fields tbody.content td ul.attachments { list-style: none; margin: 0; padding: 0; @@ -527,7 +547,7 @@ body.fullwidth #wrap { margin-right: 0; } #config tbody td.value code.editinline-container { padding: 0; } #config tbody td input { background: #fff; border: 1px solid; border-color: #999 #ddd #ddd #999; - font: 11px normal "DejaVu Sans Mono",Monaco,monospace; + font: normal 11px "DejaVu Sans Mono",Menlo,Courier,monospace; margin: 0; padding: 1px; width: 100%; } @@ -557,5 +577,6 @@ form#replicator p.actions { padding: 1px; clear: left; margin: 0; #status tr.none th { color: #666; font-weight: normal; } #status td.object, #status td.pid { - font-family: "DejaVu Sans Mono",Monaco,monospace; font-size: 11px; + font-family: "DejaVu Sans Mono",Menlo,Courier,monospace; + font-size: 11px; } -- cgit v1.2.3