You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ga...@apache.org on 2014/07/25 11:04:02 UTC

[1/3] fauxton commit: updated refs/heads/master to d68bc8e

Repository: couchdb-fauxton
Updated Branches:
  refs/heads/master 893e9881d -> d68bc8e4c


restore state of couchdb in couchdb-fauxon

automatically expand ace correctly

remove unnecessary resize, improve comments

have save warning right in principle

final brush-up


Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/b340f1dd
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/b340f1dd
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/b340f1dd

Branch: refs/heads/master
Commit: b340f1dd3b04e41c4bdc28d8a4e2d9524053a6f8
Parents: 99665a1
Author: sebastianrothbucher <se...@googlemail.com>
Authored: Mon Jul 14 23:08:18 2014 +0200
Committer: sebastianrothbucher <se...@googlemail.com>
Committed: Fri Jul 18 00:26:34 2014 +0200

----------------------------------------------------------------------
 app/addons/documents/assets/less/documents.less |  24 ++++
 app/addons/documents/templates/code_editor.html |   2 +
 .../documents/templates/string_edit_modal.html  |  30 +++++
 app/addons/documents/views.js                   | 122 ++++++++++++++++++-
 app/addons/fauxton/components.js                |  48 +++++++-
 5 files changed, 223 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/b340f1dd/app/addons/documents/assets/less/documents.less
----------------------------------------------------------------------
diff --git a/app/addons/documents/assets/less/documents.less b/app/addons/documents/assets/less/documents.less
index e62be30..0537595 100644
--- a/app/addons/documents/assets/less/documents.less
+++ b/app/addons/documents/assets/less/documents.less
@@ -152,4 +152,28 @@ button.beautify {
   }
 }
 
+button.string-edit {
+  position: absolute;
+  padding: 0;
+  z-index: 1000;
+  width: 16px;
+  left: 22px;
+}
+
+button.string-edit[disabled] {
+  display: none;
+}
+
+#string-edit-modal {
+  div.modal {
+    overflow-x: visible;
+    width: initial;
+    min-width: 560px;
+  }
+}
+
+#string-editor-wrapper {
+  height: 500px;
+  width: 100%;
+}
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/b340f1dd/app/addons/documents/templates/code_editor.html
----------------------------------------------------------------------
diff --git a/app/addons/documents/templates/code_editor.html b/app/addons/documents/templates/code_editor.html
index 811e111..2198079 100644
--- a/app/addons/documents/templates/code_editor.html
+++ b/app/addons/documents/templates/code_editor.html
@@ -22,6 +22,7 @@ the License.
   </div>
 
   <div class="span7">
+    <button class="btn string-edit" title="Edit line" disabled="true"><i class="icon icon-edit"></i></button>
     <% if (attachments) { %>
     <div class="btn-group">
       <button class="dropdown-toggle btn" data-bypass="true" data-toggle="dropdown">
@@ -48,6 +49,7 @@ the License.
 
 <div id="upload-modal"> </div>
 <div id="duplicate-modal"> </div> 
+<div id="string-edit-modal"> </div> 
 </div>
 
   <div id="editor-container" class="doc-code"><%- JSON.stringify(doc.attributes, null, "  ") %></div>

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/b340f1dd/app/addons/documents/templates/string_edit_modal.html
----------------------------------------------------------------------
diff --git a/app/addons/documents/templates/string_edit_modal.html b/app/addons/documents/templates/string_edit_modal.html
new file mode 100644
index 0000000..1177795
--- /dev/null
+++ b/app/addons/documents/templates/string_edit_modal.html
@@ -0,0 +1,30 @@
+<!--
+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.
+-->
+
+<div class="modal hide fade">
+  <div class="modal-header">
+    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+    <h3>Edit text <span id="string-edit-header"></span></h3>
+  </div>
+  <div class="modal-body">
+    <div id="modal-error" class="hide alert alert-error"/>
+    <div id="string-editor-wrapper"><div id="string-editor-container" class="doc-code"></div></div>
+  </div>
+  <div class="modal-footer">
+    <button data-dismiss="modal" class="btn"><i class="icon fonticon-circle-x"></i> Cancel</button>
+    <button id="string-edit-save-btn" class="btn btn-success save"><i class="fonticon-circle-check"></i> Save</button>
+  </div>
+</div>
+
+

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/b340f1dd/app/addons/documents/views.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/views.js b/app/addons/documents/views.js
index 6ccb733..9e397af 100644
--- a/app/addons/documents/views.js
+++ b/app/addons/documents/views.js
@@ -247,6 +247,62 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb,
     }
   });
 
+  Views.StringEditModal = Components.ModalView.extend({
+    template: "addons/documents/templates/string_edit_modal",
+
+    initialize: function () {
+      _.bindAll(this);
+    },
+
+    events: {
+      "click #string-edit-save-btn":"saveString"
+    },
+  
+    saveString: function (event) {
+      event.preventDefault();
+      var newStr = this.subEditor.getValue();
+      this.subEditor.editSaved();
+      this.editor.replaceCurrentLine(this.indent + this.hashKey + JSON.stringify(newStr) + this.comma + "\n");
+      this.hideModal();
+    },
+
+    _showModal: function () {
+      this.$('.bar').css({width: '0%'});
+      this.$('.progress').addClass('hide');
+      this.clear_error_msg();
+    }, 
+
+    openWin: function(editor, indent, hashKey, jsonString, comma) {
+      this.editor = editor;
+      this.indent = indent;
+      this.hashKey = hashKey;      
+      this.$('#string-edit-header').text(hashKey);
+      this.subEditor.setValue(JSON.parse(jsonString));
+      /* make sure we don't have save warnings w/out change */
+      this.subEditor.editSaved();
+      this.comma = comma;
+      this.showModal();
+    },
+
+    afterRender: function() {
+      /* make sure we init only ONCE */
+      if (!this.subEditor) {
+        this.subEditor = new Components.Editor({
+          editorId: "string-editor-container",
+          mode: "plain"
+        });
+        this.subEditor.render();
+        /* optimize by disabling auto sizing (35 is the lines fitting into the pop-up) */
+        this.subEditor.configureFixedHeightEditor(35);
+      }
+    },
+
+    cleanup: function () {
+      if (this.subEditor) this.subEditor.remove();
+    }
+
+  });
+
   Views.Document = FauxtonAPI.View.extend({
     template: "addons/documents/templates/all_docs_item",
     tagName: "tr",
@@ -751,7 +807,8 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb,
       "click button.delete": "destroy",
       "click button.duplicate": "duplicate",
       "click button.upload": "upload",
-      "click button.cancel-button": "goback"
+      "click button.cancel-button": "goback",
+      "click button.string-edit": "stringEditing"
     },
 
     disableLoader: true,
@@ -765,6 +822,57 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb,
       FauxtonAPI.navigate(this.database.url("index") + "?limit=100");
     },
 
+    determineStringEditMatch: function(event) {
+      var selStart = this.editor.getSelectionStart().row;
+      var selEnd = this.editor.getSelectionEnd().row;
+      /* one JS(ON) string can't span more than one line - we edit one string, so ensure we don't select several lines */
+      if (selStart >=0 && selEnd >= 0 && selStart === selEnd && this.editor.isRowExpanded(selStart)) {    
+        var editLine = this.editor.getLine(selStart);
+	var editMatch = editLine.match(/^([ \t]*)("[a-zA-Z0-9_]*": )?(".*",?[ \t]*)$/);
+	if (editMatch) {
+          return editMatch;
+	} else {
+          return null;
+	}
+      } else {
+        return null;
+      }
+    }, 
+
+    showHideEditDocString: function (event) {
+      this.$("button.string-edit").attr("disabled", "true");
+      if (!this.hasValidCode()) {
+        return false;
+      }
+      var editMatch = this.determineStringEditMatch(event);
+      if (editMatch) {
+        this.$("button.string-edit").removeAttr("disabled");
+	/* remove the following line (along with CSS) to go back to the toolbar */
+        this.$("button.string-edit").css("top", (this.$("#editor-container")[0].offsetTop - 2 + this.editor.getRowHeight() * this.editor.documentToScreenRow(this.editor.getSelectionStart().row)) + "px");
+        return true;
+      }
+      return false;
+    },
+
+    stringEditing: function(event) {
+      event.preventDefault();   
+      if (!this.hasValidCode()) {
+        return;
+      }
+      var editMatch = this.determineStringEditMatch(event);
+      if (editMatch) {
+        var indent = editMatch[1] || "",
+              hashKey = editMatch[2] || "",
+              editText = editMatch[3],
+              comma = "";
+        if (editText.substring(editText.length - 1) === ",") {
+          editText = editText.substring(0, editText.length - 1); 
+          comma = ",";
+        }
+        this.stringEditModal.openWin(this.editor, indent, hashKey, editText, comma);
+      }
+    },
+
     destroy: function(event) {
       if (this.model.isNewDoc()) {
         FauxtonAPI.addNotification({
@@ -802,6 +910,10 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb,
 
       this.duplicateModal = this.setView('#duplicate-modal', new Views.DuplicateDocModal({model: this.model}));
       this.duplicateModal.render();
+
+      /* initialization is automatic - and make sure ONCE */
+      this.stringEditModal = this.stringEditModal || this.setView('#string-edit-modal', new Views.StringEditModal());
+      /* this.stringEditModal.render(); */
     },
 
     upload: function (event) {
@@ -999,6 +1111,14 @@ function(app, FauxtonAPI, Components, Documents, Databases, pouchdb,
           clear:  true
         });
       });
+
+      var that = this;
+      this.listenTo(editor.editor, "changeSelection", function (event) {
+        that.showHideEditDocString(event);
+      });
+      this.listenTo(editor.editor.session, "changeBackMarker", function (event) {
+        that.showHideEditDocString(event);
+      });
     },
 
     cleanup: function () {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/b340f1dd/app/addons/fauxton/components.js
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/components.js b/app/addons/fauxton/components.js
index 79a9320..f0dcc31 100644
--- a/app/addons/fauxton/components.js
+++ b/app/addons/fauxton/components.js
@@ -419,8 +419,9 @@ function(app, FauxtonAPI, ace, spin) {
       this.setHeightToLineCount();
 
       this.editor.setTheme("ace/theme/" + this.theme);
-
-      this.editor.getSession().setMode("ace/mode/" + this.mode);
+      if (this.mode != "plain") {
+        this.editor.getSession().setMode("ace/mode/" + this.mode);
+      }
       this.editor.setShowPrintMargin(false);
       this.addCommands();
 
@@ -529,6 +530,49 @@ function(app, FauxtonAPI, ace, spin) {
 
     isIgnorableError: function(msg) {
       return _.contains(this.excludedViewErrors, msg);
+    },
+
+    configureFixedHeightEditor: function(numLines) {
+      this.editor.renderer.setVScrollBarAlwaysVisible(true);
+      this.editor.renderer.setHScrollBarAlwaysVisible(true);
+      /* customize the ace scrolling for static edit height */
+      this.editor.renderer.$autosize = function() {
+        this.$size.height = numLines * this.lineHeight;
+        this.desiredHeight = numLines * this.lineHeight;
+        this.container.style.height = this.desiredHeight + "px";
+        this.scrollBarV.setVisible(true);
+        this.scrollBarH.setVisible(true);
+      };
+    },
+
+    replaceCurrentLine: function(replacement) {
+      this.editor.getSelection().selectLine();
+      this.editor.insert(replacement);
+      this.editor.getSelection().moveCursorUp();
+    },
+
+    getLine: function(lineNum) {
+      return this.editor.session.getLine(lineNum);
+    },
+
+    getSelectionStart: function() {
+      return this.editor.getSelectionRange().start;
+    },
+
+    getSelectionEnd: function() {
+      return this.editor.getSelectionRange().end;
+    },
+
+    getRowHeight: function() {
+      return this.editor.renderer.layerConfig.lineHeight;
+    },
+
+    isRowExpanded: function(row) {
+      return !this.editor.getSession().isRowFolded(row);
+    },
+
+    documentToScreenRow: function(row) {
+      return this.editor.getSession().documentToScreenRow(row, 0);
     }
 
   });


[3/3] fauxton commit: updated refs/heads/master to d68bc8e

Posted by ga...@apache.org.
Fine tune string edit.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/d68bc8e4
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/d68bc8e4
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/d68bc8e4

Branch: refs/heads/master
Commit: d68bc8e4c6c72118f8679f82651b04216b3afae6
Parents: 12f282c
Author: sebastianrothbucher <se...@googlemail.com>
Authored: Thu Jul 24 23:00:06 2014 +0200
Committer: Garren Smith <ga...@gmail.com>
Committed: Fri Jul 25 09:55:05 2014 +0200

----------------------------------------------------------------------
 app/addons/documents/views-doceditor.js | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/d68bc8e4/app/addons/documents/views-doceditor.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/views-doceditor.js b/app/addons/documents/views-doceditor.js
index 5514bd2..e05b8f4 100644
--- a/app/addons/documents/views-doceditor.js
+++ b/app/addons/documents/views-doceditor.js
@@ -252,8 +252,9 @@ function(app, FauxtonAPI, Components, Documents, Databases,
       var editMatch = this.determineStringEditMatch(event);
       if (editMatch) {
         this.$("button.string-edit").removeAttr("disabled");
-	/* remove the following line (along with CSS) to go back to the toolbar */
-        this.$("button.string-edit").css("top", (this.$("#editor-container")[0].offsetTop - 2 + this.editor.getRowHeight() * this.editor.documentToScreenRow(this.editor.getSelectionStart().row)) + "px");
+        /* remove the following line (along with CSS) to go back to the toolbar: take the offset top of the editor, go down as many lines as we are positioned including fold and adjust by two pixels as the button is slightly larger than a line */
+        var positionFromTop = (this.$("#editor-container").offset().top - 2 + this.editor.getRowHeight() * this.editor.documentToScreenRow(this.editor.getSelectionStart().row));
+        this.$("button.string-edit").css("top", positionFromTop + "px");
         return true;
       }
       return false;


[2/3] fauxton commit: updated refs/heads/master to d68bc8e

Posted by ga...@apache.org.
upstream merge


Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/12f282c4
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/12f282c4
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/12f282c4

Branch: refs/heads/master
Commit: 12f282c455e91f359a33d02668f20e429d679683
Parents: b340f1d 893e988
Author: sebastianrothbucher <se...@googlemail.com>
Authored: Thu Jul 24 22:50:48 2014 +0200
Committer: sebastianrothbucher <se...@googlemail.com>
Committed: Thu Jul 24 22:50:48 2014 +0200

----------------------------------------------------------------------
 Gruntfile.js                                    |   11 +-
 app/addons/activetasks/templates/tabs.html      |   11 +-
 app/addons/activetasks/views.js                 |    2 +
 app/addons/config/templates/item.html           |    8 +-
 .../documents/assets/less/advancedOptions.less  |    1 +
 app/addons/documents/assets/less/changes.less   |   31 +
 app/addons/documents/assets/less/documents.less |   87 +-
 app/addons/documents/assets/less/sidenav.less   |  147 ++
 app/addons/documents/routes.js                  |  137 +-
 .../documents/templates/all_docs_layout.html    |   12 +-
 app/addons/documents/templates/changes.html     |    4 +-
 app/addons/documents/templates/code_editor.html |    4 +-
 app/addons/documents/templates/ddoc_info.html   |    2 +-
 .../templates/delete_database_modal.html        |    4 +-
 .../documents/templates/design_doc_menu.html    |   32 +
 .../templates/design_doc_selector.html          |    3 +
 .../templates/duplicate_doc_modal.html          |    4 +-
 .../documents/templates/index_menu_item.html    |   17 +-
 app/addons/documents/templates/search.html      |   15 -
 app/addons/documents/templates/sidebar.html     |   69 +-
 .../documents/templates/upload_modal.html       |    4 +-
 app/addons/documents/templates/view_editor.html |    7 +-
 app/addons/documents/views-advancedopts.js      |  270 +++
 app/addons/documents/views-changes.js           |   84 +
 app/addons/documents/views-doceditor.js         |  535 +++++
 app/addons/documents/views-index.js             |  574 ++++++
 app/addons/documents/views-sidebar.js           |  253 +++
 app/addons/documents/views.js                   | 1587 +--------------
 app/addons/fauxton/base.js                      |   22 +-
 app/addons/fauxton/components.js                |   27 +
 app/addons/fauxton/templates/api_bar.html       |   16 +-
 app/addons/fauxton/templates/breadcrumbs.html   |    2 +-
 app/addons/fauxton/templates/menu_dropdown.html |   33 +
 app/addons/permissions/templates/section.html   |    4 +-
 app/addons/verifyinstall/base.js                |    2 +-
 app/templates/layouts/two_pane.html             |    1 -
 app/templates/layouts/with_tabs_sidebar.html    |    6 +-
 assets/fonts/FontAwesome.otf                    |  Bin 0 -> 61896 bytes
 assets/fonts/Gemfile                            |    5 +
 assets/fonts/Gemfile.lock                       |   31 +
 assets/fonts/README.md                          |   39 +
 assets/fonts/fauxtonicon.eot                    |  Bin 0 -> 16314 bytes
 assets/fonts/fauxtonicon.svg                    |  644 ++++++
 assets/fonts/fauxtonicon.ttf                    |  Bin 0 -> 16130 bytes
 assets/fonts/fauxtonicon.woff                   |  Bin 0 -> 5804 bytes
 assets/fonts/fontawesome-webfont.eot            |  Bin 0 -> 37405 bytes
 assets/fonts/fontawesome-webfont.svg            |  399 ++++
 assets/fonts/fontawesome-webfont.ttf            |  Bin 0 -> 79076 bytes
 assets/fonts/fontawesome-webfont.woff           |  Bin 0 -> 43572 bytes
 assets/fonts/fontcustom.yml                     |   51 +
 .../fonts/styleguide/fauxtonicon-preview.html   | 1868 ++++++++++++++++++
 assets/fonts/templates/icons.less               |   30 +
 assets/icons/activetasks.svg                    |    8 +
 assets/icons/arrow-box-down.svg                 |    8 +
 assets/icons/arrow-box-up.svg                   |    8 +
 assets/icons/arrow_left.svg                     |    7 +
 assets/icons/arrow_right.svg                    |    7 +
 assets/icons/arrows-cw.svg                      |    8 +
 assets/icons/article.svg                        |    8 +
 assets/icons/attention-alt.svg                  |    8 +
 assets/icons/attention-circled.svg              |    8 +
 assets/icons/block.svg                          |    8 +
 assets/icons/bookmark-ribbon-wplus.svg          |    8 +
 assets/icons/bookmark.svg                       |    8 +
 assets/icons/burger.svg                         |    8 +
 assets/icons/cancel-circled.svg                 |    8 +
 assets/icons/cancel-circled2.svg                |    8 +
 assets/icons/cancel.svg                         |    8 +
 assets/icons/circle-empty.svg                   |    8 +
 assets/icons/clipboard.svg                      |    8 +
 assets/icons/clock.svg                          |    8 +
 assets/icons/cog.svg                            |    8 +
 assets/icons/collapse.svg                       |    8 +
 assets/icons/cw.svg                             |    8 +
 assets/icons/dashboard.svg                      |    8 +
 assets/icons/database.svg                       |    8 +
 assets/icons/deselect-all.svg                   |   15 +
 assets/icons/document.svg                       |    8 +
 assets/icons/documents.svg                      |    8 +
 assets/icons/dot-circled.svg                    |    8 +
 assets/icons/down-1.svg                         |    8 +
 assets/icons/down-circled.svg                   |    8 +
 assets/icons/down-dir.svg                       |    8 +
 assets/icons/down-open.svg                      |    8 +
 assets/icons/down.svg                           |    8 +
 assets/icons/drop-down-dots.svg                 |    8 +
 assets/icons/exchange.svg                       |    8 +
 assets/icons/expand.svg                         |    8 +
 assets/icons/eye.svg                            |    8 +
 assets/icons/help-circled.svg                   |    8 +
 assets/icons/help.svg                           |    8 +
 assets/icons/info-circled.svg                   |    8 +
 assets/icons/json.svg                           |    8 +
 assets/icons/key.svg                            |    8 +
 assets/icons/left-1.svg                         |    8 +
 assets/icons/left-circled.svg                   |    8 +
 assets/icons/left-dir.svg                       |    8 +
 assets/icons/left-open.svg                      |    8 +
 assets/icons/left.svg                           |    8 +
 assets/icons/link.svg                           |    8 +
 assets/icons/list-alt.svg                       |    8 +
 assets/icons/lock.svg                           |    8 +
 assets/icons/mail-alt.svg                       |    8 +
 assets/icons/mail.svg                           |    8 +
 assets/icons/megaphone.svg                      |    8 +
 assets/icons/minus-circled.svg                  |    8 +
 assets/icons/minus-circled2.svg                 |    9 +
 assets/icons/minus-squared-alt.svg              |    8 +
 assets/icons/minus-squared.svg                  |    8 +
 assets/icons/minus.svg                          |    8 +
 assets/icons/mixer.svg                          |    8 +
 assets/icons/new-database.svg                   |    8 +
 assets/icons/ok-circled-2.svg                   |    8 +
 assets/icons/ok-circled.svg                     |    8 +
 assets/icons/ok.svg                             |    8 +
 assets/icons/paperclip.svg                      | 1364 +++++++++++++
 assets/icons/pencil.svg                         |    8 +
 assets/icons/picture.svg                        |    8 +
 assets/icons/play.svg                           |    8 +
 assets/icons/plus-circled.svg                   |    8 +
 assets/icons/plus-circled2.svg                  |   10 +
 assets/icons/plus-squared-alt.svg               |    8 +
 assets/icons/plus-squared.svg                   |    8 +
 assets/icons/plus.svg                           |    8 +
 assets/icons/popin.svg                          |    8 +
 assets/icons/popout.svg                         |    8 +
 assets/icons/profile.svg                        |    8 +
 assets/icons/replicate.svg                      |    8 +
 assets/icons/reply-all.svg                      |    8 +
 assets/icons/reply.svg                          |    8 +
 assets/icons/resize-full-reverse.svg            |    8 +
 assets/icons/resize-full.svg                    |    8 +
 assets/icons/resize-small-reverse.svg           |    8 +
 assets/icons/resize-small.svg                   |    8 +
 assets/icons/right-1.svg                        |    8 +
 assets/icons/right-circled.svg                  |    8 +
 assets/icons/right-dir.svg                      |    8 +
 assets/icons/right-open.svg                     |    8 +
 assets/icons/right.svg                          |    8 +
 assets/icons/save.svg                           |    8 +
 assets/icons/search.svg                         |    8 +
 assets/icons/select-all.svg                     |   11 +
 assets/icons/sidenav-filter-function.svg        |   10 +
 assets/icons/sidenav-info.svg                   |   15 +
 assets/icons/sidenav-list-function.svg          |   12 +
 assets/icons/sidenav-map-reduce.svg             |   13 +
 assets/icons/sidenav-search.svg                 |   17 +
 assets/icons/sidenav-show-function.svg          |   13 +
 assets/icons/sidenav-update-function.svg        |   12 +
 assets/icons/sitemap.svg                        |    8 +
 assets/icons/stats.svg                          |    8 +
 assets/icons/support.svg                        |    8 +
 assets/icons/swap-arrows.svg                    | 1318 ++++++++++++
 assets/icons/table.svg                          |    8 +
 assets/icons/trash.svg                          |    8 +
 assets/icons/up-1.svg                           |    8 +
 assets/icons/up-circled.svg                     |    8 +
 assets/icons/up-dir.svg                         |    8 +
 assets/icons/up-open.svg                        |    8 +
 assets/icons/up.svg                             |    8 +
 assets/icons/user.svg                           |    8 +
 assets/icons/users.svg                          |    8 +
 assets/icons/wrench.svg                         |    8 +
 assets/img/FontAwesome.otf                      |  Bin 61896 -> 0 bytes
 assets/img/fontawesome-webfont.eot              |  Bin 37405 -> 0 bytes
 assets/img/fontawesome-webfont.svg              |  399 ----
 assets/img/fontawesome-webfont.ttf              |  Bin 79076 -> 0 bytes
 assets/img/fontawesome-webfont.woff             |  Bin 43572 -> 0 bytes
 assets/img/fontcustom_fauxton.eot               |  Bin 7364 -> 0 bytes
 assets/img/fontcustom_fauxton.svg               |  200 --
 assets/img/fontcustom_fauxton.ttf               |  Bin 9636 -> 0 bytes
 assets/img/fontcustom_fauxton.woff              |  Bin 4816 -> 0 bytes
 assets/less/bootstrap/dropdowns.less            |   37 +-
 .../less/bootstrap/font-awesome/variables.less  |    2 +-
 assets/less/bootstrap/navs.less                 |    3 -
 assets/less/bootstrap/variables.less            |    8 +-
 assets/less/fauxton.less                        |  191 +-
 assets/less/icons.less                          |  272 ++-
 assets/less/mixins.less                         |   21 +
 assets/less/variables.less                      |    4 +-
 package.json                                    |    4 +-
 readme.md                                       |   41 +-
 tasks/couchserver.js                            |    4 +-
 183 files changed, 9388 insertions(+), 2494 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/12f282c4/app/addons/documents/assets/less/documents.less
----------------------------------------------------------------------
diff --cc app/addons/documents/assets/less/documents.less
index 0537595,c466e53..13bd4fc
--- a/app/addons/documents/assets/less/documents.less
+++ b/app/addons/documents/assets/less/documents.less
@@@ -119,6 -100,6 +100,31 @@@ button.beautify 
      font-size: 16px;
  }
  
++button.string-edit {
++  position: absolute;
++  padding: 0;
++  z-index: 1000;
++  width: 16px;
++  left: 22px;
++}
++
++button.string-edit[disabled] {
++  display: none;
++}
++
++#string-edit-modal {
++  div.modal {
++    overflow-x: visible;
++    width: initial;
++    min-width: 560px;
++  }
++}
++
++#string-editor-wrapper {
++  height: 500px;
++  width: 100%;
++}
++
  #keys-input {
    width: 100%;
  }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/12f282c4/app/addons/documents/templates/code_editor.html
----------------------------------------------------------------------
diff --cc app/addons/documents/templates/code_editor.html
index 2198079,4a14a9e..76d37ef
--- a/app/addons/documents/templates/code_editor.html
+++ b/app/addons/documents/templates/code_editor.html
@@@ -22,7 -22,6 +22,7 @@@ the License
    </div>
  
    <div class="span7">
-     <button class="btn string-edit" title="Edit line" disabled="true"><i class="icon icon-edit"></i></button>
++    <button class="btn string-edit" title="Edit line" disabled="true"><i class="icon icon-edit"></i></button>  
      <% if (attachments) { %>
      <div class="btn-group">
        <button class="dropdown-toggle btn" data-bypass="true" data-toggle="dropdown">

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/12f282c4/app/addons/documents/views-doceditor.js
----------------------------------------------------------------------
diff --cc app/addons/documents/views-doceditor.js
index 0000000,add8d8c..5514bd2
mode 000000,100644..100644
--- a/app/addons/documents/views-doceditor.js
+++ b/app/addons/documents/views-doceditor.js
@@@ -1,0 -1,416 +1,535 @@@
+ // 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",
+        "addons/fauxton/components",
+ 
+        "addons/documents/resources",
+        "addons/databases/resources",
+ 
+        // Libs
+        "addons/fauxton/resizeColumns",
+ 
+        // Plugins
+        "plugins/prettify"
+ ],
+ 
+ function(app, FauxtonAPI, Components, Documents, Databases,
+          resizeColumns, prettify) {
+ 
+   var Views = {};
+ 
+   /* Attachments upload modal */
+ 
+   Views.UploadModal = Components.ModalView.extend({
+     template: "addons/documents/templates/upload_modal",
+ 
+     events: {
+       "click #upload-btn": "uploadFile"
+     },
+ 
+     uploadFile: function (event) {
+       event.preventDefault();
+ 
+       var docRev = this.model.get('_rev'),
+           that = this,
+           $form = this.$('#file-upload');
+ 
+       if (!docRev) {
+         return this.set_error_msg('The document needs to be saved before adding an attachment.');
+       }
+ 
+       if ($('input[type="file"]')[0].files.length === 0) {
+         return this.set_error_msg('Selected a file to be uploaded.');
+       }
+ 
+       this.$('#_rev').val(docRev);
+ 
+       $form.ajaxSubmit({
+         url: this.model.url(),
+         type: 'POST',
+         beforeSend: this.beforeSend,
+         uploadProgress: this.uploadProgress,
+         success: this.success,
+         error: function (resp) {
+           console.log('ERR on upload', resp);
+           return that.set_error_msg('Could not upload document: ' + JSON.parse(resp.responseText).reason);
+         }
+       });
+     },
+ 
+     success: function (resp) {
+       var hideModal = this.hideModal,
+           $form = this.$('#file-upload');
+ 
+       FauxtonAPI.triggerRouteEvent('reRenderDoc');
+       //slight delay to make this transistion a little more fluid and less jumpy
+       setTimeout(function () {
+         $form.clearForm();
+         hideModal();
+         $('.modal-backdrop').remove();
+       }, 1000);
+     },
+ 
+     uploadProgress: function(event, position, total, percentComplete) {
+       this.$('.bar').css({width: percentComplete + '%'});
+     },
+ 
+     beforeSend: function () {
+       this.$('.progress').removeClass('hide');
+     },
+ 
+     _showModal: function () {
+       this.$('.bar').css({width: '0%'});
+       this.$('.progress').addClass('hide');
+     }
+   });
+ 
++  Views.StringEditModal = Components.ModalView.extend({
++    template: "addons/documents/templates/string_edit_modal",
++
++    initialize: function () {
++      _.bindAll(this);
++    },
++
++    events: {
++      "click #string-edit-save-btn":"saveString"
++    },
++  
++    saveString: function (event) {
++      event.preventDefault();
++      var newStr = this.subEditor.getValue();
++      this.subEditor.editSaved();
++      this.editor.replaceCurrentLine(this.indent + this.hashKey + JSON.stringify(newStr) + this.comma + "\n");
++      this.hideModal();
++    },
++
++    _showModal: function () {
++      this.$('.bar').css({width: '0%'});
++      this.$('.progress').addClass('hide');
++      this.clear_error_msg();
++    }, 
++
++    openWin: function(editor, indent, hashKey, jsonString, comma) {
++      this.editor = editor;
++      this.indent = indent;
++      this.hashKey = hashKey;      
++      this.$('#string-edit-header').text(hashKey);
++      this.subEditor.setValue(JSON.parse(jsonString));
++      /* make sure we don't have save warnings w/out change */
++      this.subEditor.editSaved();
++      this.comma = comma;
++      this.showModal();
++    },
++
++    afterRender: function() {
++      /* make sure we init only ONCE */
++      if (!this.subEditor) {
++        this.subEditor = new Components.Editor({
++          editorId: "string-editor-container",
++          mode: "plain"
++        });
++        this.subEditor.render();
++        /* optimize by disabling auto sizing (35 is the lines fitting into the pop-up) */
++        this.subEditor.configureFixedHeightEditor(35);
++      }
++    },
++
++    cleanup: function () {
++      if (this.subEditor) this.subEditor.remove();
++    }
++
++  });
+ 
+ 
+   /* Doc Duplication modal */
+   Views.DuplicateDocModal = Components.ModalView.extend({
+     template: "addons/documents/templates/duplicate_doc_modal",
+ 
+     initialize: function () {
+       _.bindAll(this);
+     },
+ 
+     events: {
+       "click #duplicate-btn":"duplicate",
+       "submit #doc-duplicate": "duplicate"
+ 
+     },
+ 
+     duplicate: function (event) {
+       event.preventDefault();
+       var newId = this.$('#dup-id').val(),
+           isDDoc = newId.match(/^_design\//),
+           removeDDocID = newId.replace(/^_design\//,""),
+           encodedID = isDDoc? "_design/"+ app.utils.safeURLName(removeDDocID):app.utils.safeURLName(newId);
+ 
+       this.hideModal();
+       FauxtonAPI.triggerRouteEvent('duplicateDoc', encodedID);
+     },
+ 
+     _showModal: function () {
+       this.$('.bar').css({width: '0%'});
+       this.$('.progress').addClass('hide');
+       this.clear_error_msg();
+       this.$('.modal').modal();
+       // hack to get modal visible
+       $('.modal-backdrop').css('z-index',1025);
+     },
+ 
+     showModal: function () {
+       var showModal = this._showModal,
+           setDefaultIdValue = this.setDefaultIdValue,
+           uuid = new FauxtonAPI.UUID();
+ 
+       uuid.fetch().then(function () {
+         setDefaultIdValue(uuid.next());
+         showModal();
+       });
+     },
+ 
+     setDefaultIdValue: function (id) {
+       this.$('#dup-id').val(id);
+     }
+   });
+ 
+   /* Document editor*/
+    Views.CodeEditor = FauxtonAPI.View.extend({
+     template: "addons/documents/templates/code_editor",
+     events: {
+       "click button.save-doc": "saveDoc",
+       "click button.delete": "destroy",
+       "click button.duplicate": "duplicate",
+       "click button.upload": "upload",
 -      "click button.cancel-button": "goback"
++      "click button.cancel-button": "goback",
++      "click button.string-edit": "stringEditing"
+     },
+ 
+     disableLoader: true,
+ 
+     initialize: function (options) {
+       this.database = options.database;
+       _.bindAll(this);
+     },
+ 
+     goback: function(){
+       FauxtonAPI.navigate(this.database.url("index") + "?limit=100");
+     },
+ 
++    determineStringEditMatch: function(event) {
++      var selStart = this.editor.getSelectionStart().row;
++      var selEnd = this.editor.getSelectionEnd().row;
++      /* one JS(ON) string can't span more than one line - we edit one string, so ensure we don't select several lines */
++      if (selStart >=0 && selEnd >= 0 && selStart === selEnd && this.editor.isRowExpanded(selStart)) {    
++        var editLine = this.editor.getLine(selStart);
++	var editMatch = editLine.match(/^([ \t]*)("[a-zA-Z0-9_]*": )?(".*",?[ \t]*)$/);
++	if (editMatch) {
++          return editMatch;
++	} else {
++          return null;
++	}
++      } else {
++        return null;
++      }
++    }, 
++
++    showHideEditDocString: function (event) {
++      this.$("button.string-edit").attr("disabled", "true");
++      if (!this.hasValidCode()) {
++        return false;
++      }
++      var editMatch = this.determineStringEditMatch(event);
++      if (editMatch) {
++        this.$("button.string-edit").removeAttr("disabled");
++	/* remove the following line (along with CSS) to go back to the toolbar */
++        this.$("button.string-edit").css("top", (this.$("#editor-container")[0].offsetTop - 2 + this.editor.getRowHeight() * this.editor.documentToScreenRow(this.editor.getSelectionStart().row)) + "px");
++        return true;
++      }
++      return false;
++    },
++
++    stringEditing: function(event) {
++      event.preventDefault();   
++      if (!this.hasValidCode()) {
++        return;
++      }
++      var editMatch = this.determineStringEditMatch(event);
++      if (editMatch) {
++        var indent = editMatch[1] || "",
++              hashKey = editMatch[2] || "",
++              editText = editMatch[3],
++              comma = "";
++        if (editText.substring(editText.length - 1) === ",") {
++          editText = editText.substring(0, editText.length - 1); 
++          comma = ",";
++        }
++        this.stringEditModal.openWin(this.editor, indent, hashKey, editText, comma);
++      }
++    },
++
+     destroy: function(event) {
+       if (this.model.isNewDoc()) {
+         FauxtonAPI.addNotification({
+           msg: 'This document has not been saved yet.',
+           type: 'warning',
+           clear:  true
+         });
+         return;
+       }
+ 
+       if (!window.confirm("Are you sure you want to delete this doc?")) {
+         return false;
+       }
+ 
+       var database = this.model.database;
+ 
+       this.model.destroy().then(function(resp) {
+         FauxtonAPI.addNotification({
+           msg: "Succesfully deleted your doc",
+           clear:  true
+         });
+         FauxtonAPI.navigate(database.url("index"));
+       }, function(resp) {
+         FauxtonAPI.addNotification({
+           msg: "Failed to delete your doc!",
+           type: "error",
+           clear:  true
+         });
+       });
+     },
+ 
+     beforeRender: function () {
+       this.uploadModal = this.setView('#upload-modal', new Views.UploadModal({model: this.model}));
+       this.uploadModal.render();
+ 
+       this.duplicateModal = this.setView('#duplicate-modal', new Views.DuplicateDocModal({model: this.model}));
++
++      /* initialization is automatic - and make sure ONCE */
++      this.stringEditModal = this.stringEditModal || this.setView('#string-edit-modal', new Views.StringEditModal());
++      /* this.stringEditModal.render(); */
+       this.duplicateModal.render();
+     },
+ 
+     upload: function (event) {
+       event.preventDefault();
+       if (this.model.isNewDoc()) {
+         FauxtonAPI.addNotification({
+           msg: 'Please save the document before uploading an attachment.',
+           type: 'warning',
+           clear:  true
+         });
+         return;
+       }
+       this.uploadModal.showModal();
+     },
+ 
+     duplicate: function(event) {
+       if (this.model.isNewDoc()) {
+         FauxtonAPI.addNotification({
+           msg: 'Please save the document before duplicating it.',
+           type: 'warning',
+           clear:  true
+         });
+         return;
+       }
+       event.preventDefault();
+       this.duplicateModal.showModal();
+     },
+ 
+     updateValues: function() {
+       if (this.model.changedAttributes()) {
+         FauxtonAPI.addNotification({
+           msg: "Document saved successfully.",
+           type: "success",
+           clear: true
+         });
+         this.editor.setValue(this.model.prettyJSON());
+       }
+     },
+ 
+     establish: function() {
+       var promise = this.model.fetch(),
+           databaseId = this.database.safeID(),
+           deferred = $.Deferred(),
+           that = this;
+ 
+       promise.then(function () {
+         deferred.resolve();
+       }, function (xhr, reason, msg) {
+         if (xhr.status === 404) {
+           FauxtonAPI.addNotification({
+             msg: 'The document does not exist',
+             type: 'error',
+             clear: true
+           });
+           that.goback();
+         }
+         deferred.reject();
+      });
+ 
+       return deferred;
+     },
+ 
+     saveDoc: function(event) {
+       var json,
+       that = this,
+       editor = this.editor,
+       validDoc = this.getDocFromEditor();
+ 
+       if (validDoc) {
+         this.getDocFromEditor();
+ 
+         FauxtonAPI.addNotification({msg: "Saving document."});
+ 
+         this.model.save().then(function () {
+           editor.editSaved();
+           FauxtonAPI.navigate('/database/' + that.database.safeID() + '/' + that.model.id);
+         }).fail(function(xhr) {
+           var responseText = JSON.parse(xhr.responseText).reason;
+           FauxtonAPI.addNotification({
+             msg: "Save failed: " + responseText,
+             type: "error",
+             fade: false,
+             clear: true,
+             selector: "#doc .errors-container"
+           });
+         });
+       } else if(this.model.validationError && this.model.validationError === 'Cannot change a documents id.') {
+           FauxtonAPI.addNotification({
+             msg: "Cannot save: " + 'Cannot change a documents _id, try Duplicate doc instead!',
+             type: "error",
+             selector: "#doc .errors-container",
+             clear:  true
+           });
+         delete this.model.validationError;
+       } else {
+         FauxtonAPI.addNotification({
+           msg: "Please fix the JSON errors and try again.",
+           type: "error",
+           selector: "#doc .errors-container",
+           clear:  true
+         });
+       }
+     },
+ 
+     getDocFromEditor: function () {
+       var json;
+ 
+       if (!this.hasValidCode()) {
+         return false;
+       }
+ 
+       json = JSON.parse(this.editor.getValue());
+ 
+       this.model.clear().set(json, {validate: true});
+       if (this.model.validationError) {
+         return false;
+       }
+ 
+       return this.model;
+     },
+ 
+     hasValidCode: function() {
+       var errors = this.editor.getAnnotations();
+       return errors.length === 0;
+     },
+ 
+     serialize: function() {
+       return {
+         doc: this.model,
+         attachments: this.getAttachments()
+       };
+     },
+ 
+     getAttachments: function () {
+       var attachments = this.model.get('_attachments');
+ 
+       if (!attachments) { return false; }
+ 
+       return _.map(attachments, function (att, key) {
+         return {
+           fileName: key,
+           size: att.length,
+           contentType: att.content_type,
+           url: this.model.url() + '/' + app.utils.safeURLName(key)
+         };
+       }, this);
+     },
+ 
+     afterRender: function() {
+       var saveDoc = this.saveDoc,
+           editor,
+           model;
+ 
+       this.editor = new Components.Editor({
+         editorId: "editor-container",
+         forceMissingId: true,
+         commands: [{
+           name: 'save',
+           bindKey: {win: 'Ctrl-S',  mac: 'Ctrl-S'},
+           exec: function(editor) {
+             saveDoc();
+           },
+           readOnly: true // false if this command should not apply in readOnly mode
+         }]
+       });
+       this.editor.render();
+ 
+       editor = this.editor;
+       model = this.model;
+ 
+       this.listenTo(this.model, "sync", this.updateValues);
+       this.listenTo(editor.editor, "change", function (event) {
+         var changedDoc;
+         try {
+           changedDoc = JSON.parse(editor.getValue());
+         } catch(exception) {
+           //not complete doc. Cannot work with it
+           return;
+         }
+ 
+         var keyChecked = ["_id"];
+         if (model.get("_rev")) { keyChecked.push("_rev");}
+ 
+         //check the changedDoc has all the required standard keys
+         if (_.isEmpty(_.difference(keyChecked, _.keys(changedDoc)))) { return; }
+ 
+         editor.setReadOnly(true);
+         setTimeout(function () { editor.setReadOnly(false);}, 400);
+         // use extend so that _id stays at the top of the object with displaying the doc
+         changedDoc = _.extend({_id: model.id, _rev: model.get("_rev")}, changedDoc);
+         editor.setValue(JSON.stringify(changedDoc, null, "  "));
+         FauxtonAPI.addNotification({
+           type: "error",
+           msg: "Cannot remove a documents Id or Revision.",
+           clear:  true
+         });
+       });
++
++      var that = this;
++      this.listenTo(editor.editor, "changeSelection", function (event) {
++        that.showHideEditDocString(event);
++      });
++      this.listenTo(editor.editor.session, "changeBackMarker", function (event) {
++        that.showHideEditDocString(event);
++      });
+     },
+ 
+     cleanup: function () {
+       if (this.editor) this.editor.remove();
+     }
+   });
+ 
+   return Views;
+ });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/12f282c4/app/addons/fauxton/components.js
----------------------------------------------------------------------
diff --cc app/addons/fauxton/components.js
index f0dcc31,85f7b34..fc0f500
--- a/app/addons/fauxton/components.js
+++ b/app/addons/fauxton/components.js
@@@ -419,9 -419,8 +419,11 @@@ function(app, FauxtonAPI, ace, spin) 
        this.setHeightToLineCount();
  
        this.editor.setTheme("ace/theme/" + this.theme);
+ 
 -      this.editor.getSession().setMode("ace/mode/" + this.mode);
 +      if (this.mode != "plain") {
 +        this.editor.getSession().setMode("ace/mode/" + this.mode);
 +      }
++      
        this.editor.setShowPrintMargin(false);
        this.addCommands();