couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From deathb...@apache.org
Subject fauxton commit: updated refs/heads/master to 8149799
Date Wed, 23 Jul 2014 13:57:04 GMT
Repository: couchdb-fauxton
Updated Branches:
  refs/heads/master 4e371855a -> 81497990c


Pulled views out into their own files


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

Branch: refs/heads/master
Commit: 81497990cdec0fbb3d867d3271e416447cbd5fd5
Parents: 4e37185
Author: deathbearbrown <deathbearbrown@gmail.com>
Authored: Wed Jul 23 09:47:32 2014 -0400
Committer: deathbearbrown <deathbearbrown@gmail.com>
Committed: Wed Jul 23 09:47:32 2014 -0400

----------------------------------------------------------------------
 app/addons/documents/changesviews.js     |   84 ++
 app/addons/documents/doceditorviews.js   |  416 ++++++++
 app/addons/documents/indexviews.js       |  574 +++++++++++
 app/addons/documents/queryoptionviews.js |  270 ++++++
 app/addons/documents/routes.js           |   27 +-
 app/addons/documents/views.js            | 1290 +------------------------
 6 files changed, 1378 insertions(+), 1283 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/81497990/app/addons/documents/changesviews.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/changesviews.js b/app/addons/documents/changesviews.js
new file mode 100644
index 0000000..2f91c21
--- /dev/null
+++ b/app/addons/documents/changesviews.js
@@ -0,0 +1,84 @@
+// 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",
+       // Libs
+       "addons/fauxton/resizeColumns",
+
+       // Plugins
+       "plugins/prettify",
+       // this should never be global available:
+       // https://github.com/zeroclipboard/zeroclipboard/blob/master/docs/security.md
+       "plugins/zeroclipboard/ZeroClipboard"
+],
+
+function(app, FauxtonAPI, resizeColumns,  prettify, ZeroClipboard) {
+
+  var Views = {};
+
+  Views.Changes = FauxtonAPI.View.extend({
+    template: "addons/documents/templates/changes",
+
+    initialize: function () {
+      this.listenTo( this.model.changes, 'sync', this.render);
+      this.listenTo( this.model.changes, 'cachesync', this.render);
+    },
+
+    events: {
+      "click button.js-toggle-json": "toggleJson"
+    },
+
+    toggleJson: function(event) {
+      event.preventDefault();
+
+      var $button = this.$(event.target),
+          $container = $button.closest('.change-box').find(".js-json-container");
+
+      if (!$container.is(":visible")) {
+        $button
+          .text("Close JSON")
+          .addClass("btn-secondary")
+          .removeClass("btn-primary");
+      } else {
+        $button.text("View JSON")
+          .addClass("btn-primary")
+          .removeClass("btn-secondary");
+      }
+
+      $container.slideToggle();
+    },
+
+    establish: function() {
+      return [ this.model.changes.fetchOnce({prefill: true})];
+    },
+
+    serialize: function () {
+      return {
+        changes: this.model.changes.toJSON(),
+        database: this.model
+      };
+    },
+
+    afterRender: function(){
+      prettyPrint();
+      ZeroClipboard.config({ moviePath: "/assets/js/plugins/zeroclipboard/ZeroClipboard.swf" });
+      var client = new ZeroClipboard(this.$(".js-copy"));
+    }
+  });
+
+
+
+  return Views;
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/81497990/app/addons/documents/doceditorviews.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/doceditorviews.js b/app/addons/documents/doceditorviews.js
new file mode 100644
index 0000000..add8d8c
--- /dev/null
+++ b/app/addons/documents/doceditorviews.js
@@ -0,0 +1,416 @@
+// 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');
+    }
+  });
+
+
+
+  /* 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"
+    },
+
+    disableLoader: true,
+
+    initialize: function (options) {
+      this.database = options.database;
+      _.bindAll(this);
+    },
+
+    goback: function(){
+      FauxtonAPI.navigate(this.database.url("index") + "?limit=100");
+    },
+
+    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}));
+      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
+        });
+      });
+    },
+
+    cleanup: function () {
+      if (this.editor) this.editor.remove();
+    }
+  });
+
+  return Views;
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/81497990/app/addons/documents/indexviews.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/indexviews.js b/app/addons/documents/indexviews.js
new file mode 100644
index 0000000..df8c10d
--- /dev/null
+++ b/app/addons/documents/indexviews.js
@@ -0,0 +1,574 @@
+// 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",
+  "addons/pouchdb/base",
+  //views
+  "addons/documents/queryoptionviews",
+  // Libs
+  "addons/fauxton/resizeColumns",
+
+  // Plugins
+  "plugins/beautify",
+  "plugins/prettify"
+],
+
+function(app, FauxtonAPI, Components, Documents, Databases, pouchdb,
+         QueryOptions, resizeColumns, beautify, prettify) {
+
+  var Views = {};
+
+  Views.ViewEditor = FauxtonAPI.View.extend({
+    template: "addons/documents/templates/view_editor",
+    builtinReduces: ['_sum', '_count', '_stats'],
+
+    events: {
+      "click button.save": "saveView",
+      "click button.delete": "deleteView",
+      "change select#reduce-function-selector": "updateReduce",
+      "click button.preview": "previewView",
+      "click #db-views-tabs-nav": 'toggleIndexNav',
+      "click .beautify_map":  "beautifyCode",
+      "click .beautify_reduce":  "beautifyCode",
+      "click #query-options-wrapper": 'toggleIndexNav'
+    },
+
+    langTemplates: {
+      "javascript": {
+        map: "function(doc) {\n  emit(doc._id, 1);\n}",
+        reduce: "function(keys, values, rereduce){\n  if (rereduce){\n    return sum(values);\n  } else {\n    return values.length;\n  }\n}"
+      }
+    },
+
+    defaultLang: "javascript",
+
+    initialize: function(options) {
+      this.newView = options.newView || false;
+      this.ddocs = options.ddocs;
+      this.params = options.params;
+      this.database = options.database;
+      this.currentDdoc = options.currentddoc;
+      if (this.newView) {
+        this.viewName = 'newView';
+      } else {
+        this.ddocID = options.ddocInfo.id;
+        this.viewName = options.viewName;
+        this.ddocInfo = new Documents.DdocInfo({_id: this.ddocID},{database: this.database});
+      }
+
+      this.showIndex = false;
+      _.bindAll(this);
+    },
+
+    establish: function () {
+      if (this.ddocInfo) {
+        return this.ddocInfo.fetch();
+      }
+    },
+
+    updateValues: function() {
+      var notification;
+      if (this.model.changedAttributes()) {
+        notification = FauxtonAPI.addNotification({
+          msg: "Document saved successfully.",
+          type: "success",
+          clear: true
+        });
+        this.editor.setValue(this.model.prettyJSON());
+      }
+    },
+
+    updateReduce: function(event) {
+      var $ele = $("#reduce-function-selector");
+      var $reduceContainer = $(".control-group.reduce-function");
+      if ($ele.val() == "CUSTOM") {
+        this.createReduceEditor();
+        this.reduceEditor.setValue(this.langTemplates.javascript.reduce);
+        $reduceContainer.show();
+      } else {
+        $reduceContainer.hide();
+      }
+    },
+
+    deleteView: function (event) {
+      event.preventDefault();
+
+      if (this.newView) { return alert('Cannot delete a new view.'); }
+      if (!confirm('Are you sure you want to delete this view?')) {return;}
+
+      var that = this,
+          promise,
+          viewName = this.$('#index-name').val(),
+          ddocName = this.$('#ddoc :selected').val(),
+          ddoc = this.getCurrentDesignDoc();
+
+      ddoc.removeDdocView(viewName);
+
+      if (ddoc.hasViews()) {
+        promise = ddoc.save();
+      } else {
+        promise = ddoc.destroy();
+      }
+
+      promise.then(function () {
+        FauxtonAPI.navigate('/database/' + that.database.safeID() + '/_all_docs?limit=' + Databases.DocLimit);
+        FauxtonAPI.triggerRouteEvent('reloadDesignDocs');
+      });
+    },
+
+    saveView: function(event) {
+      var json, notification,
+      that = this;
+
+      if (event) { event.preventDefault();}
+
+      $('#dashboard-content').scrollTop(0); //scroll up
+
+      if (this.hasValidCode() && this.$('#new-ddoc:visible').val() !=="") {
+        var mapVal = this.mapEditor.getValue(),
+        reduceVal = this.reduceVal(),
+        viewName = this.$('#index-name').val(),
+        ddoc = this.getCurrentDesignDoc(),
+        ddocName = ddoc.id,
+        viewNameChange = false;
+
+        if (this.viewName !== viewName) {
+          ddoc.removeDdocView(this.viewName);
+          this.viewName = viewName;
+          viewNameChange = true;
+        }
+
+        notification = FauxtonAPI.addNotification({
+          msg: "Saving document.",
+          selector: "#define-view .errors-container",
+          clear: true
+        });
+
+        ddoc.setDdocView(viewName, mapVal, reduceVal);
+
+        ddoc.save().then(function () {
+          that.ddocs.add(ddoc);
+
+          that.mapEditor.editSaved();
+          that.reduceEditor && that.reduceEditor.editSaved();
+
+
+          FauxtonAPI.addNotification({
+            msg: "View has been saved.",
+            type: "success",
+            selector: "#define-view .errors-container",
+            clear: true
+          });
+
+          if (that.newView || viewNameChange) {
+            var fragment = '/database/' + that.database.safeID() +'/' + ddoc.safeID() + '/_view/' + app.utils.safeURLName(viewName);
+
+            FauxtonAPI.navigate(fragment, {trigger: false});
+            that.newView = false;
+            that.ddocID = ddoc.safeID();
+            that.viewName = viewName;
+            that.ddocInfo = ddoc;
+            that.showIndex = true;
+            that.render();
+            FauxtonAPI.triggerRouteEvent('reloadDesignDocs', {
+              selectedTab: app.utils.removeSpecialCharacters(ddocName.replace(/_design\//,'')) + '_' + app.utils.removeSpecialCharacters(viewName)
+            });
+          }
+
+          if (that.reduceFunStr !== reduceVal) {
+            that.reduceFunStr = reduceVal;
+            that.advancedOptions.renderOnUpdatehasReduce(that.hasReduce());
+          }
+
+          FauxtonAPI.triggerRouteEvent('updateAllDocs', {ddoc: ddocName, view: viewName});
+
+        }, function(xhr) {
+          var responseText = JSON.parse(xhr.responseText).reason;
+          notification = FauxtonAPI.addNotification({
+            msg: "Save failed: " + responseText,
+            type: "error",
+            clear: true
+          });
+        });
+      } else {
+        var errormessage = (this.$('#new-ddoc:visible').val() ==="")?"Enter a design doc name":"Please fix the Javascript errors and try again.";
+        notification = FauxtonAPI.addNotification({
+          msg: errormessage,
+          type: "error",
+          selector: "#define-view .errors-container",
+          clear: true
+        });
+      }
+    },
+
+    updateView: function(event, paramInfo) {
+       event.preventDefault();
+
+       if (this.newView) { return alert('Please save this new view before querying it.'); }
+
+       var errorParams = paramInfo.errorParams,
+           params = paramInfo.params;
+
+       if (_.any(errorParams)) {
+         _.map(errorParams, function(param) {
+
+           // TODO: Where to add this error?
+           // bootstrap wants the error on a control-group div, but we're not using that
+           //$('form.view-query-update input[name='+param+'], form.view-query-update select[name='+param+']').addClass('error');
+           return FauxtonAPI.addNotification({
+             msg: "JSON Parse Error on field: "+param.name,
+             type: "error",
+             selector: ".advanced-options .errors-container",
+             clear: true
+           });
+         });
+         FauxtonAPI.addNotification({
+           msg: "Make sure that strings are properly quoted and any other values are valid JSON structures",
+           type: "warning",
+           selector: ".advanced-options .errors-container",
+           clear: true
+         });
+
+         return false;
+      }
+
+       var fragment = window.location.hash.replace(/\?.*$/, '');
+       if (!_.isEmpty(params)) {
+        fragment = fragment + '?' + $.param(params);
+       }
+
+       FauxtonAPI.navigate(fragment, {trigger: false});
+       FauxtonAPI.triggerRouteEvent('updateAllDocs', {ddoc: this.ddocID, view: this.viewName});
+    },
+
+
+    previewView: function(event, paramsInfo) {
+      event.preventDefault();
+      var that = this,
+      mapVal = this.mapVal(),
+      reduceVal = this.reduceVal(),
+      paramsArr = [];
+
+      if (paramsInfo && paramsInfo.params) {
+        paramsArr = paramsInfo.params;
+      }
+
+      var params = _.reduce(paramsArr, function (params, param) {
+        params[param.name] = param.value;
+        return params;
+      }, {reduce: false});
+
+      FauxtonAPI.addNotification({
+        msg: "<strong>Warning!</strong> Preview executes the Map/Reduce functions in your browser, and may behave differently from CouchDB.",
+        type: "warning",
+        selector: ".advanced-options .errors-container",
+        fade: true,
+        escape: false // beware of possible XSS when the message changes
+      });
+
+      var promise = FauxtonAPI.Deferred();
+
+      if (!this.database.allDocs || this.database.allDocs.params.include_docs !== true) {
+        this.database.buildAllDocs({limit: Databases.DocLimit.toString(), include_docs: true});
+        promise = this.database.allDocs.fetch();
+       } else {
+        promise.resolve();
+       }
+
+      promise.then(function () {
+        params.docs = that.database.allDocs.map(function (model) { return model.get('doc');});
+        var queryPromise = pouchdb.runViewQuery({map: mapVal, reduce: reduceVal}, params);
+        queryPromise.then(function (results) {
+          FauxtonAPI.triggerRouteEvent('updatePreviewDocs', {rows: results.rows, ddoc: that.getCurrentDesignDoc().id, view: that.viewName});
+        });
+      });
+    },
+
+    getCurrentDesignDoc: function () {
+      return this.designDocSelector.getCurrentDesignDoc();
+    },
+
+    isCustomReduceEnabled: function() {
+      return $("#reduce-function-selector").val() == "CUSTOM";
+    },
+
+    mapVal: function () {
+      if (this.mapEditor) {
+        return this.mapEditor.getValue();
+      }
+
+      return this.$('#map-function').text();
+    },
+
+    reduceVal: function() {
+      var reduceOption = this.$('#reduce-function-selector :selected').val(),
+      reduceVal = "";
+
+      if (reduceOption === 'CUSTOM') {
+        if (!this.reduceEditor) { this.createReduceEditor(); }
+        reduceVal = this.reduceEditor.getValue();
+      } else if ( reduceOption !== 'NONE') {
+        reduceVal = reduceOption;
+      }
+
+      return reduceVal;
+    },
+
+
+    hasValidCode: function() {
+      return _.every(["mapEditor", "reduceEditor"], function(editorName) {
+        var editor = this[editorName];
+        if (editorName === "reduceEditor" && ! this.isCustomReduceEnabled()) {
+          return true;
+        }
+        return editor.hadValidCode();
+      }, this);
+    },
+
+    toggleIndexNav: function (event) {
+      $('#dashboard-content').scrollTop(0); //scroll up
+
+      var $targetId = this.$(event.target).attr('id'),
+          $previousTab = this.$(this.$('li.active a').attr('href')),
+          $targetTab = this.$(this.$(event.target).attr('href'));
+
+      if ($targetTab.attr('id') !== $previousTab.attr('id')) {
+        $previousTab.removeAttr('style');
+      }
+
+      if ($targetId === 'index-nav') {
+        if (this.newView) { return; }
+        var that = this;
+        $('#dashboard-content').scrollTop(0); //scroll up
+        $targetTab.toggle('slow', function(){
+           that.showEditors();
+        });
+      } else {
+        $targetTab.toggle('slow');
+      }
+    },
+
+    serialize: function() {
+      return {
+        ddocs: this.ddocs,
+        ddoc: this.model,
+        ddocName: this.model.id,
+        viewName: this.viewName,
+        reduceFunStr: this.reduceFunStr,
+        isCustomReduce: this.hasCustomReduce(),
+        newView: this.newView,
+        langTemplates: this.langTemplates.javascript
+      };
+    },
+
+    hasCustomReduce: function() {
+      return this.reduceFunStr && ! _.contains(this.builtinReduces, this.reduceFunStr);
+    },
+
+    hasReduce: function () {
+      return this.reduceFunStr || false;
+    },
+
+    createReduceEditor: function () {
+      if (this.reduceEditor) {
+        this.reduceEditor.remove();
+      }
+
+      this.reduceEditor = new Components.Editor({
+        editorId: "reduce-function",
+        mode: "javascript",
+        couchJSHINT: true
+      });
+      this.reduceEditor.render();
+
+      if (this.reduceEditor.getLines() === 1){
+        this.$('.beautify_reduce').removeClass("hide");
+        $('.beautify-tooltip').tooltip();
+      }
+    },
+    beforeRender: function () {
+
+      if (this.newView) {
+        this.reduceFunStr = '';
+        if (this.ddocs.length === 0) {
+          this.model = new Documents.Doc(null, {database: this.database});
+        } else {
+          this.model = this.ddocs.first().dDocModel();
+        }
+        this.ddocID = this.model.id;
+      } else {
+        var ddocDecode = decodeURIComponent(this.ddocID);
+        this.model = this.ddocs.get(this.ddocID).dDocModel();
+        this.reduceFunStr = this.model.viewHasReduce(this.viewName);
+      }
+
+      var viewFilters = FauxtonAPI.getExtensions('sidebar:viewFilters'),
+          filteredModels = this.ddocs.models,
+          designDocs = this.ddocs.clone();
+
+      if (!_.isEmpty(viewFilters)) {
+        _.each(viewFilters, function (filter) {
+          filteredModels = _.filter(filteredModels, filter);
+        });
+        designDocs.reset(filteredModels, {silent: true});
+      }
+
+      this.designDocSelector = this.setView('.design-doc-group', new Views.DesignDocSelector({
+        collection: designDocs,
+        ddocName: this.currentDdoc || this.model.id,
+        database: this.database
+      }));
+
+      if (!this.newView) {
+        this.eventer = _.extend({}, Backbone.Events);
+
+        this.advancedOptions = this.insertView('#query', new QueryOptions.AdvancedOptions({
+          updateViewFn: this.updateView,
+          previewFn: this.previewView,
+          database: this.database,
+          viewName: this.viewName,
+          ddocName: this.model.id,
+          hasReduce: this.hasReduce(),
+          eventer: this.eventer,
+          showStale: true
+        }));
+      }
+
+    },
+
+    afterRender: function() {
+
+      if (this.params && !this.newView) {
+        this.advancedOptions.updateFromParams(this.params);
+      }
+
+      this.designDocSelector.updateDesignDoc();
+      if (this.newView || this.showIndex) {
+        this.showEditors();
+        this.showIndex = false;
+      } else {
+        this.$('#index').hide();
+        this.$('#index-nav').parent().removeClass('active');
+      }
+
+    },
+
+    showEditors: function () {
+      this.mapEditor = new Components.Editor({
+        editorId: "map-function",
+        mode: "javascript",
+        couchJSHINT: true
+      });
+      this.mapEditor.render();
+
+      if (this.hasCustomReduce()) {
+        this.createReduceEditor();
+      } else {
+        $(".control-group.reduce-function").hide();
+      }
+
+      if (this.newView) {
+        this.mapEditor.setValue(this.langTemplates[this.defaultLang].map);
+        //Use a built in view by default
+        //this.reduceEditor.setValue(this.langTemplates[this.defaultLang].reduce);
+      }
+
+      this.mapEditor.editSaved();
+      this.reduceEditor && this.reduceEditor.editSaved();
+
+      if (this.mapEditor.getLines() === 1){
+        this.$('.beautify_map').removeClass("hide");
+        $('.beautify-tooltip').tooltip();
+      }
+    },
+    beautifyCode: function(e){
+      e.preventDefault();
+      var targetEditor = $(e.currentTarget).hasClass('beautify_reduce')?this.reduceEditor:this.mapEditor;
+      var beautifiedCode = beautify(targetEditor.getValue());
+      targetEditor.setValue(beautifiedCode);
+    },
+    cleanup: function () {
+      this.mapEditor && this.mapEditor.remove();
+      this.reduceEditor && this.reduceEditor.remove();
+    }
+  });
+
+  Views.DesignDocSelector = FauxtonAPI.View.extend({
+    template: "addons/documents/templates/design_doc_selector",
+
+    events: {
+      "change select#ddoc": "updateDesignDoc"
+    },
+
+    initialize: function (options) {
+      this.ddocName = options.ddocName;
+      this.database = options.database;
+      this.listenTo(this.collection, 'add', this.ddocAdded);
+      this.DocModel = options.DocModel || Documents.Doc;
+    },
+
+    ddocAdded: function (ddoc) {
+      this.ddocName = ddoc.id;
+      this.render();
+    },
+
+    serialize: function () {
+      return {
+        ddocName: this.ddocName,
+        ddocs: this.collection
+      };
+    },
+
+    updateDesignDoc: function () {
+      if (this.newDesignDoc()) {
+        this.$('#new-ddoc-section').show();
+      } else {
+        this.$('#new-ddoc-section').hide();
+      }
+    },
+
+    newDesignDoc: function () {
+
+      return this.$('#ddoc').val() === 'new-doc';
+    },
+
+    newDocValidation: function(){
+      return this.newDesignDoc() && this.$('#new-ddoc').val()==="";
+    },
+    getCurrentDesignDoc: function () {
+      if (this.newDesignDoc()) {
+        var doc = {
+          _id: '_design/' + this.$('#new-ddoc').val(),
+          views: {},
+          language: "javascript"
+        };
+        var ddoc = new this.DocModel(doc, {database: this.database});
+        //this.collection.add(ddoc);
+        return ddoc;
+      } else if ( !this.newDesignDoc() ) {
+        var ddocName = this.$('#ddoc').val();
+        return this.collection.find(function (ddoc) {
+          return ddoc.id === ddocName;
+        }).dDocModel();
+      }
+    }
+  });
+
+  return Views;
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/81497990/app/addons/documents/queryoptionviews.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/queryoptionviews.js b/app/addons/documents/queryoptionviews.js
new file mode 100644
index 0000000..b2e1af5
--- /dev/null
+++ b/app/addons/documents/queryoptionviews.js
@@ -0,0 +1,270 @@
+// 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",
+       // Libs
+       "addons/fauxton/resizeColumns",
+],
+
+function(app, FauxtonAPI, resizeColumns ) {
+
+  var Views = {};
+
+  Views.AdvancedOptions = FauxtonAPI.View.extend({
+    template: "addons/documents/templates/advanced_options",
+    className: "advanced-options well",
+
+    initialize: function (options) {
+      this.database = options.database;
+      this.ddocName = options.ddocName;
+      this.viewName = options.viewName;
+      this.updateViewFn = options.updateViewFn;
+      this.previewFn = options.previewFn;
+      this.showStale = _.isUndefined(options.showStale) ? false : options.showStale;
+      this.hasReduce = _.isUndefined(options.hasReduce) ? true : options.hasReduce;
+    },
+
+    events: {
+      "change form.js-view-query-update input": "updateFilters",
+      "change form.js-view-query-update select": "updateFilters",
+      "submit form.js-view-query-update": "updateView",
+      "click .toggle-btns > label":  "toggleQuery"
+    },
+
+    toggleQuery: function(e){
+      e.preventDefault();
+
+      if (this.$(e.currentTarget).hasClass("active")){
+        this.$('.js-query-keys-wrapper').addClass("hide");
+        this.$(".toggle-btns > label").removeClass('active');
+        this.$('.js-query-keys-wrapper').find("input,textarea").attr("disabled","true");
+      } else {
+        this.$('.js-query-keys-wrapper').removeClass("hide");
+        var showFunctionName =this.$(e.currentTarget).attr("for");
+        //highlight current
+        this.$(".toggle-btns > label").removeClass('active');
+        this.$(e.currentTarget).addClass("active");
+        this.$("[id^='js-show']").hide();
+        //show section & disable what needs to be disabled
+        this[showFunctionName]();
+      }
+    },
+
+    showKeys: function(){
+      this.$("#js-showKeys, .js-disabled-message").show();
+      this.$('[name="startkey"],[name="endkey"],[name="inclusive_end"]').attr("disabled","true");
+      this.$('[name="keys"]').removeAttr("disabled");
+    },
+
+    showStartEnd: function(){
+      this.$("#js-showStartEnd").show();
+      this.$('[name="startkey"],[name="endkey"],[name="inclusive_end"]').removeAttr("disabled");
+      this.$('.js-disabled-message').hide();
+      this.$('[name="keys"]').attr("disabled","true");
+    },
+
+    beforeRender: function () {
+      if (this.viewName && this.ddocName) {
+        var buttonViews = FauxtonAPI.getExtensions('advancedOptions:ViewButton');
+        _.each(buttonViews, function (view) {
+          this.insertView('#button-options', view);
+          view.update(this.database, this.ddocName, this.viewName);
+        }, this);
+      }
+    },
+
+    renderOnUpdatehasReduce: function (hasReduce) {
+      this.hasReduce = hasReduce;
+      this.render();
+    },
+
+    parseJSON: function (value) {
+      try {
+        return JSON.parse(value);
+      } catch(e) {
+        return undefined;
+      }
+    },
+
+    validateKeys:  function(param){
+      var errorMsg = false,
+          parsedValue = this.parseJSON(param.value);
+
+      if (_.isUndefined(parsedValue)) {
+        errorMsg = "Keys must be valid json.";
+      } else if (!_.isArray(parsedValue)) {
+        errorMsg =  "Keys values must be in an array. E.g [1,2,3]";
+      }
+
+      if (errorMsg) {
+        this.$('.js-keys-error').empty();
+        FauxtonAPI.addNotification({
+          type: "error",
+          msg: errorMsg,
+          clear:  false,
+          selector: '.advanced-options .errors-container'
+        });
+        return false;
+      }
+
+      return true;
+    },
+    validateFields: function(params){
+      var errors = false;
+      //so ghetto. Spaghetti code.
+      for (var i= 0; i <params.length; i++){
+        if (params[i].name === "skip"){
+          if (!(/^\d+$/).test(params[i].value)){
+            FauxtonAPI.addNotification({
+              msg: "Numbers only for skip",
+              type: "warn",
+              selector: ".advanced-options .errors-container",
+              clear:  true
+            });
+            errors = true;
+          }
+        }
+      }
+      return errors;
+    },
+    queryParams: function () {
+      var $form = this.$(".js-view-query-update"),
+          keysParam = false;
+
+      var params = _.reduce($form.serializeArray(), function(params, param) {
+        if (!param.value) { return params; }
+        if (param.name === "limit" && param.value === 'None') { return params; }
+        if (param.name === "keys") { keysParam = param; }
+        params.push(param);
+        return params;
+      }, []);
+
+
+      if (keysParam && !this.validateKeys(keysParam)) { return false; }
+
+      if (params && this.validateFields(params)){ return false; }
+
+      // Validate *key* params to ensure they're valid JSON
+      var keyParams = ["keys","startkey","endkey"];
+      var errorParams = _.filter(params, function(param) {
+        if (_.contains(keyParams, param.name) && _.isUndefined(this.parseJSON(param.value))) {
+            return true;
+          }
+
+          return false;
+      }, this);
+
+      return {params: params, errorParams: errorParams};
+    },
+
+    updateView: function (event) {
+      event.preventDefault();
+      var params = this.queryParams();
+      if (!params) { return;}
+      this.updateViewFn(event, params);
+    },
+
+    updateFilters: function(event) {
+      event.preventDefault();
+      var $ele = $(event.currentTarget);
+      var name = $ele.attr('name');
+      this.updateFiltersFor(name, $ele);
+    },
+
+    updateFiltersFor: function(name, $ele) {
+      var $form = $ele.parents("form.js-view-query-update:first");
+      switch (name) {
+        // Reduce constraints
+        //   - Can't include_docs for reduce=true
+        //   - can't include group_level for reduce=false
+        case "reduce":
+          if ($ele.prop('checked') === true) {
+          if ($form.find("input[name=include_docs]").prop("checked") === true) {
+            $form.find("input[name=include_docs]").prop("checked", false);
+            var notification = FauxtonAPI.addNotification({
+              msg: "include_docs has been disabled as you cannot include docs on a reduced view",
+              type: "warn",
+              selector: ".advanced-options .errors-container",
+              clear:  true
+            });
+          }
+          $form.find("input[name=include_docs]").prop("disabled", true);
+          $form.find("select[name=group_level]").prop("disabled", false);
+        } else {
+          $form.find("select[name=group_level]").val("999").prop("disabled", true);
+          $form.find("input[name=include_docs]").prop("disabled", false);
+        }
+        break;
+        case "skip":
+          if (!(/^\d+$/).test($ele.val())){
+            FauxtonAPI.addNotification({
+              msg: "Numbers only for skip",
+              type: "warn",
+              selector: ".advanced-options .errors-container",
+              clear:  true
+            });
+          }
+        break;
+        case "include_docs":
+        break;
+      }
+    },
+
+    updateFromParams: function (params) {
+      var $form = this.$el.find("form.js-view-query-update");
+      _.each(params, function(val, key) {
+        var $ele;
+        switch (key) {
+          case "limit":
+          case "descending":
+          case "group_level":
+            if (!val) { return; }
+            $form.find("select[name='"+key+"']").val(val);
+          break;
+          case "include_docs":
+            case "stale":
+            case "inclusive_end":
+            $form.find("input[name='"+key+"']").prop('checked', true);
+          break;
+          case "reduce":
+            $ele = $form.find("input[name='"+key+"']");
+          if (val == "true") {
+            $ele.prop('checked', true);
+          }
+          this.updateFiltersFor(key, $ele);
+          break;
+          case "key":
+          case "keys":
+            $form.find("textarea[name='"+key+"']").val(val);
+          break;
+          default:
+            $form.find("input[name='"+key+"']").val(val);
+          break;
+        }
+      }, this);
+    },
+
+    serialize: function () {
+      return {
+        hasReduce: this.hasReduce,
+        showPreview: false,
+        showStale: this.showStale
+      };
+    }
+  });
+
+
+  return Views;
+
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/81497990/app/addons/documents/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes.js b/app/addons/documents/routes.js
index 276e3fc..2140e04 100644
--- a/app/addons/documents/routes.js
+++ b/app/addons/documents/routes.js
@@ -11,17 +11,22 @@
 // the License.
 
 define([
-       "app",
+  "app",
 
-       "api",
+  "api",
 
-       // Modules
-       "addons/documents/views",
-       "addons/databases/base",
-       "addons/documents/resources"
+  // Modules
+  //views
+  "addons/documents/views",
+  "addons/documents/changesviews",
+  "addons/documents/indexviews",
+  "addons/documents/doceditorviews",
+
+  "addons/databases/base",
+  "addons/documents/resources"
 ],
 
-function(app, FauxtonAPI, Documents, Databases, Resources) {
+function(app, FauxtonAPI, Documents, Changes, Index, DocEditor, Databases, Resources) {
 
   var DocEditorRouteObject = FauxtonAPI.RouteObject.extend({
     layout: "one_pane",
@@ -58,7 +63,7 @@ function(app, FauxtonAPI, Documents, Databases, Resources) {
 
     code_editor: function (database, doc) {
 
-      this.docView = this.setView("#dashboard-content", new Documents.Views.CodeEditor({
+      this.docView = this.setView("#dashboard-content", new DocEditor.CodeEditor({
         model: this.doc,
         database: this.database
       }));
@@ -299,7 +304,7 @@ function(app, FauxtonAPI, Documents, Databases, Resources) {
         }
       });
 
-      this.viewEditor = this.setView("#dashboard-upper-content", new Documents.Views.ViewEditor({
+      this.viewEditor = this.setView("#dashboard-upper-content", new Index.ViewEditor({
         model: this.data.database,
         ddocs: this.data.designDocs,
         viewName: view,
@@ -359,7 +364,7 @@ function(app, FauxtonAPI, Documents, Databases, Resources) {
       this.toolsView && this.toolsView.remove();
       this.documentsView && this.documentsView.remove();
 
-      this.viewEditor = this.setView("#dashboard-upper-content", new Documents.Views.ViewEditor({
+      this.viewEditor = this.setView("#dashboard-upper-content", new Index.ViewEditor({
         currentddoc: "_design/"+designDoc || "",
         ddocs: this.data.designDocs,
         params: params,
@@ -499,7 +504,7 @@ function(app, FauxtonAPI, Documents, Databases, Resources) {
       var docParams = app.getParams();
       this.data.database.buildChanges(docParams);
 
-      this.documentsView = this.setView("#dashboard-lower-content", new Documents.Views.Changes({
+      this.documentsView = this.setView("#dashboard-lower-content", new Changes.Changes({
         model: this.data.database
       }));
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/81497990/app/addons/documents/views.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/views.js b/app/addons/documents/views.js
index c88ff39..66305ec 100644
--- a/app/addons/documents/views.js
+++ b/app/addons/documents/views.js
@@ -11,29 +11,24 @@
 // the License.
 
 define([
-       "app",
-
-       "api",
-       "addons/fauxton/components",
-
-       "addons/documents/resources",
-       "addons/documents/sidebarviews",
-       "addons/databases/resources",
-       "addons/pouchdb/base",
-
-       // Libs
-       "addons/fauxton/resizeColumns",
-
-       // Plugins
-       "plugins/beautify",
-       "plugins/prettify",
-       // this should never be global available:
-       // https://github.com/zeroclipboard/zeroclipboard/blob/master/docs/security.md
-       "plugins/zeroclipboard/ZeroClipboard"
+  "app",
+
+  "api",
+  "addons/fauxton/components",
+  "addons/documents/resources",
+  "addons/databases/resources",
+
+  //Views
+  "addons/documents/sidebarviews",
+  "addons/documents/queryoptionviews",
+  // Libs
+  "addons/fauxton/resizeColumns",
+  //plugins
+  "plugins/prettify"
 ],
 
-function(app, FauxtonAPI, Components, Documents, Views, Databases, pouchdb,
-         resizeColumns, beautify, prettify, ZeroClipboard) {
+function(app, FauxtonAPI, Components, Documents, Databases, Views, QueryOptions,
+         resizeColumns, prettify) {
 
   function showError (msg) {
     FauxtonAPI.addNotification({
@@ -44,56 +39,6 @@ function(app, FauxtonAPI, Components, Documents, Views, Databases, pouchdb,
   }
 
 
-  Views.SearchBox = FauxtonAPI.View.extend({
-    template: "addons/documents/templates/search",
-    tagName: "form",
-    initialize: function(options){
-      this.collection = options.collection;
-      this.database = options.database;
-    },
-    afterRender: function(){
-      var collection = this.collection;
-      var form = this.$el;
-      var searchbox = form.find("input#searchbox");
-      var database = this.database;
-
-      form.submit(function(evt){
-        evt.preventDefault();
-        var viewname = form.find("input#view").val().split('/');
-        var url = "#database/" + database + "/_design/";
-        url += viewname[0] + "/_view/" + viewname[1];
-        if (searchbox.val() !== ""){
-          // TODO: this'll need to work when val() is a number etc.
-          url += '?startkey="' + searchbox.val() + '"';
-        }
-        FauxtonAPI.navigate(url);
-      });
-
-      searchbox.typeahead({
-        source: function(query, process) {
-          // TODO: include _all_docs and view keys somehow
-          var views = _.map(collection.pluck('doc'), function(d){
-            return _.map(_.keys(d.views), function(view){
-              return d._id.split('/')[1] + "/" + view;
-            });
-          });
-          return _.flatten(views);
-        },
-        minLength: 3,
-        updater: function(item){
-          // TODO: some way to return the original search box
-          this.$element.removeClass('span12');
-          this.$element.addClass('span6');
-          this.$element.attr('placeholder', 'Search by view key');
-          $('<span class="add-on span6">' + item +'</span>').insertBefore(this.$element);
-          $('<input type="hidden" id="view" value="' + item +'"/>').insertBefore(this.$element);
-          // Remove the type ahead for now
-          $('.typehead').unbind();
-        }
-      });
-    }
-  });
-
   Views.DeleteDBModal = Components.ModalView.extend({
     template: "addons/documents/templates/delete_database_modal",
 
@@ -134,118 +79,7 @@ function(app, FauxtonAPI, Components, Documents, Views, Databases, pouchdb,
     }
   });
 
-  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.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);
-    }
-  });
 
   Views.Document = FauxtonAPI.View.extend({
     template: "addons/documents/templates/all_docs_item",
@@ -336,7 +170,7 @@ function(app, FauxtonAPI, Components, Documents, Views, Databases, pouchdb,
     }
   });
 
-  
+
   Views.AllDocsNumber = FauxtonAPI.View.extend({
     template: "addons/documents/templates/all_docs_number",
 
@@ -416,7 +250,7 @@ function(app, FauxtonAPI, Components, Documents, Views, Databases, pouchdb,
     },
 
     beforeRender: function () {
-      this.advancedOptions = this.insertView('#query', new Views.AdvancedOptions({
+      this.advancedOptions = this.insertView('#query', new QueryOptions.AdvancedOptions({
         updateViewFn: this.updateAllDocs,
         previewFn: this.previewView,
         hasReduce: false,
@@ -717,1046 +551,7 @@ function(app, FauxtonAPI, Components, Documents, Views, Databases, pouchdb,
     }
   });
 
-  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"
-    },
-
-    disableLoader: true,
-
-    initialize: function (options) {
-      this.database = options.database;
-      _.bindAll(this);
-    },
-
-    goback: function(){
-      FauxtonAPI.navigate(this.database.url("index") + "?limit=100");
-    },
-
-    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}));
-      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
-        });
-      });
-    },
-
-    cleanup: function () {
-      if (this.editor) this.editor.remove();
-    }
-  });
-
-  Views.AdvancedOptions = FauxtonAPI.View.extend({
-    template: "addons/documents/templates/advanced_options",
-    className: "advanced-options well",
-
-    initialize: function (options) {
-      this.database = options.database;
-      this.ddocName = options.ddocName;
-      this.viewName = options.viewName;
-      this.updateViewFn = options.updateViewFn;
-      this.previewFn = options.previewFn;
-      this.showStale = _.isUndefined(options.showStale) ? false : options.showStale;
-      this.hasReduce = _.isUndefined(options.hasReduce) ? true : options.hasReduce;
-    },
-
-    events: {
-      "change form.js-view-query-update input": "updateFilters",
-      "change form.js-view-query-update select": "updateFilters",
-      "submit form.js-view-query-update": "updateView",
-      "click .toggle-btns > label":  "toggleQuery"
-    },
-
-    toggleQuery: function(e){
-      e.preventDefault();
-
-      if (this.$(e.currentTarget).hasClass("active")){
-        this.$('.js-query-keys-wrapper').addClass("hide");
-        this.$(".toggle-btns > label").removeClass('active');
-        this.$('.js-query-keys-wrapper').find("input,textarea").attr("disabled","true");
-      } else {
-        this.$('.js-query-keys-wrapper').removeClass("hide");
-        var showFunctionName =this.$(e.currentTarget).attr("for");
-        //highlight current
-        this.$(".toggle-btns > label").removeClass('active');
-        this.$(e.currentTarget).addClass("active");
-        this.$("[id^='js-show']").hide();
-        //show section & disable what needs to be disabled
-        this[showFunctionName]();
-      }
-    },
-
-    showKeys: function(){
-      this.$("#js-showKeys, .js-disabled-message").show();
-      this.$('[name="startkey"],[name="endkey"],[name="inclusive_end"]').attr("disabled","true");
-      this.$('[name="keys"]').removeAttr("disabled");
-    },
-
-    showStartEnd: function(){
-      this.$("#js-showStartEnd").show();
-      this.$('[name="startkey"],[name="endkey"],[name="inclusive_end"]').removeAttr("disabled");
-      this.$('.js-disabled-message').hide();
-      this.$('[name="keys"]').attr("disabled","true");
-    },
-
-    beforeRender: function () {
-      if (this.viewName && this.ddocName) {
-        var buttonViews = FauxtonAPI.getExtensions('advancedOptions:ViewButton');
-        _.each(buttonViews, function (view) {
-          this.insertView('#button-options', view);
-          view.update(this.database, this.ddocName, this.viewName);
-        }, this);
-      }
-    },
-
-    renderOnUpdatehasReduce: function (hasReduce) {
-      this.hasReduce = hasReduce;
-      this.render();
-    },
-
-    parseJSON: function (value) {
-      try {
-        return JSON.parse(value);
-      } catch(e) {
-        return undefined;
-      }
-    },
-
-    validateKeys:  function(param){
-      var errorMsg = false,
-          parsedValue = this.parseJSON(param.value);
-
-      if (_.isUndefined(parsedValue)) {
-        errorMsg = "Keys must be valid json.";
-      } else if (!_.isArray(parsedValue)) {
-        errorMsg =  "Keys values must be in an array. E.g [1,2,3]";
-      }
-
-      if (errorMsg) {
-        this.$('.js-keys-error').empty();
-        FauxtonAPI.addNotification({
-          type: "error",
-          msg: errorMsg,
-          clear:  false,
-          selector: '.advanced-options .errors-container'
-        });
-        return false;
-      }
-
-      return true;
-    },
-    validateFields: function(params){
-      var errors = false;
-      //so ghetto. Spaghetti code.
-      for (var i= 0; i <params.length; i++){
-        if (params[i].name === "skip"){
-          if (!(/^\d+$/).test(params[i].value)){
-            FauxtonAPI.addNotification({
-              msg: "Numbers only for skip",
-              type: "warn",
-              selector: ".advanced-options .errors-container",
-              clear:  true
-            });
-            errors = true;
-          }
-        }
-      }
-      return errors;
-    },
-    queryParams: function () {
-      var $form = this.$(".js-view-query-update"),
-          keysParam = false;
-
-      var params = _.reduce($form.serializeArray(), function(params, param) {
-        if (!param.value) { return params; }
-        if (param.name === "limit" && param.value === 'None') { return params; }
-        if (param.name === "keys") { keysParam = param; }
-        params.push(param);
-        return params;
-      }, []);
-
-
-      if (keysParam && !this.validateKeys(keysParam)) { return false; }
-
-      if (params && this.validateFields(params)){ return false; }
-
-      // Validate *key* params to ensure they're valid JSON
-      var keyParams = ["keys","startkey","endkey"];
-      var errorParams = _.filter(params, function(param) {
-        if (_.contains(keyParams, param.name) && _.isUndefined(this.parseJSON(param.value))) {
-            return true;
-          }
-
-          return false;
-      }, this);
-
-      return {params: params, errorParams: errorParams};
-    },
-
-    updateView: function (event) {
-      event.preventDefault();
-      var params = this.queryParams();
-      if (!params) { return;}
-      this.updateViewFn(event, params);
-    },
-
-    updateFilters: function(event) {
-      event.preventDefault();
-      var $ele = $(event.currentTarget);
-      var name = $ele.attr('name');
-      this.updateFiltersFor(name, $ele);
-    },
-
-    updateFiltersFor: function(name, $ele) {
-      var $form = $ele.parents("form.js-view-query-update:first");
-      switch (name) {
-        // Reduce constraints
-        //   - Can't include_docs for reduce=true
-        //   - can't include group_level for reduce=false
-        case "reduce":
-          if ($ele.prop('checked') === true) {
-          if ($form.find("input[name=include_docs]").prop("checked") === true) {
-            $form.find("input[name=include_docs]").prop("checked", false);
-            var notification = FauxtonAPI.addNotification({
-              msg: "include_docs has been disabled as you cannot include docs on a reduced view",
-              type: "warn",
-              selector: ".advanced-options .errors-container",
-              clear:  true
-            });
-          }
-          $form.find("input[name=include_docs]").prop("disabled", true);
-          $form.find("select[name=group_level]").prop("disabled", false);
-        } else {
-          $form.find("select[name=group_level]").val("999").prop("disabled", true);
-          $form.find("input[name=include_docs]").prop("disabled", false);
-        }
-        break;
-        case "skip":
-          if (!(/^\d+$/).test($ele.val())){
-            FauxtonAPI.addNotification({
-              msg: "Numbers only for skip",
-              type: "warn",
-              selector: ".advanced-options .errors-container",
-              clear:  true
-            });
-          }
-        break;
-        case "include_docs":
-        break;
-      }
-    },
-
-    updateFromParams: function (params) {
-      var $form = this.$el.find("form.js-view-query-update");
-      _.each(params, function(val, key) {
-        var $ele;
-        switch (key) {
-          case "limit":
-          case "descending":
-          case "group_level":
-            if (!val) { return; }
-            $form.find("select[name='"+key+"']").val(val);
-          break;
-          case "include_docs":
-            case "stale":
-            case "inclusive_end":
-            $form.find("input[name='"+key+"']").prop('checked', true);
-          break;
-          case "reduce":
-            $ele = $form.find("input[name='"+key+"']");
-          if (val == "true") {
-            $ele.prop('checked', true);
-          }
-          this.updateFiltersFor(key, $ele);
-          break;
-          case "key":
-          case "keys":
-            $form.find("textarea[name='"+key+"']").val(val);
-          break;
-          default:
-            $form.find("input[name='"+key+"']").val(val);
-          break;
-        }
-      }, this);
-    },
-
-    serialize: function () {
-      return {
-        hasReduce: this.hasReduce,
-        showPreview: false,
-        showStale: this.showStale
-      };
-    }
-  });
-
-  Views.DesignDocSelector = FauxtonAPI.View.extend({
-    template: "addons/documents/templates/design_doc_selector",
-
-    events: {
-      "change select#ddoc": "updateDesignDoc"
-    },
-
-    initialize: function (options) {
-      this.ddocName = options.ddocName;
-      this.database = options.database;
-      this.listenTo(this.collection, 'add', this.ddocAdded);
-      this.DocModel = options.DocModel || Documents.Doc;
-    },
-
-    ddocAdded: function (ddoc) {
-      this.ddocName = ddoc.id;
-      this.render();
-    },
-
-    serialize: function () {
-      return {
-        ddocName: this.ddocName,
-        ddocs: this.collection
-      };
-    },
-
-    updateDesignDoc: function () {
-      if (this.newDesignDoc()) {
-        this.$('#new-ddoc-section').show();
-      } else {
-        this.$('#new-ddoc-section').hide();
-      }
-    },
-
-    newDesignDoc: function () {
-
-      return this.$('#ddoc').val() === 'new-doc';
-    },
-
-    newDocValidation: function(){
-      return this.newDesignDoc() && this.$('#new-ddoc').val()==="";
-    },
-    getCurrentDesignDoc: function () {
-      if (this.newDesignDoc()) {
-        var doc = {
-          _id: '_design/' + this.$('#new-ddoc').val(),
-          views: {},
-          language: "javascript"
-        };
-        var ddoc = new this.DocModel(doc, {database: this.database});
-        //this.collection.add(ddoc);
-        return ddoc;
-      } else if ( !this.newDesignDoc() ) {
-        var ddocName = this.$('#ddoc').val();
-        return this.collection.find(function (ddoc) {
-          return ddoc.id === ddocName;
-        }).dDocModel();
-      }
-    }
-  });
-
-  Views.ViewEditor = FauxtonAPI.View.extend({
-    template: "addons/documents/templates/view_editor",
-    builtinReduces: ['_sum', '_count', '_stats'],
-
-    events: {
-      "click button.save": "saveView",
-      "click button.delete": "deleteView",
-      "change select#reduce-function-selector": "updateReduce",
-      "click button.preview": "previewView",
-      "click #db-views-tabs-nav": 'toggleIndexNav',
-      "click .beautify_map":  "beautifyCode",
-      "click .beautify_reduce":  "beautifyCode",
-      "click #query-options-wrapper": 'toggleIndexNav'
-    },
-
-    langTemplates: {
-      "javascript": {
-        map: "function(doc) {\n  emit(doc._id, 1);\n}",
-        reduce: "function(keys, values, rereduce){\n  if (rereduce){\n    return sum(values);\n  } else {\n    return values.length;\n  }\n}"
-      }
-    },
-
-    defaultLang: "javascript",
-
-    initialize: function(options) {
-      this.newView = options.newView || false;
-      this.ddocs = options.ddocs;
-      this.params = options.params;
-      this.database = options.database;
-      this.currentDdoc = options.currentddoc;
-      if (this.newView) {
-        this.viewName = 'newView';
-      } else {
-        this.ddocID = options.ddocInfo.id;
-        this.viewName = options.viewName;
-        this.ddocInfo = new Documents.DdocInfo({_id: this.ddocID},{database: this.database});
-      }
-
-      this.showIndex = false;
-      _.bindAll(this);
-    },
-
-    establish: function () {
-      if (this.ddocInfo) {
-        return this.ddocInfo.fetch();
-      }
-    },
-
-    updateValues: function() {
-      var notification;
-      if (this.model.changedAttributes()) {
-        notification = FauxtonAPI.addNotification({
-          msg: "Document saved successfully.",
-          type: "success",
-          clear: true
-        });
-        this.editor.setValue(this.model.prettyJSON());
-      }
-    },
-
-    updateReduce: function(event) {
-      var $ele = $("#reduce-function-selector");
-      var $reduceContainer = $(".control-group.reduce-function");
-      if ($ele.val() == "CUSTOM") {
-        this.createReduceEditor();
-        this.reduceEditor.setValue(this.langTemplates.javascript.reduce);
-        $reduceContainer.show();
-      } else {
-        $reduceContainer.hide();
-      }
-    },
-
-    deleteView: function (event) {
-      event.preventDefault();
-
-      if (this.newView) { return alert('Cannot delete a new view.'); }
-      if (!confirm('Are you sure you want to delete this view?')) {return;}
-
-      var that = this,
-          promise,
-          viewName = this.$('#index-name').val(),
-          ddocName = this.$('#ddoc :selected').val(),
-          ddoc = this.getCurrentDesignDoc();
-
-      ddoc.removeDdocView(viewName);
-
-      if (ddoc.hasViews()) {
-        promise = ddoc.save();
-      } else {
-        promise = ddoc.destroy();
-      }
-
-      promise.then(function () {
-        FauxtonAPI.navigate('/database/' + that.database.safeID() + '/_all_docs?limit=' + Databases.DocLimit);
-        FauxtonAPI.triggerRouteEvent('reloadDesignDocs');
-      });
-    },
-
-    saveView: function(event) {
-      var json, notification,
-      that = this;
-
-      if (event) { event.preventDefault();}
-
-      $('#dashboard-content').scrollTop(0); //scroll up
-
-      if (this.hasValidCode() && this.$('#new-ddoc:visible').val() !=="") {
-        var mapVal = this.mapEditor.getValue(),
-        reduceVal = this.reduceVal(),
-        viewName = this.$('#index-name').val(),
-        ddoc = this.getCurrentDesignDoc(),
-        ddocName = ddoc.id,
-        viewNameChange = false;
-
-        if (this.viewName !== viewName) {
-          ddoc.removeDdocView(this.viewName);
-          this.viewName = viewName;
-          viewNameChange = true;
-        }
-
-        notification = FauxtonAPI.addNotification({
-          msg: "Saving document.",
-          selector: "#define-view .errors-container",
-          clear: true
-        });
-
-        ddoc.setDdocView(viewName, mapVal, reduceVal);
-
-        ddoc.save().then(function () {
-          that.ddocs.add(ddoc);
-
-          that.mapEditor.editSaved();
-          that.reduceEditor && that.reduceEditor.editSaved();
-
-
-          FauxtonAPI.addNotification({
-            msg: "View has been saved.",
-            type: "success",
-            selector: "#define-view .errors-container",
-            clear: true
-          });
-
-          if (that.newView || viewNameChange) {
-            var fragment = '/database/' + that.database.safeID() +'/' + ddoc.safeID() + '/_view/' + app.utils.safeURLName(viewName);
-
-            FauxtonAPI.navigate(fragment, {trigger: false});
-            that.newView = false;
-            that.ddocID = ddoc.safeID();
-            that.viewName = viewName;
-            that.ddocInfo = ddoc;
-            that.showIndex = true;
-            that.render();
-            FauxtonAPI.triggerRouteEvent('reloadDesignDocs', {
-              selectedTab: app.utils.removeSpecialCharacters(ddocName.replace(/_design\//,'')) + '_' + app.utils.removeSpecialCharacters(viewName)
-            });
-          }
-
-          if (that.reduceFunStr !== reduceVal) {
-            that.reduceFunStr = reduceVal;
-            that.advancedOptions.renderOnUpdatehasReduce(that.hasReduce());
-          }
-
-          FauxtonAPI.triggerRouteEvent('updateAllDocs', {ddoc: ddocName, view: viewName});
-
-        }, function(xhr) {
-          var responseText = JSON.parse(xhr.responseText).reason;
-          notification = FauxtonAPI.addNotification({
-            msg: "Save failed: " + responseText,
-            type: "error",
-            clear: true
-          });
-        });
-      } else {
-        var errormessage = (this.$('#new-ddoc:visible').val() ==="")?"Enter a design doc name":"Please fix the Javascript errors and try again.";
-        notification = FauxtonAPI.addNotification({
-          msg: errormessage,
-          type: "error",
-          selector: "#define-view .errors-container",
-          clear: true
-        });
-      }
-    },
-
-    updateView: function(event, paramInfo) {
-       event.preventDefault();
-
-       if (this.newView) { return alert('Please save this new view before querying it.'); }
-
-       var errorParams = paramInfo.errorParams,
-           params = paramInfo.params;
-
-       if (_.any(errorParams)) {
-         _.map(errorParams, function(param) {
-
-           // TODO: Where to add this error?
-           // bootstrap wants the error on a control-group div, but we're not using that
-           //$('form.view-query-update input[name='+param+'], form.view-query-update select[name='+param+']').addClass('error');
-           return FauxtonAPI.addNotification({
-             msg: "JSON Parse Error on field: "+param.name,
-             type: "error",
-             selector: ".advanced-options .errors-container",
-             clear: true
-           });
-         });
-         FauxtonAPI.addNotification({
-           msg: "Make sure that strings are properly quoted and any other values are valid JSON structures",
-           type: "warning",
-           selector: ".advanced-options .errors-container",
-           clear: true
-         });
-
-         return false;
-      }
-
-       var fragment = window.location.hash.replace(/\?.*$/, '');
-       if (!_.isEmpty(params)) {
-        fragment = fragment + '?' + $.param(params);
-       }
-
-       FauxtonAPI.navigate(fragment, {trigger: false});
-       FauxtonAPI.triggerRouteEvent('updateAllDocs', {ddoc: this.ddocID, view: this.viewName});
-    },
-
-
-    previewView: function(event, paramsInfo) {
-      event.preventDefault();
-      var that = this,
-      mapVal = this.mapVal(),
-      reduceVal = this.reduceVal(),
-      paramsArr = [];
-
-      if (paramsInfo && paramsInfo.params) {
-        paramsArr = paramsInfo.params;
-      }
-
-      var params = _.reduce(paramsArr, function (params, param) {
-        params[param.name] = param.value;
-        return params;
-      }, {reduce: false});
-
-      FauxtonAPI.addNotification({
-        msg: "<strong>Warning!</strong> Preview executes the Map/Reduce functions in your browser, and may behave differently from CouchDB.",
-        type: "warning",
-        selector: ".advanced-options .errors-container",
-        fade: true,
-        escape: false // beware of possible XSS when the message changes
-      });
-
-      var promise = FauxtonAPI.Deferred();
-
-      if (!this.database.allDocs || this.database.allDocs.params.include_docs !== true) {
-        this.database.buildAllDocs({limit: Databases.DocLimit.toString(), include_docs: true});
-        promise = this.database.allDocs.fetch();
-       } else {
-        promise.resolve();
-       }
-
-      promise.then(function () {
-        params.docs = that.database.allDocs.map(function (model) { return model.get('doc');});
-        var queryPromise = pouchdb.runViewQuery({map: mapVal, reduce: reduceVal}, params);
-        queryPromise.then(function (results) {
-          FauxtonAPI.triggerRouteEvent('updatePreviewDocs', {rows: results.rows, ddoc: that.getCurrentDesignDoc().id, view: that.viewName});
-        });
-      });
-    },
-
-    getCurrentDesignDoc: function () {
-      return this.designDocSelector.getCurrentDesignDoc();
-    },
-
-    isCustomReduceEnabled: function() {
-      return $("#reduce-function-selector").val() == "CUSTOM";
-    },
-
-    mapVal: function () {
-      if (this.mapEditor) {
-        return this.mapEditor.getValue();
-      }
-
-      return this.$('#map-function').text();
-    },
-
-    reduceVal: function() {
-      var reduceOption = this.$('#reduce-function-selector :selected').val(),
-      reduceVal = "";
-
-      if (reduceOption === 'CUSTOM') {
-        if (!this.reduceEditor) { this.createReduceEditor(); }
-        reduceVal = this.reduceEditor.getValue();
-      } else if ( reduceOption !== 'NONE') {
-        reduceVal = reduceOption;
-      }
-
-      return reduceVal;
-    },
-
-
-    hasValidCode: function() {
-      return _.every(["mapEditor", "reduceEditor"], function(editorName) {
-        var editor = this[editorName];
-        if (editorName === "reduceEditor" && ! this.isCustomReduceEnabled()) {
-          return true;
-        }
-        return editor.hadValidCode();
-      }, this);
-    },
-
-    toggleIndexNav: function (event) {
-      $('#dashboard-content').scrollTop(0); //scroll up
-
-      var $targetId = this.$(event.target).attr('id'),
-          $previousTab = this.$(this.$('li.active a').attr('href')),
-          $targetTab = this.$(this.$(event.target).attr('href'));
-
-      if ($targetTab.attr('id') !== $previousTab.attr('id')) {
-        $previousTab.removeAttr('style');
-      }
-
-      if ($targetId === 'index-nav') {
-        if (this.newView) { return; }
-        var that = this;
-        $('#dashboard-content').scrollTop(0); //scroll up
-        $targetTab.toggle('slow', function(){
-           that.showEditors();
-        });
-      } else {
-        $targetTab.toggle('slow');
-      }
-    },
-
-    serialize: function() {
-      return {
-        ddocs: this.ddocs,
-        ddoc: this.model,
-        ddocName: this.model.id,
-        viewName: this.viewName,
-        reduceFunStr: this.reduceFunStr,
-        isCustomReduce: this.hasCustomReduce(),
-        newView: this.newView,
-        langTemplates: this.langTemplates.javascript
-      };
-    },
-
-    hasCustomReduce: function() {
-      return this.reduceFunStr && ! _.contains(this.builtinReduces, this.reduceFunStr);
-    },
-
-    hasReduce: function () {
-      return this.reduceFunStr || false;
-    },
-
-    createReduceEditor: function () {
-      if (this.reduceEditor) {
-        this.reduceEditor.remove();
-      }
-
-      this.reduceEditor = new Components.Editor({
-        editorId: "reduce-function",
-        mode: "javascript",
-        couchJSHINT: true
-      });
-      this.reduceEditor.render();
-
-      if (this.reduceEditor.getLines() === 1){
-        this.$('.beautify_reduce').removeClass("hide");
-        $('.beautify-tooltip').tooltip();
-      }
-    },
-    beforeRender: function () {
-
-      if (this.newView) {
-        this.reduceFunStr = '';
-        if (this.ddocs.length === 0) {
-          this.model = new Documents.Doc(null, {database: this.database});
-        } else {
-          this.model = this.ddocs.first().dDocModel();
-        }
-        this.ddocID = this.model.id;
-      } else {
-        var ddocDecode = decodeURIComponent(this.ddocID);
-        this.model = this.ddocs.get(this.ddocID).dDocModel();
-        this.reduceFunStr = this.model.viewHasReduce(this.viewName);
-      }
-
-      var viewFilters = FauxtonAPI.getExtensions('sidebar:viewFilters'),
-          filteredModels = this.ddocs.models,
-          designDocs = this.ddocs.clone();
-
-      if (!_.isEmpty(viewFilters)) {
-        _.each(viewFilters, function (filter) {
-          filteredModels = _.filter(filteredModels, filter);
-        });
-        designDocs.reset(filteredModels, {silent: true});
-      }
-
-      this.designDocSelector = this.setView('.design-doc-group', new Views.DesignDocSelector({
-        collection: designDocs,
-        ddocName: this.currentDdoc || this.model.id,
-        database: this.database
-      }));
-
-      if (!this.newView) {
-        this.eventer = _.extend({}, Backbone.Events);
-
-        this.advancedOptions = this.insertView('#query', new Views.AdvancedOptions({
-          updateViewFn: this.updateView,
-          previewFn: this.previewView,
-          database: this.database,
-          viewName: this.viewName,
-          ddocName: this.model.id,
-          hasReduce: this.hasReduce(),
-          eventer: this.eventer,
-          showStale: true
-        }));
-      }
-
-    },
-
-    afterRender: function() {
 
-      if (this.params && !this.newView) {
-        this.advancedOptions.updateFromParams(this.params);
-      }
-
-      this.designDocSelector.updateDesignDoc();
-      if (this.newView || this.showIndex) {
-        this.showEditors();
-        this.showIndex = false;
-      } else {
-        this.$('#index').hide();
-        this.$('#index-nav').parent().removeClass('active');
-      }
-
-    },
-
-    showEditors: function () {
-      this.mapEditor = new Components.Editor({
-        editorId: "map-function",
-        mode: "javascript",
-        couchJSHINT: true
-      });
-      this.mapEditor.render();
-
-      if (this.hasCustomReduce()) {
-        this.createReduceEditor();
-      } else {
-        $(".control-group.reduce-function").hide();
-      }
-
-      if (this.newView) {
-        this.mapEditor.setValue(this.langTemplates[this.defaultLang].map);
-        //Use a built in view by default
-        //this.reduceEditor.setValue(this.langTemplates[this.defaultLang].reduce);
-      }
-
-      this.mapEditor.editSaved();
-      this.reduceEditor && this.reduceEditor.editSaved();
-
-      if (this.mapEditor.getLines() === 1){
-        this.$('.beautify_map').removeClass("hide");
-        $('.beautify-tooltip').tooltip();
-      }
-    },
-    beautifyCode: function(e){
-      e.preventDefault();
-      var targetEditor = $(e.currentTarget).hasClass('beautify_reduce')?this.reduceEditor:this.mapEditor;
-      var beautifiedCode = beautify(targetEditor.getValue());
-      targetEditor.setValue(beautifiedCode);
-    },
-    cleanup: function () {
-      this.mapEditor && this.mapEditor.remove();
-      this.reduceEditor && this.reduceEditor.remove();
-    }
-  });
 
   Views.JumpToDoc = FauxtonAPI.View.extend({
     template: "addons/documents/templates/jumpdoc",
@@ -1782,56 +577,7 @@ function(app, FauxtonAPI, Components, Documents, Views, Databases, pouchdb,
   });
 
 
-  
-  Views.Changes = FauxtonAPI.View.extend({
-    template: "addons/documents/templates/changes",
-
-    initialize: function () {
-      this.listenTo( this.model.changes, 'sync', this.render);
-      this.listenTo( this.model.changes, 'cachesync', this.render);
-    },
-
-    events: {
-      "click button.js-toggle-json": "toggleJson"
-    },
-
-    toggleJson: function(event) {
-      event.preventDefault();
-
-      var $button = this.$(event.target),
-          $container = $button.closest('.change-box').find(".js-json-container");
-
-      if (!$container.is(":visible")) {
-        $button
-          .text("Close JSON")
-          .addClass("btn-secondary")
-          .removeClass("btn-primary");
-      } else {
-        $button.text("View JSON")
-          .addClass("btn-primary")
-          .removeClass("btn-secondary");
-      }
-
-      $container.slideToggle();
-    },
-
-    establish: function() {
-      return [ this.model.changes.fetchOnce({prefill: true})];
-    },
 
-    serialize: function () {
-      return {
-        changes: this.model.changes.toJSON(),
-        database: this.model
-      };
-    },
-
-    afterRender: function(){
-      prettyPrint();
-      ZeroClipboard.config({ moviePath: "/assets/js/plugins/zeroclipboard/ZeroClipboard.swf" });
-      var client = new ZeroClipboard(this.$(".js-copy"));
-    }
-  });
 
   Views.DdocInfo = FauxtonAPI.View.extend({
     template: "addons/documents/templates/ddoc_info",


Mime
View raw message