Return-Path: X-Original-To: apmail-couchdb-commits-archive@www.apache.org Delivered-To: apmail-couchdb-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id B2039116FB for ; Mon, 28 Jul 2014 13:47:50 +0000 (UTC) Received: (qmail 70320 invoked by uid 500); 28 Jul 2014 13:47:50 -0000 Delivered-To: apmail-couchdb-commits-archive@couchdb.apache.org Received: (qmail 70157 invoked by uid 500); 28 Jul 2014 13:47:50 -0000 Mailing-List: contact commits-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list commits@couchdb.apache.org Received: (qmail 69958 invoked by uid 99); 28 Jul 2014 13:47:50 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 28 Jul 2014 13:47:50 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 208E39B7B8C; Mon, 28 Jul 2014 13:47:50 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: deathbear@apache.org To: commits@couchdb.apache.org Date: Mon, 28 Jul 2014 13:47:56 -0000 Message-Id: In-Reply-To: <7caa3dcb9e4c49299b87886f4aca1074@git.apache.org> References: <7caa3dcb9e4c49299b87886f4aca1074@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [8/8] fauxton commit: updated refs/heads/secondary-indexes to 4c45e12 Ripping out views into it's own addon Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/4c45e129 Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/4c45e129 Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/4c45e129 Branch: refs/heads/secondary-indexes Commit: 4c45e12966f22065ff333e500af4f926f84bf358 Parents: df3f068 Author: deathbearbrown Authored: Tue Jul 22 16:40:06 2014 -0400 Committer: deathbearbrown Committed: Mon Jul 28 09:47:38 2014 -0400 ---------------------------------------------------------------------- app/addons/documents/routes.js | 102 +--- .../templates/design_doc_selector.html | 38 -- app/addons/documents/templates/view_editor.html | 91 --- app/addons/documents/views-index.js | 574 ------------------- app/addons/indexes/index-components.js | 2 + app/addons/indexes/routes-filter.js | 47 ++ app/addons/indexes/routes-list.js | 47 ++ app/addons/indexes/routes-show.js | 47 ++ app/addons/indexes/routes-viewindexes.js | 204 +++++++ app/addons/indexes/routes.js | 24 +- .../indexes/templates/design_doc_selector.html | 38 ++ app/addons/indexes/templates/view_editor.html | 70 +++ app/addons/indexes/views.js | 559 +++++++++++++++++- settings.json.default | 1 + 14 files changed, 1021 insertions(+), 823 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/4c45e129/app/addons/documents/routes.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/routes.js b/app/addons/documents/routes.js index 9c266be..449e50e 100644 --- a/app/addons/documents/routes.js +++ b/app/addons/documents/routes.js @@ -19,14 +19,13 @@ define([ //views "addons/documents/views", "addons/documents/views-changes", - "addons/documents/views-index", "addons/documents/views-doceditor", "addons/databases/base", "addons/documents/resources" ], -function(app, FauxtonAPI, Documents, Changes, Index, DocEditor, Databases, Resources) { +function(app, FauxtonAPI, Documents, Changes, DocEditor, Databases, Resources) { var DocEditorRouteObject = FauxtonAPI.RouteObject.extend({ layout: "one_pane", @@ -133,28 +132,10 @@ function(app, FauxtonAPI, Documents, Changes, Index, DocEditor, Databases, Resou route: "allDocs", roles: ["_reader","_writer","_admin"] }, - "database/:database/_design/:ddoc/_view/:view": { - route: "viewFn", - roles: ['_admin'] - }, - "database/:database/_design/:ddoc/_lists/:fn": { - route: "tempFn", - roles: ['_admin'] - }, - "database/:database/_design/:ddoc/_filters/:fn": { - route: "tempFn", - roles: ['_admin'] - }, - "database/:database/_design/:ddoc/_show/:fn": { - route: "tempFn", - roles: ['_admin'] - }, "database/:database/_design/:ddoc/metadata": { route: "designDocMetadata", roles: ['_admin'] }, - "database/:database/new_view": "newViewEditor", - "database/:database/new_view/:designDoc": "newViewEditor", "database/:database/_changes(:params)": "changes" }, @@ -213,15 +194,6 @@ function(app, FauxtonAPI, Documents, Changes, Index, DocEditor, Databases, Resou this.apiUrl = [designDocInfo.url('apiurl'), designDocInfo.documentation() ]; }, - tempFn: function(databaseName, ddoc, fn){ - this.setView("#dashboard-upper-content", new Documents.Views.temp({})); - this.crumbs = function () { - return [ - {"name": this.data.database.id, "link": Databases.databaseUrl(this.data.database)}, - ]; - }; - - }, establish: function () { return this.data.designDocs.fetch({reset: true}); @@ -286,56 +258,6 @@ function(app, FauxtonAPI, Documents, Changes, Index, DocEditor, Databases, Resou this.apiUrl = [this.data.database.allDocs.urlRef("apiurl", urlParams), this.data.database.allDocs.documentation() ]; }, - viewFn: function (databaseName, ddoc, view) { - var params = this.createParams(), - urlParams = params.urlParams, - docParams = params.docParams, - decodeDdoc = decodeURIComponent(ddoc); - - view = view.replace(/\?.*$/,''); - - this.data.indexedDocs = new Documents.IndexCollection(null, { - database: this.data.database, - design: decodeDdoc, - view: view, - params: docParams, - paging: { - pageSize: this.getDocPerPageLimit(urlParams, parseInt(docParams.limit, 10)) - } - }); - - this.viewEditor = this.setView("#dashboard-upper-content", new Index.ViewEditor({ - model: this.data.database, - ddocs: this.data.designDocs, - viewName: view, - params: urlParams, - newView: false, - database: this.data.database, - ddocInfo: this.ddocInfo(decodeDdoc, this.data.designDocs, view) - })); - - this.toolsView && this.toolsView.remove(); - - this.documentsView = this.createViewDocumentsView({ - designDoc: decodeDdoc, - docParams: docParams, - urlParams: urlParams, - database: this.data.database, - indexedDocs: this.data.indexedDocs, - designDocs: this.data.designDocs, - view: view - }); - - this.sidebar.setSelectedTab(app.utils.removeSpecialCharacters(ddoc) + '_' + app.utils.removeSpecialCharacters(view)); - - this.crumbs = function () { - return [ - {"name": this.data.database.id, "link": Databases.databaseUrl(this.data.database)}, - ]; - }; - - this.apiUrl = [this.data.indexedDocs.urlRef("apiurl", urlParams), "docs"]; - }, ddocInfo: function (designDoc, designDocs, view) { return { @@ -358,28 +280,6 @@ function(app, FauxtonAPI, Documents, Changes, Index, DocEditor, Databases, Resou })); }, - newViewEditor: function (database, designDoc) { - var params = app.getParams(); - - this.toolsView && this.toolsView.remove(); - this.documentsView && this.documentsView.remove(); - - this.viewEditor = this.setView("#dashboard-upper-content", new Index.ViewEditor({ - currentddoc: "_design/"+designDoc || "", - ddocs: this.data.designDocs, - params: params, - database: this.data.database, - newView: true - })); - - this.sidebar.setSelectedTab('new-view'); - this.crumbs = function () { - return [ - {"name": this.data.database.id, "link": Databases.databaseUrl(this.data.database)}, - ]; - }; - }, - updateAllDocsFromView: function (event) { var view = event.view, params = this.createParams(), http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/4c45e129/app/addons/documents/templates/design_doc_selector.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/design_doc_selector.html b/app/addons/documents/templates/design_doc_selector.html deleted file mode 100644 index 828b5a5..0000000 --- a/app/addons/documents/templates/design_doc_selector.html +++ /dev/null @@ -1,38 +0,0 @@ - -
- - -
- - http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/4c45e129/app/addons/documents/templates/view_editor.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/view_editor.html b/app/addons/documents/templates/view_editor.html deleted file mode 100644 index e6fbbc1..0000000 --- a/app/addons/documents/templates/view_editor.html +++ /dev/null @@ -1,91 +0,0 @@ - - -
-
-
-
-
-
-
- -
-
- -
- - -
- - -
- - <% if (newView) { %> -
<%= langTemplates.map %>
- <% } else { %> -
<%- ddoc.get('views')[viewName].map %>
- - <% } %> -
- - -
- - - -
- -
- - <% if (newView) { %> -
<%- langTemplates.reduce %>
- <% } else { %> -
<%- ddoc.get('views')[viewName].reduce %>
- - <% } %> -
- -
- - <% if (!newView) { %> - - <% } %> -
-
-
-
-
-
-
-
-
-
-
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/4c45e129/app/addons/documents/views-index.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/views-index.js b/app/addons/documents/views-index.js deleted file mode 100644 index d0ed8ed..0000000 --- a/app/addons/documents/views-index.js +++ /dev/null @@ -1,574 +0,0 @@ -// 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/views-advancedopts", - // 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: "Warning! 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/4c45e129/app/addons/indexes/index-components.js ---------------------------------------------------------------------- diff --git a/app/addons/indexes/index-components.js b/app/addons/indexes/index-components.js index ffb22a0..1ec34e2 100644 --- a/app/addons/indexes/index-components.js +++ b/app/addons/indexes/index-components.js @@ -23,6 +23,8 @@ define([ ], function(app, FauxtonAPI) { + var Components = {}; + return Components; }); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/4c45e129/app/addons/indexes/routes-filter.js ---------------------------------------------------------------------- diff --git a/app/addons/indexes/routes-filter.js b/app/addons/indexes/routes-filter.js new file mode 100644 index 0000000..492b014 --- /dev/null +++ b/app/addons/indexes/routes-filter.js @@ -0,0 +1,47 @@ +// 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/databases/base", + "addons/indexes/views", + "addons/documents/views", + "addons/indexes/resources" +], + +function (app, FauxtonAPI, Databases, Views, Documents, Resources) { + + var FilterIndexes = FauxtonAPI.RouteObject.extend({ + layout: "two_pane", + routes: { + "database/:database/_design/:ddoc/_filters/:fn": { + route: "tempFn", + roles: ['_admin'] + }, + "database/:database/new_filter": "newFilterEditor", + "database/:database/new_filter/:designDoc": "newFilterEditor" + }, + newFilterEditor: function(){ + return false; + }, + tempFn: function(databaseName, ddoc, fn){ + this.setView("#dashboard-upper-content", new Documents.Views.temp({})); + this.crumbs = function () { + return [ + {"name": this.data.database.id, "link": Databases.databaseUrl(this.data.database)}, + ]; + }; + } + }); + + return FilterIndexes; +}); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/4c45e129/app/addons/indexes/routes-list.js ---------------------------------------------------------------------- diff --git a/app/addons/indexes/routes-list.js b/app/addons/indexes/routes-list.js new file mode 100644 index 0000000..10141b7 --- /dev/null +++ b/app/addons/indexes/routes-list.js @@ -0,0 +1,47 @@ +// 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/databases/base", + "addons/indexes/views", + "addons/documents/views", + "addons/indexes/resources" +], + +function (app, FauxtonAPI, Databases, Views, Documents, Resources) { + + var ListIndexes = FauxtonAPI.RouteObject.extend({ + layout: "two_pane", + routes: { + "database/:database/_design/:ddoc/_lists/:fn": { + route: "tempFn", + roles: ['_admin'] + }, + "database/:database/new_lists": "newListsEditor", + "database/:database/new_lists/:designDoc": "newListsEditor" + }, + newListsEditor: function(){ + return false; + }, + tempFn: function(databaseName, ddoc, fn){ + this.setView("#dashboard-upper-content", new Documents.Views.temp({})); + this.crumbs = function () { + return [ + {"name": this.data.database.id, "link": Databases.databaseUrl(this.data.database)}, + ]; + }; + } + }); + + return ListIndexes; +}); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/4c45e129/app/addons/indexes/routes-show.js ---------------------------------------------------------------------- diff --git a/app/addons/indexes/routes-show.js b/app/addons/indexes/routes-show.js new file mode 100644 index 0000000..1861fd1 --- /dev/null +++ b/app/addons/indexes/routes-show.js @@ -0,0 +1,47 @@ +// 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/databases/base", + "addons/indexes/views", + "addons/documents/views", + "addons/indexes/resources" +], + +function (app, FauxtonAPI, Databases, Views, Documents, Resources) { + + var ShowIndexes = FauxtonAPI.RouteObject.extend({ + layout: "two_pane", + routes: { + "database/:database/_design/:ddoc/_show/:fn": { + route: "tempFn", + roles: ['_admin'] + }, + "database/:database/new_show": "newShowEditor", + "database/:database/new_show/:designDoc": "newShowEditor" + }, + newShowEditor: function(){ + return false; + }, + tempFn: function(databaseName, ddoc, fn){ + this.setView("#dashboard-upper-content", new Documents.Views.temp({})); + this.crumbs = function () { + return [ + {"name": this.data.database.id, "link": Databases.databaseUrl(this.data.database)}, + ]; + }; + } + }); + + return ShowIndexes; +}); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/4c45e129/app/addons/indexes/routes-viewindexes.js ---------------------------------------------------------------------- diff --git a/app/addons/indexes/routes-viewindexes.js b/app/addons/indexes/routes-viewindexes.js new file mode 100644 index 0000000..9577cbb --- /dev/null +++ b/app/addons/indexes/routes-viewindexes.js @@ -0,0 +1,204 @@ +// 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/databases/base", + "addons/indexes/views", + "addons/documents/views", + "addons/indexes/resources" +], + +function (app, FauxtonAPI, Databases, Views, Documents, Resources) { + + var ViewIndexes = FauxtonAPI.RouteObject.extend({ + layout: "two_pane", + routes: { + "database/:database/_design/:ddoc/_view/:view": { + route: "viewFn", + roles: ['_admin'] + }, + "database/:database/new_view": "newViewEditor", + "database/:database/new_view/:designDoc": "newViewEditor" + }, + initialize: function (route, masterLayout, options) { + this.databaseName = options[0]; + + this.data = { + database: new Databases.Model({id:this.databaseName}) + }; + + this.data.designDocs = new Documents.AllDocs(null, { + database: this.data.database, + paging: { + pageSize: 500 + }, + params: { + startkey: '_design', + endkey: '_design1', + include_docs: true, + limit: 500 + } + }); + }, + + + createViewDocumentsView: function (options) { + return this.setView("#right-content", new Documents.Views.AllDocsList({ + database: options.database, + collection: options.indexedDocs, + nestedView: Documents.Views.Row, + viewList: true, + ddocInfo: this.ddocInfo(options.designDoc, options.designDocs, options.view), + docParams: options.docParams, + params: options.urlParams + })); + }, + + ddocInfo: function (designDoc, designDocs, view) { + return { + id: "_design/" + designDoc, + currView: view, + designDocs: designDocs + }; + }, + + createParams: function (options) { + var urlParams = app.getParams(options); + var params = Documents.QueryParams.parse(urlParams); + + return { + urlParams: urlParams, + docParams: _.extend(params, {limit: this.getDocPerPageLimit(params, 20)}) + }; + }, + + getDocPerPageLimit: function (urlParams, perPage) { + var storedPerPage = perPage; + + if (window.localStorage) { + storedPerPage = window.localStorage.getItem('fauxton:perpage'); + + if (!storedPerPage) { + this.setDocPerPageLimit(perPage); + storedPerPage = perPage; + } else { + storedPerPage = parseInt(storedPerPage, 10); + } + } + + if (!urlParams.limit || urlParams.limit > storedPerPage) { + return parseInt(storedPerPage, 10); + } else { + return parseInt(urlParams.limit, 10); + } + }, + + establish: function () { + return this.data.designDocs.fetch({reset: true}); + }, + + updateAllDocsFromPreview: function (event) { + var view = event.view, + rows = event.rows, + ddoc = event.ddoc; + + this.data.indexedDocs = new Documents.PouchIndexCollection(null, { + database: this.data.database, + design: ddoc, + view: view, + rows: rows + }); + + // this.documentsView = this.setView("#dashboard-lower-content", new Documents.Views.AllDocsList({ + // database: this.data.database, + // collection: this.data.indexedDocs, + // nestedView: Documents.Views.Row, + // viewList: true + // })); + }, + + newViewEditor: function (database, designDoc) { + var params = app.getParams(); + + this.toolsView && this.toolsView.remove(); + this.documentsView && this.documentsView.remove(); + + this.viewEditor = this.setView("#left-content", new Views.ViewEditor({ + currentddoc: "_design/"+designDoc || "", + ddocs: this.data.designDocs, + params: params, + database: this.data.database, + newView: true + })); + + this.sidebar.setSelectedTab('new-view'); + this.crumbs = function () { + return [ + {"name": this.data.database.id, "link": Databases.databaseUrl(this.data.database)}, + ]; + }; + }, + + viewFn: function (databaseName, ddoc, view) { + var params = this.createParams(), + urlParams = params.urlParams, + docParams = params.docParams, + decodeDdoc = decodeURIComponent(ddoc); + + view = view.replace(/\?.*$/,''); + + this.data.indexedDocs = new Documents.IndexCollection(null, { + database: this.data.database, + design: decodeDdoc, + view: view, + params: docParams, + paging: { + pageSize: this.getDocPerPageLimit(urlParams, parseInt(docParams.limit, 10)) + } + }); + + this.viewEditor = this.setView("#left-content", new Views.ViewEditor({ + model: this.data.database, + ddocs: this.data.designDocs, + viewName: view, + params: urlParams, + newView: false, + database: this.data.database, + ddocInfo: this.ddocInfo(decodeDdoc, this.data.designDocs, view) + })); + + this.toolsView && this.toolsView.remove(); + + this.documentsView = this.createViewDocumentsView({ + designDoc: decodeDdoc, + docParams: docParams, + urlParams: urlParams, + database: this.data.database, + indexedDocs: this.data.indexedDocs, + designDocs: this.data.designDocs, + view: view + }); + + + this.crumbs = function () { + return [ + {"name": this.data.database.id, "link": Databases.databaseUrl(this.data.database)}, + ]; + }; + + this.apiUrl = [this.data.indexedDocs.urlRef("apiurl", urlParams), "docs"]; + } + }); + + return ViewIndexes; +}); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/4c45e129/app/addons/indexes/routes.js ---------------------------------------------------------------------- diff --git a/app/addons/indexes/routes.js b/app/addons/indexes/routes.js index 4c7515d..52771d6 100644 --- a/app/addons/indexes/routes.js +++ b/app/addons/indexes/routes.js @@ -12,22 +12,14 @@ define([ "app", "api", - "addons/indexes/resources", - "addons/indexes/views" + "addons/indexes/views", + "addons/indexes/routes-viewindexes", + "addons/indexes/routes-filter", + "addons/indexes/routes-show", + "addons/indexes/routes-list", ], -function (app, FauxtonAPI, Resources, Views) { - - var ViewIndexes = FauxtonAPI.RouteObject.extend({}); - - var FilterIndexes = FauxtonAPI.RouteObject.extend({}); - - var ShowIndexes = FauxtonAPI.RouteObject.extend({}); - - var ListIndexes = FauxtonAPI.RouteObject.extend({}); - - - Resources.RouteObjects = [ViewIndexes, FilterIndexes, ShowIndexes, ListIndexes]; - - return Resources; +function (app, FauxtonAPI, Views, ViewIndex, Filter, Show, List) { + Views.RouteObjects = [ViewIndex, Filter, Show, List]; + return Views; }); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/4c45e129/app/addons/indexes/templates/design_doc_selector.html ---------------------------------------------------------------------- diff --git a/app/addons/indexes/templates/design_doc_selector.html b/app/addons/indexes/templates/design_doc_selector.html new file mode 100644 index 0000000..828b5a5 --- /dev/null +++ b/app/addons/indexes/templates/design_doc_selector.html @@ -0,0 +1,38 @@ + +
+ + +
+ + http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/4c45e129/app/addons/indexes/templates/view_editor.html ---------------------------------------------------------------------- diff --git a/app/addons/indexes/templates/view_editor.html b/app/addons/indexes/templates/view_editor.html new file mode 100644 index 0000000..afc7454 --- /dev/null +++ b/app/addons/indexes/templates/view_editor.html @@ -0,0 +1,70 @@ + +
+
+
+
+ +
+
+ +
+ + +
+ + +
+ + <% if (newView) { %> +
<%= langTemplates.map %>
+ <% } else { %> +
<%- ddoc.get('views')[viewName].map %>
+ + <% } %> +
+ + +
+ + + +
+ +
+ + <% if (newView) { %> +
<%- langTemplates.reduce %>
+ <% } else { %> +
<%- ddoc.get('views')[viewName].reduce %>
+ + <% } %> +
+ +
+ + <% if (!newView) { %> + + <% } %> +
+
+
+
+ http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/4c45e129/app/addons/indexes/views.js ---------------------------------------------------------------------- diff --git a/app/addons/indexes/views.js b/app/addons/indexes/views.js index e8383cf..42a9066 100644 --- a/app/addons/indexes/views.js +++ b/app/addons/indexes/views.js @@ -9,13 +9,566 @@ // 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" + "app", + + "api", + "addons/fauxton/components", + + "addons/documents/resources", + "addons/databases/resources", + "addons/pouchdb/base", + //views + "addons/documents/views-advancedopts", + // Libs + "addons/fauxton/resizeColumns", + + // Plugins + "plugins/beautify", + "plugins/prettify" ], -function (app, FauxtonAPI) { +function(app, FauxtonAPI, Components, Documents, Databases, pouchdb, + QueryOptions, resizeColumns, beautify, prettify) { + var Views = {}; + Views.ViewEditor = FauxtonAPI.View.extend({ + template: "addons/indexes/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: "Warning! 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/indexes/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/4c45e129/settings.json.default ---------------------------------------------------------------------- diff --git a/settings.json.default b/settings.json.default index bc5a617..d278368 100644 --- a/settings.json.default +++ b/settings.json.default @@ -3,6 +3,7 @@ { "name": "fauxton" }, { "name": "databases" }, { "name": "documents" }, + { "name": "indexes" }, { "name": "pouchdb" }, { "name": "activetasks" }, { "name": "config" },