You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ro...@apache.org on 2014/10/15 14:33:38 UTC
[3/8] fauxton commit: updated refs/heads/port-views to f114d07
import index module
Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/fc1eb5c8
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/fc1eb5c8
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/fc1eb5c8
Branch: refs/heads/port-views
Commit: fc1eb5c8a7907e4fe9622b439b7052adc530ec95
Parents: b74df89
Author: Robert Kowalski <ro...@apache.org>
Authored: Tue Oct 14 16:12:33 2014 +0200
Committer: Robert Kowalski <ro...@apache.org>
Committed: Wed Oct 15 14:33:09 2014 +0200
----------------------------------------------------------------------
.gitignore | 1 +
app/addons/indexes/assets/less/doc-item.less | 95 +++
app/addons/indexes/assets/less/index-form.less | 64 ++
app/addons/indexes/assets/less/indexes.less | 17 +
.../assets/less/new-index-placeholder.less | 26 +
app/addons/indexes/base.js | 78 +++
app/addons/indexes/resources.js | 216 ++++++
app/addons/indexes/routes-core.js | 224 +++++++
app/addons/indexes/routes-list.js | 108 +++
app/addons/indexes/routes-show.js | 103 +++
app/addons/indexes/routes-viewindexes.js | 144 ++++
app/addons/indexes/routes.js | 24 +
.../indexes/templates/design_doc_selector.html | 34 +
app/addons/indexes/templates/header_right.html | 23 +
.../indexes/templates/index_row_docular.html | 35 +
app/addons/indexes/templates/list_editor.html | 18 +
.../indexes/templates/preview_screen.html | 18 +
app/addons/indexes/templates/show_editor.html | 41 ++
app/addons/indexes/templates/view_editor.html | 80 +++
app/addons/indexes/views.js | 653 +++++++++++++++++++
20 files changed, 2002 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 1baaaf1..f7cb6c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,7 @@ app/addons/*
!app/addons/databases
!app/addons/documents
!app/addons/styletests
+!app/addons/indexes
settings.json*
!settings.json.default
!assets/js/plugins/zeroclipboard/ZeroClipboard.swf
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/app/addons/indexes/assets/less/doc-item.less
----------------------------------------------------------------------
diff --git a/app/addons/indexes/assets/less/doc-item.less b/app/addons/indexes/assets/less/doc-item.less
new file mode 100644
index 0000000..3d3e3ad
--- /dev/null
+++ b/app/addons/indexes/assets/less/doc-item.less
@@ -0,0 +1,95 @@
+// 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.
+.view table td div.doc-menu-item div.dropdown{
+ display: block;
+}
+
+
+#doc-list{
+ padding-top: 30px;
+ .all-docs-item {
+ .select {
+ display:none;
+ float: left;
+ vertical-align: top;
+ }
+ &.showSelect{
+ .select {
+ display:block;
+ width: 10%;
+ }
+ .doc-item {
+ width:90%;
+ }
+ }
+ }
+ div.doc-row {
+ margin-bottom:20px;
+ .doc-item {
+ float:left;
+ width:100%;
+ vertical-align: top;
+ position: relative;
+ .border-radius(5px 5px 5px 5px);
+ .box-shadow(3px 4px 0 rgba(0, 0, 0, 0.3));
+ border: 1px solid #000;
+ header {
+ font-weight: bold;
+ position: relative;
+ padding: 20px;
+ background-color: #777;
+ color: #3a2c2b;
+ border-bottom: 1px solid #000;
+ .header-id-number{
+ color: #fff;
+ margin-left: 10px;
+ }
+ }
+
+ .doc-data{
+ pre.prettyprint{
+ }
+ }
+
+ &:hover{
+ .btn-group{
+ display:block;
+ }
+ }
+ //temporary
+ .btn-group{
+ position:absolute;
+ top:10px;
+ right:10px;
+ display:none;
+ }
+
+ .doc-menu {
+ position:absolute;
+ right: 0px;
+ top: 0px;
+ .doc-menu-item{
+ a {
+ text-decoration: none;
+ }
+ .dropdown-menu {
+ left:auto;
+ right: 0px;
+ }
+ display: inline-block;
+ width: 30px;
+ height: 30px;
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/app/addons/indexes/assets/less/index-form.less
----------------------------------------------------------------------
diff --git a/app/addons/indexes/assets/less/index-form.less b/app/addons/indexes/assets/less/index-form.less
new file mode 100644
index 0000000..c07163b
--- /dev/null
+++ b/app/addons/indexes/assets/less/index-form.less
@@ -0,0 +1,64 @@
+// 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.
+.index-form{
+ .control-group {
+ padding:15px 25px;
+ border-bottom: 1px solid #D9D9D9;
+ border-top: 1px solid #fff;
+ margin: 0 0 0 1px;
+ > input[type=text]{
+ width: 100%;
+ .border-radius(5px 5px 5px 5px);
+ }
+ }
+ .js-editor {
+ border: 1px solid #ccc;
+ .border-radius(5px 5px 5px 5px);
+ }
+}
+.input-prepend {
+ margin-left:0;
+}
+.new-ddoc {
+ .select-wrapper {
+ .border-radius(5px 0 0 5px);
+ margin-left:0;
+ overflow: hidden;
+ border: 1px solid #d0cdc6;
+ position: relative;
+ select {
+ border: 0;
+ color: #000;
+ background: transparent;
+ font-size: 14px;
+ padding: 5px 10px;
+ -webkit-appearance: none;
+ -moz-appearance: window;
+ height: 44px;
+ }
+ i {
+ position: absolute;
+ right: 20px;
+ top: 16px;
+ display: block;
+ color: #000;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-width: 10px 7.5px 0 7.5px;
+ border-color: #000000 transparent transparent transparent;
+ }
+ }
+ input[type=text]{
+ .border-radius(0px 5px 5px 0);
+ }
+}
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/app/addons/indexes/assets/less/indexes.less
----------------------------------------------------------------------
diff --git a/app/addons/indexes/assets/less/indexes.less b/app/addons/indexes/assets/less/indexes.less
new file mode 100644
index 0000000..5795cce
--- /dev/null
+++ b/app/addons/indexes/assets/less/indexes.less
@@ -0,0 +1,17 @@
+// 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.
+@import "../../../../../assets/less/variables.less";
+@import "../../../../../assets/less/bootstrap/variables.less";
+@import "../../../../../assets/less/bootstrap/mixins.less";
+@import "new-index-placeholder.less";
+@import "index-form.less";
+@import "doc-item.less";
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/app/addons/indexes/assets/less/new-index-placeholder.less
----------------------------------------------------------------------
diff --git a/app/addons/indexes/assets/less/new-index-placeholder.less b/app/addons/indexes/assets/less/new-index-placeholder.less
new file mode 100644
index 0000000..b5ca506
--- /dev/null
+++ b/app/addons/indexes/assets/less/new-index-placeholder.less
@@ -0,0 +1,26 @@
+// 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.
+.watermark-logo {
+ background: transparent url('../img/couchWatermark.png') no-repeat 50% 50%;
+ min-height: 400px;
+ padding-top: 60%;
+ text-align: center;
+ margin: 0 20%;
+ h3 {
+ border-bottom: 1px solid #ccc;
+ padding-bottom:10px;
+ margin-bottom:20px;
+ }
+ .preview {
+ margin: 0 10px;
+ }
+}
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/app/addons/indexes/base.js
----------------------------------------------------------------------
diff --git a/app/addons/indexes/base.js b/app/addons/indexes/base.js
new file mode 100644
index 0000000..f2220fa
--- /dev/null
+++ b/app/addons/indexes/base.js
@@ -0,0 +1,78 @@
+// 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.
+
+
+/* View Indexes */
+define([
+ "app",
+ "api",
+ "addons/indexes/routes"
+],
+function(app, FauxtonAPI, Routes) {
+ Routes.initialize = function() {
+
+ /*
+ Example of an extension:
+ An extension is just like an event that may or may not have listener in another view.
+ In this case the listener is in the documents addon in the sidebar.
+
+ If there are is a view that you want rendered in another route, this is the way to do it.
+
+ Each Secondary index is going to trigger this event with the views it's passing.
+ The views will be rendered and have links to the routes defined in this addon. Then it's just business as usual.
+
+ FauxtonAPI.registerExtension('sidebar:list', new Views.IndexMenu({}));
+ FauxtonAPI.registerExtension('sidebar:links',{
+ title: "New View",
+ url: "new_view"
+ });
+
+
+ */
+ //Show in the sidebar
+ FauxtonAPI.registerExtension('sidebar:list', {
+ selector:'views',
+ ddocType:'view',
+ icon: "fonticon-sidenav-map-reduce"
+ });
+
+ //Commented out since they are just POCs
+ // FauxtonAPI.registerExtension('sidebar:list', {
+ // selector:'list',
+ // icon: "fonticon-sidenav-list-function"
+ // });
+ // FauxtonAPI.registerExtension('sidebar:list', {
+ // selector:'show',
+ // icon: "fonticon-sidenav-show-function"
+ // });
+
+
+ /* show in the add new menu dropdown */
+ FauxtonAPI.registerExtension('sidebar:links', {
+ title: "Secondary View",
+ url: "new_view"
+ });
+
+ //Commented out since they are just POCs
+ // FauxtonAPI.registerExtension('sidebar:links', {
+ // title: "List Function",
+ // url: "new_list"
+ // });
+
+ // FauxtonAPI.registerExtension('sidebar:links', {
+ // url: 'new_show',
+ // title: 'Show Index'
+ // });
+
+ };
+ return Routes;
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/app/addons/indexes/resources.js
----------------------------------------------------------------------
diff --git a/app/addons/indexes/resources.js b/app/addons/indexes/resources.js
new file mode 100644
index 0000000..2b5fbe7
--- /dev/null
+++ b/app/addons/indexes/resources.js
@@ -0,0 +1,216 @@
+// 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",
+ "cloudant.pagingcollection"
+],
+
+function(app, FauxtonAPI, PagingCollection) {
+ var Resources = {};
+
+
+ Resources.QueryParams = (function () {
+ var _eachParams = function (params, action) {
+ // clone to avoid in-place modification
+ var result = _.clone(params);
+
+ _.each(['startkey', 'endkey', 'key'], function (key) {
+ if (_.has(result, key)) {
+ result[key] = action(result[key]);
+ }
+ });
+
+ return result;
+ };
+
+ return {
+ parse: function (params) {
+ return _eachParams(params, JSON.parse);
+ },
+
+ stringify: function (params) {
+ return _eachParams(params, JSON.stringify);
+ }
+ };
+ })();
+
+ Resources.ViewRow = FauxtonAPI.Model.extend({
+ // this is a hack so that backbone.collections doesn't group
+ // these by id and reduce the number of items returned.
+ idAttribute: "_id",
+
+ docType: function() {
+ if (!this.id) return "reduction";
+
+ return this.id.match(/^_design/) ? "design doc" : "doc";
+ },
+ documentation: function(){
+ return "docs";
+ },
+ url: function(context) {
+ return this.collection.database.url(context) + "/" + this.safeID();
+ },
+
+ isEditable: function() {
+ return this.docType() != "reduction";
+ },
+ safeID: function() {
+ var id = this.id || this.get("id");
+
+ return app.utils.safeURLName(id);
+ },
+
+ prettyJSON: function() {
+ //var data = this.get("doc") ? this.get("doc") : this;
+ return JSON.stringify(this, null, " ");
+ }
+ });
+
+
+
+ Resources.IndexCollection = PagingCollection.extend({
+ model: Resources.ViewRow,
+ documentation: function(){
+ return "docs";
+ },
+ initialize: function(_models, options) {
+ this.database = options.database;
+ this.params = _.extend({limit: 20, reduce: false}, options.params);
+
+ this.idxType = "_view";
+ this.view = options.view;
+ this.design = options.design.replace('_design/','');
+ this.perPageLimit = options.perPageLimit || 20;
+
+ if (!this.params.limit) {
+ this.params.limit = this.perPageLimit;
+ }
+ },
+
+ urlRef: function(context, params) {
+ var query = "";
+
+ if (params) {
+ if (!_.isEmpty(params)) {
+ query = "?" + $.param(params);
+ } else {
+ query = '';
+ }
+ } else if (this.params) {
+ var parsedParam = Resources.QueryParams.stringify(this.params);
+ query = "?" + $.param(parsedParam);
+ }
+
+ var startOfUrl = app.host;
+ if (context === 'app') {
+ startOfUrl = 'database';
+ } else if (context === "apiurl"){
+ startOfUrl = window.location.origin;
+ }
+ var design = app.utils.safeURLName(this.design),
+ view = app.utils.safeURLName(this.view);
+
+ var url = [startOfUrl, this.database.safeID(), "_design", design, this.idxType, view];
+ return url.join("/") + query;
+ },
+
+ url: function () {
+ return this.urlRef.apply(this, arguments);
+ },
+
+ totalRows: function() {
+ if (this.params.reduce) { return "unknown_reduce";}
+
+ return this.viewMeta.total_rows || "unknown";
+ },
+
+ updateSeq: function() {
+ return this.viewMeta.update_seq || false;
+ },
+
+ simple: function () {
+ var docs = this.map(function (item) {
+ return {
+ _id: item.id,
+ key: item.get('key'),
+ value: item.get('value')
+ };
+ });
+
+ return new Resources.IndexCollection(docs, {
+ database: this.database,
+ params: this.params,
+ view: this.view,
+ design: this.design
+ });
+ },
+
+ parse: function(resp) {
+ var rows = resp.rows;
+ this.endTime = new Date().getTime();
+ this.requestDuration = (this.endTime - this.startTime);
+
+ return PagingCollection.prototype.parse.apply(this, arguments);
+ },
+
+ buildAllDocs: function(){
+ this.fetch();
+ },
+
+ // We implement our own fetch to store the starttime so we that
+ // we can get the request duration
+ fetch: function () {
+ this.startTime = new Date().getTime();
+ return PagingCollection.prototype.fetch.call(this);
+ },
+
+ allDocs: function(){
+ return this.models;
+ },
+
+ // This is taken from futon.browse.js $.timeString
+ requestDurationInString: function () {
+ var ms, sec, min, h, timeString, milliseconds = this.requestDuration;
+
+ sec = Math.floor(milliseconds / 1000.0);
+ min = Math.floor(sec / 60.0);
+ sec = (sec % 60.0).toString();
+ if (sec.length < 2) {
+ sec = "0" + sec;
+ }
+
+ h = (Math.floor(min / 60.0)).toString();
+ if (h.length < 2) {
+ h = "0" + h;
+ }
+
+ min = (min % 60.0).toString();
+ if (min.length < 2) {
+ min = "0" + min;
+ }
+
+ timeString = h + ":" + min + ":" + sec;
+
+ ms = (milliseconds % 1000.0).toString();
+ while (ms.length < 3) {
+ ms = "0" + ms;
+ }
+ timeString += "." + ms;
+
+ return timeString;
+ }
+
+ });
+
+ return Resources;
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/app/addons/indexes/routes-core.js
----------------------------------------------------------------------
diff --git a/app/addons/indexes/routes-core.js b/app/addons/indexes/routes-core.js
new file mode 100644
index 0000000..1277c6b
--- /dev/null
+++ b/app/addons/indexes/routes-core.js
@@ -0,0 +1,224 @@
+// 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 CoreIndexRouteObj = FauxtonAPI.RouteObject.extend({
+ layout: "two_pane",
+
+ initialize: function (route, masterLayout, options) {
+ _.bindAll(this);
+ var params = this.createParams(),
+ urlParams = params.urlParams,
+ docParams = params.docParams;
+
+ 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
+ }
+ });
+
+
+ /* --------------------------------------------------
+ Set up right header
+ ----------------------------------------------------*/
+
+ this.rightHeader = this.setView("#api-navbar", new Views.RightHeader({
+ database: this.data.database,
+ model: this.data.database,
+ endpoint: this.data.designDocs.urlRef("apiurl", urlParams),
+ documentation: "docs"
+ }));
+
+ },
+
+ events: {
+ "route:perPageChange": "perPageChange",
+ "route:paginate": "paginate",
+ "route:updateAllDocs": "updateAllDocsFromView"
+ },
+
+ /* --------------------------------------------------
+ Called when you change the # of items to show in the pagination footer
+ ----------------------------------------------------*/
+ perPageChange: function (perPage) {
+ // We need to restore the collection parameters to the defaults (1st page)
+ // and update the page size
+ this.perPage = perPage;
+ this.documentsView.forceRender();
+ this.documentsView.collection.pageSizeReset(perPage, {fetch: false});
+ this.setDocPerPageLimit(perPage);
+ },
+
+ /* --------------------------------------------------
+ Store the docs to show per page in local storage
+ ----------------------------------------------------*/
+ setDocPerPageLimit: function (perPage) {
+ window.localStorage.setItem('fauxton:perpage', perPage);
+ },
+
+ /* --------------------------------------------------
+ Triggers when you hit the paginate forward and backwards buttons
+ ----------------------------------------------------*/
+
+ paginate: function (options) {
+ var collection = this.documentsView.collection;
+
+ this.documentsView.forceRender();
+ collection.paging.pageSize = options.perPage;
+ var promise = collection[options.direction]({fetch: false});
+ },
+
+ /* --------------------------------------------------
+ Get Design doc info
+ ----------------------------------------------------*/
+ ddocInfo: function (designDoc, designDocs, view) {
+ return {
+ id: "_design/" + designDoc,
+ currView: view,
+ designDocs: designDocs
+ };
+ },
+
+ /* --------------------------------------------------
+ URL params from Advanced/ Query options
+ ----------------------------------------------------*/
+ 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)})
+ };
+ },
+
+ /* --------------------------------------------------
+ determines how many docs to display for the request
+ ----------------------------------------------------*/
+ 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});
+ },
+
+
+ /* --------------------------------------------------
+ Reload preview docs
+ -----------------------------------------------------*/
+ updateAllDocsFromView: function (event) {
+ var view = event.view,
+ params = this.createParams(),
+ urlParams = params.urlParams,
+ docParams = params.docParams,
+ ddoc = event.ddoc,
+ pageSize,
+ collection;
+
+ var defaultPageSize = _.isUndefined(this.documentsView) ? 20 : this.documentsView.perPage();
+ docParams.limit = pageSize = this.getDocPerPageLimit(urlParams, defaultPageSize);
+
+ if (event.allDocs) {
+ this.eventAllDocs = true; // this is horrible. But I cannot get the trigger not to fire the route!
+ this.data.database.buildAllDocs(docParams);
+ collection = this.data.database.allDocs;
+ collection.paging.pageSize = pageSize;
+
+ } else {
+ collection = this.data.indexedDocs = new Resources.IndexCollection(null, {
+ database: this.data.database,
+ design: ddoc,
+ view: view,
+ params: docParams,
+ paging: {
+ pageSize: pageSize
+ }
+ });
+
+ if (!this.documentsView) {
+ this.documentsView = this.createViewDocumentsView({
+ designDoc: ddoc,
+ docParams: docParams,
+ urlParams: urlParams,
+ database: this.data.database,
+ indexedDocs: this.indexedDocs,
+ designDocs: this.data.designDocs,
+ view: view
+ });
+ }
+ }
+
+ this.documentsView.setCollection(collection);
+ this.documentsView.setParams(docParams, urlParams);
+
+ this.documentsView.forceRender();
+ },
+
+ /* --------------------------------------------------
+ Docs that are returned from a view
+ ----------------------------------------------------*/
+ createViewDocumentsView: function (options) {
+ return this.setView("#right-content", new Documents.Views.AllDocsList({
+ database: options.database,
+ collection: options.indexedDocs,
+ nestedView: Views.Row,
+ viewList: true,
+ ddocInfo: this.ddocInfo(options.designDoc, options.designDocs, options.view),
+ docParams: options.docParams,
+ params: options.urlParams
+ }));
+ }
+ });
+
+ return CoreIndexRouteObj;
+
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/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..437cef6
--- /dev/null
+++ b/app/addons/indexes/routes-list.js
@@ -0,0 +1,108 @@
+// 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",
+ "addons/indexes/routes-core",
+ "addons/fauxton/components"
+],
+
+function (app, FauxtonAPI, Databases, Views, Documents, Resources, RouteCore, Components) {
+
+ var ListIndexes = RouteCore.extend({
+ routes: {
+ "database/:database/_design/:ddoc/_lists/:fn": {
+ route: "tempFn",
+ roles: ['_admin']
+ },
+ "database/:database/new_list": "newListsEditor",
+ "database/:database/new_list/:designDoc": "newListsEditor"
+ },
+
+ apiUrl: function() {
+ //TODO: Hook up proper API urls
+ return '';
+ },
+
+ newListsEditor: function (database, designDoc) {
+ var params = app.getParams();
+
+ /* --------------------------------------------------
+ Insert View Editor for new list
+ ----------------------------------------------------*/
+ this.setView("#left-content", new Views.ListEditor({
+ model: this.data.database,
+ currentddoc: designDoc ? "_design/"+designDoc : "",
+ ddocs: this.data.designDocs,
+ params: params,
+ database: this.data.database,
+ newView: true
+ }));
+ /* --------------------------------------------------
+ Insert Preview Screen View
+ ----------------------------------------------------*/
+ this.setView("#right-content", new Views.PreviewScreen({}));
+
+ /* --------------------------------------------------
+ Set up & Insert breadcrumb header
+ ----------------------------------------------------*/
+ var crumbs = [
+ {"name": "", "className": "fonticon-left-open", "link": Databases.databaseUrl(this.data.database)},
+ {"name": "Create a List Index", "link": Databases.databaseUrl(this.data.database)}
+ ];
+ this.leftheader = this.setView("#breadcrumbs", new Components.LeftHeader({
+ crumbs: crumbs
+ }));
+ },
+ tempFn: function(databaseName, ddoc, view){
+ /* --------------------------------------------------
+ Set up breadcrumb header
+ ----------------------------------------------------*/
+ var crumbs = [
+ {"name": "", "className": "fonticon-left-open", "link": Databases.databaseUrl(this.data.database)},
+ {"name": view, "link": Databases.databaseUrl(this.data.database)}
+ ];
+
+ var dropdown = [{
+ links: [{
+ title: 'Duplicate Index',
+ icon: 'fonticon-documents'
+ },{
+ title: 'Delete',
+ icon: 'fonticon-trash'
+ }]
+ }];
+
+ this.leftheader = this.setView("#breadcrumbs", new Components.LeftHeader({
+ crumbs: crumbs,
+ dropdownMenu: dropdown
+ }));
+
+
+ /* --------------------------------------------------
+ Insert List Editor
+ ----------------------------------------------------*/
+ this.setView("#left-content", new Views.ListEditor({}));
+
+ /* --------------------------------------------------
+ Insert Preview Screen View
+ ----------------------------------------------------*/
+ this.setView("#right-content", new Views.PreviewScreen({}));
+ }
+ });
+
+ return ListIndexes;
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/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..73f52d1
--- /dev/null
+++ b/app/addons/indexes/routes-show.js
@@ -0,0 +1,103 @@
+// 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",
+ "addons/indexes/routes-core",
+ "addons/fauxton/components"
+],
+
+function (app, FauxtonAPI, Databases, Views, Documents, Resources, RouteCore, Components) {
+
+ var ShowIndexes = RouteCore.extend({
+ routes: {
+ "database/:database/_design/:ddoc/_show/:fn": {
+ route: "tempFn",
+ roles: ['_admin']
+ },
+ "database/:database/new_show": "newShowEditor",
+ "database/:database/new_show/:designDoc": "newShowEditor"
+ },
+
+ newShowEditor: function (database, designDoc) {
+ var params = app.getParams();
+ /* --------------------------------------------------
+ Insert View Editor for new view
+ ----------------------------------------------------*/
+ this.setView("#left-content", new Views.ShowEditor({
+ model: this.data.database,
+ currentddoc: designDoc ? "_design/"+designDoc : "",
+ ddocs: this.data.designDocs,
+ params: params,
+ database: this.data.database,
+ newView: true
+ }));
+
+ /* --------------------------------------------------
+ Insert Preview Screen View
+ ----------------------------------------------------*/
+ this.setView("#right-content", new Views.PreviewScreen({}));
+
+ /* --------------------------------------------------
+ Set up & Insert breadcrumb header
+ ----------------------------------------------------*/
+ var crumbs = [
+ {"name": "", "className": "fonticon-left-open", "link": Databases.databaseUrl(this.data.database)},
+ {"name": "Create a Show Index", "link": Databases.databaseUrl(this.data.database)}
+ ];
+ this.leftheader = this.setView("#breadcrumbs", new Components.LeftHeader({
+ crumbs: crumbs
+ }));
+ },
+ tempFn: function(databaseName, ddoc, view){
+ /* --------------------------------------------------
+ Set up breadcrumb header
+ ----------------------------------------------------*/
+ var crumbs = [
+ {"name": "", "className": "fonticon-left-open", "link": Databases.databaseUrl(this.data.database)},
+ {"name": view, "link": Databases.databaseUrl(this.data.database)}
+ ];
+
+ var dropdown = [{
+ links: [{
+ title: 'Duplicate Index',
+ icon: 'fonticon-documents'
+ },{
+ title: 'Delete',
+ icon: 'fonticon-trash'
+ }]
+ }];
+
+ this.leftheader = this.setView("#breadcrumbs", new Components.LeftHeader({
+ crumbs: crumbs,
+ dropdownMenu: dropdown
+ }));
+
+
+ /* --------------------------------------------------
+ Insert Show Editor
+ ----------------------------------------------------*/
+ this.setView("#left-content", new Views.ListEditor({}));
+
+ /* --------------------------------------------------
+ Insert Preview Screen View
+ ----------------------------------------------------*/
+ this.setView("#right-content", new Views.PreviewScreen({}));
+ }
+ });
+
+ return ShowIndexes;
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/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..663e0e8
--- /dev/null
+++ b/app/addons/indexes/routes-viewindexes.js
@@ -0,0 +1,144 @@
+// 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",
+ "addons/indexes/routes-core",
+ "addons/fauxton/components"
+],
+
+function (app, FauxtonAPI, Databases, Views, Documents, Resources, RouteCore, Components) {
+
+ var ViewIndexes = RouteCore.extend({
+ routes: {
+ "database/:database/_design/:ddoc/_view/:view": {
+ route: "viewFn",
+ roles: ['_admin']
+ },
+ "database/:database/new_view": "newViewEditor",
+ "database/:database/new_view/:designDoc": "newViewEditor"
+ },
+
+ newViewEditor: function (database, designDoc) {
+ var params = app.getParams();
+ /* --------------------------------------------------
+ remove right header
+ ----------------------------------------------------*/
+ this.rightHeader && this.rightHeader.remove();
+
+ /* --------------------------------------------------
+ Insert Preview Screen View
+ ----------------------------------------------------*/
+ this.setView("#right-content", new Views.PreviewScreen({}));
+
+ /* --------------------------------------------------
+ Insert View Editor for new view
+ ----------------------------------------------------*/
+ this.viewEditor = this.setView("#left-content", new Views.ViewEditor({
+ model: this.data.database,
+ currentddoc: designDoc ? "_design/"+designDoc : "",
+ ddocs: this.data.designDocs,
+ params: params,
+ database: this.data.database,
+ newView: true
+ }));
+
+ /* --------------------------------------------------
+ Set up & Insert breadcrumb header
+ ----------------------------------------------------*/
+ var crumbs = [
+ {"name": "", "className": "fonticon-left-open", "link": Databases.databaseUrl(this.data.database)},
+ {"name": "Create a View Index", "link": Databases.databaseUrl(this.data.database)}
+ ];
+ this.leftheader = this.setView("#breadcrumbs", new Components.LeftHeader({
+ crumbs: crumbs
+ }));
+
+ },
+
+ viewFn: function (databaseName, ddoc, view) {
+ var params = this.createParams(),
+ urlParams = params.urlParams,
+ docParams = params.docParams,
+ decodeDdoc = decodeURIComponent(ddoc);
+ view = view.replace(/\?.*$/,'');
+
+ /* --------------------------------------------------
+ Set up breadcrumb header
+ ----------------------------------------------------*/
+ var crumbs = [
+ {"name": "", "className": "fonticon-left-open", "link": Databases.databaseUrl(this.data.database)},
+ {"name": view, "link": Databases.databaseUrl(this.data.database)}
+ ];
+
+ var dropdown = [{
+ links: [
+ {
+ title: 'Delete',
+ icon: 'fonticon-trash',
+ trigger: 'index:delete'
+ }]
+ }];
+
+ this.leftheader = this.setView("#breadcrumbs", new Components.LeftHeader({
+ crumbs: crumbs,
+ dropdownMenu: dropdown
+ }));
+
+ /* --------------------------------------------------
+ Set up Index Collection
+ ----------------------------------------------------*/
+ this.data.indexedDocs = new Resources.IndexCollection(null, {
+ database: this.data.database,
+ design: decodeDdoc,
+ view: view,
+ params: docParams,
+ paging: {
+ pageSize: this.getDocPerPageLimit(urlParams, parseInt(docParams.limit, 10))
+ }
+ });
+
+
+ /* --------------------------------------------------
+ Insert View Editor
+ ----------------------------------------------------*/
+ 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)
+ }));
+
+ /* --------------------------------------------------
+ Insert Docs returned from view
+ ----------------------------------------------------*/
+ this.documentsView = this.createViewDocumentsView({
+ designDoc: decodeDdoc,
+ docParams: docParams,
+ urlParams: urlParams,
+ database: this.data.database,
+ indexedDocs: this.data.indexedDocs,
+ designDocs: this.data.designDocs,
+ view: view
+ });
+ }
+ });
+
+ return ViewIndexes;
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/app/addons/indexes/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/indexes/routes.js b/app/addons/indexes/routes.js
new file mode 100644
index 0000000..90c9aac
--- /dev/null
+++ b/app/addons/indexes/routes.js
@@ -0,0 +1,24 @@
+// 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/indexes/views",
+ "addons/indexes/routes-viewindexes",
+ "addons/indexes/routes-show",
+ "addons/indexes/routes-list",
+],
+
+function (app, FauxtonAPI, Views, ViewIndex, Show, List) {
+ Views.RouteObjects = [ViewIndex, Show, List];
+ return Views;
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/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..2cad6af
--- /dev/null
+++ b/app/addons/indexes/templates/design_doc_selector.html
@@ -0,0 +1,34 @@
+<!--
+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.
+-->
+<label for="ddoc">Save to Design Document <a class="help-link" data-bypass="true" href="<%-getDocUrl('design_doc')%>" target="_blank"><i class="icon-question-sign"></i></a></label>
+<div class="row-fluid new-ddoc">
+ <div class="select-wrapper span5">
+ <select id="ddoc">
+ <optgroup label="Select a document">
+ <option value="new-doc" <% if(newView){ %>selected="selected" <%}%> >New document</option>
+
+ <% ddocs.each(function(ddoc) { %>
+ <% if (ddoc.id === ddocName && !newView) { %>
+ <option selected="selected" value="<%- ddoc.id %>"><%- ddoc.id %></option>
+ <% } else { %>
+ <option value="<%- ddoc.id %>"><%- ddoc.id %></option>
+ <% } %>
+ <% }); %>
+ </optgroup>
+ </select>
+ <i></i>
+ </div>
+
+ <input type="text" id="new-ddoc" class="span7" <% if(!newView){ %> style="display:none"<% } %> placeholder="Enter a design doc name" />
+</div>
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/app/addons/indexes/templates/header_right.html
----------------------------------------------------------------------
diff --git a/app/addons/indexes/templates/header_right.html b/app/addons/indexes/templates/header_right.html
new file mode 100644
index 0000000..2fba038
--- /dev/null
+++ b/app/addons/indexes/templates/header_right.html
@@ -0,0 +1,23 @@
+<!--
+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.
+-->
+ <!-- Select toggle-->
+ <div id="header-api-bar" class="button"></div>
+
+ <!-- Query Options-->
+ <div class="button header-query-options">
+ <!-- Insert the query options here :) -->
+ <div id="query-options"></div>
+ </div>
+
+
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/app/addons/indexes/templates/index_row_docular.html
----------------------------------------------------------------------
diff --git a/app/addons/indexes/templates/index_row_docular.html b/app/addons/indexes/templates/index_row_docular.html
new file mode 100644
index 0000000..ba88d06
--- /dev/null
+++ b/app/addons/indexes/templates/index_row_docular.html
@@ -0,0 +1,35 @@
+<!--
+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.
+-->
+<% if (doc.isEditable()) { %>
+ <div class="select"><input type="checkbox"></div>
+<% } %>
+
+<div class="doc-item">
+ <header>
+ _id <span class="header-id-number">"<%=docID%>"</span>
+
+ <div class="doc-menu">
+ <a href="#<%= url %>" class="doc-menu-item icon fonticon-pencil"></a>
+ <% if (doc.isEditable()) { %>
+ <button href="#" class="btn btn-small btn-danger delete" title="Delete this document."><i class="icon icon-trash"></i></button>
+ <% } %>
+
+ <div id="view-doc-menu" class="doc-menu-item"></div>
+ </div>
+ </header>
+ <div class="doc-data">
+ <pre class="prettyprint"><%- doc.prettyJSON() %></pre>
+ </div>
+</div>
+<div class="clearfix"></div>
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/app/addons/indexes/templates/list_editor.html
----------------------------------------------------------------------
diff --git a/app/addons/indexes/templates/list_editor.html b/app/addons/indexes/templates/list_editor.html
new file mode 100644
index 0000000..8644909
--- /dev/null
+++ b/app/addons/indexes/templates/list_editor.html
@@ -0,0 +1,18 @@
+<!--
+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.
+-->
+
+<form>
+ <label> A FORM</label>
+
+</form>
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/app/addons/indexes/templates/preview_screen.html
----------------------------------------------------------------------
diff --git a/app/addons/indexes/templates/preview_screen.html b/app/addons/indexes/templates/preview_screen.html
new file mode 100644
index 0000000..a7de45b
--- /dev/null
+++ b/app/addons/indexes/templates/preview_screen.html
@@ -0,0 +1,18 @@
+<!--
+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.
+-->
+
+<h3>No Index Created Yet!</h3>
+<!--
+<p> Run <a href="#/preview" class="btn btn-success save"> Preview</a> To query result</p>
+-->
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/app/addons/indexes/templates/show_editor.html
----------------------------------------------------------------------
diff --git a/app/addons/indexes/templates/show_editor.html b/app/addons/indexes/templates/show_editor.html
new file mode 100644
index 0000000..ef36110
--- /dev/null
+++ b/app/addons/indexes/templates/show_editor.html
@@ -0,0 +1,41 @@
+<!--
+Licensed under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
+-->
+
+<div class="all-docs-list errors-container"></div>
+<div id="define-view" class="ddoc-alert index-form">
+ <div class="errors-container"></div>
+ <form class="form-horizontal view-query-save">
+ <div class="control-group">
+ <p>Views are the primary tool used for querying and reporting.</p>
+ </div>
+
+ <div class="control-group design-doc-group">
+ </div>
+
+
+ <div class="control-group">
+ <label for="index-name">Index name <a class="help-link" href="<%-getDocUrl('view_functions')%>" target="_blank"><i class="icon-question-sign"></i></a></label>
+ <input type="text" id="index-name" value="<%- viewName %>" placeholder="Index name" />
+ </div>
+
+
+ <div class="control-group">
+ <button class="btn btn-success save"><i class="icon fonticon-ok-circled"></i> Save & Build Index</button>
+ <% if (!newView) { %>
+ <button class="btn btn-danger delete"><i class="icon fonticon-cancel-circled"></i> Delete</button>
+ <% } %>
+ </div>
+ <div class="clearfix"></div>
+ </form>
+</div>=
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/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..2b8c540
--- /dev/null
+++ b/app/addons/indexes/templates/view_editor.html
@@ -0,0 +1,80 @@
+<!--
+Licensed under the Apache License, Version 2.0 (the "License"); you may not
+use this file except in compliance with the License. You may obtain a copy of
+the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+License for the specific language governing permissions and limitations under
+the License.
+-->
+<div class="all-docs-list errors-container"></div>
+<div id="define-view" class="ddoc-alert index-form">
+ <div class="errors-container"></div>
+ <form class="form-horizontal view-query-save">
+ <div class="control-group">
+ <p>Views are the primary tool used for querying and reporting.</p>
+ </div>
+
+
+ <div class="control-group">
+ <label for="index-name">Database name</label>
+ <p><%- database %></p>
+ </div>
+
+
+ <div class="control-group design-doc-group">
+ </div>
+
+
+ <div class="control-group">
+ <label for="index-name">Index name <a class="help-link" href="<%-getDocUrl('view_functions')%>" target="_blank"><i class="icon-question-sign"></i></a></label>
+ <input type="text" id="index-name" value="<%- viewName %>" placeholder="Index name" />
+ </div>
+
+ <div class="control-group">
+ <label for="map-function">Map function <a class="help-link" href="<%-getDocUrl('map_functions')%>" target="_blank"><i class="icon-question-sign"></i></a></label>
+ <% if (newView) { %>
+ <div class="js-editor" id="map-function"><%= langTemplates.map %></div>
+ <% } else { %>
+ <div class="js-editor" id="map-function"><%- ddoc.get('views')[viewName].map %></div>
+ <button class="beautify beautify_map btn btn-primary btn-large hide beautify-tooltip" type="button" data-toggle="tooltip" title="Reformat your minified code to make edits to it.">beautify this code</button>
+ <% } %>
+ </div>
+
+
+ <div class="control-group">
+ <label for="reduce-function-selector">Reduce (optional) <a class="help-link" href="<%-getDocUrl('reduce_functions')%>" target="_blank"><i class="icon-question-sign"></i></a></label>
+
+ <select id="reduce-function-selector">
+ <option value="" <%- !reduceFunStr ? 'selected="selected"' : '' %>>None</option>
+ <% _.each(["_sum", "_count", "_stats"], function(reduce) { %>
+ <option value="<%- reduce %>" <% if (reduce == reduceFunStr) { %>selected<% } %>><%= reduce %></option>
+ <% }) %>
+ <option value="CUSTOM" <% if (isCustomReduce) { %>selected<% } %>>Custom Reduce function</option>
+ </select>
+ </div>
+
+ <div class="control-group reduce-function">
+ <label for="reduce-function">Custom Reduce function</label>
+ <% if (newView) { %>
+ <div class="js-editor" id="reduce-function"><%- langTemplates.reduce %></div>
+ <% } else { %>
+ <div class="js-editor" id="reduce-function"><%- ddoc.get('views')[viewName].reduce %></div>
+ <button class="beautify beautify_reduce btn btn-primary btn-large hide beautify-tooltip" type="button" data-toggle="tooltip" title="Reformat your minified code to make edits to it.">beautify this code</button>
+ <% } %>
+ </div>
+
+ <div class="control-group">
+ <button class="btn btn-success save"><i class="icon fonticon-ok-circled"></i> Save & Build Index</button>
+ <% if (!newView) { %>
+ <button class="btn btn-danger delete"><i class="icon fonticon-cancel-circled"></i> Delete</button>
+ <% } %>
+ </div>
+ <div class="clearfix"></div>
+ </form>
+</div>
+
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/fc1eb5c8/app/addons/indexes/views.js
----------------------------------------------------------------------
diff --git a/app/addons/indexes/views.js b/app/addons/indexes/views.js
new file mode 100644
index 0000000..a0d5d0d
--- /dev/null
+++ b/app/addons/indexes/views.js
@@ -0,0 +1,653 @@
+// 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 = {};
+
+
+//right header
+ Views.RightHeader = FauxtonAPI.View.extend({
+ className: "header-right",
+ template: "addons/indexes/templates/header_right",
+ initialize:function(options){
+ _.bindAll(this);
+ this.database = options.database;
+ this.title = options.title;
+ this.api = options.api;
+ this.endpoint = options.endpoint;
+ this.documentation = options.documentation;
+ FauxtonAPI.Events.on('advancedOptions:updateView', this.updateView);
+ },
+ updateApiUrl: function(api){
+ //this will update the api bar when the route changes
+ //you can find the method that updates it in components.js Components.ApiBar()
+ this.apiBar && this.apiBar.update(api);
+ },
+ beforeRender: function(){
+
+ this.apiBar = this.insertView("#header-api-bar", new Components.ApiBar({
+ endpoint: this.endpoint,
+ documentation: this.documentation
+ }));
+
+ this.advancedOptions = this.insertView('#query-options', new QueryOptions.AdvancedOptions({
+ database: this.database,
+ viewName: this.viewName,
+ ddocName: this.model.id,
+ hasReduce: this.hasReduce(),
+ showStale: true
+ }));
+ },
+
+ cleanup: function(){
+ FauxtonAPI.Events.unbind('advancedOptions:updateView');
+ },
+
+ hasReduce: function(){
+
+ },
+ updateView: function(event, paramInfo) {
+ event.preventDefault();
+
+ var errorParams = paramInfo.errorParams,
+ params = paramInfo.params;
+
+ if (_.any(errorParams)) {
+ _.map(errorParams, function(param) {
+ return FauxtonAPI.addNotification({
+ msg: "JSON Parse Error on field: "+param.name,
+ type: "error",
+ clear: true
+ });
+ });
+ FauxtonAPI.addNotification({
+ msg: "Make sure that strings are properly quoted and any other values are valid JSON structures",
+ type: "warning",
+ 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});
+ }
+ });
+
+
+
+
+ Views.PreviewScreen = FauxtonAPI.View.extend({
+ template: "addons/indexes/templates/preview_screen",
+ className: "watermark-logo"
+ });
+
+
+ Views.Row = FauxtonAPI.View.extend({
+ template: "addons/indexes/templates/index_row_docular",
+ className: "doc-row",
+ events: {
+ "click button.delete": "destroy"
+ },
+
+ destroy: function (event) {
+ event.preventDefault();
+
+ window.alert('Cannot delete a document generated from a view.');
+ },
+
+ beforeRender: function(){
+ var newLinks = [{
+ links: [{
+ title: 'JSON',
+ icon: 'fonticon-json'
+ }]
+ }];
+
+ this.insertView("#view-doc-menu", new Components.MenuDropDown({
+ icon: 'fonticon-drop-down-dots',
+ links: newLinks,
+ }));
+ },
+
+ serialize: function() {
+ return {
+ docID: this.model.get('id'),
+ doc: this.model,
+ url: this.model.url('app')
+ };
+ }
+ });
+
+
+/*
+
+ INDEX EDITORS____________________________________
+
+*/
+
+ //Index view CORE extend this
+ Views.IndexCore = FauxtonAPI.View.extend({
+ 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 ? 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();
+ }
+ },
+ serialize: function() {
+ return {
+ database: this.database.get('id'),
+ ddocs: this.ddocs,
+ ddoc: this.model,
+ ddocName: this.model.id,
+ viewName: this.viewName,
+ newView: this.newView,
+ langTemplates: this.langTemplates.javascript
+ };
+ }
+ });
+
+ Views.ShowEditor = Views.IndexCore.extend({
+ template: "addons/indexes/templates/show_editor",
+ langTemplates: {
+ "javascript": {
+ map: "function(doc) {\n emit(doc._id, 1);\n}",
+ }
+ },
+ defaultLang: "javascript"
+ });
+
+ Views.ListEditor = Views.IndexCore.extend({
+ template: "addons/indexes/templates/list_editor",
+ langTemplates: {
+ "javascript": {
+ map: "function(doc) {\n emit(doc._id, 1);\n}",
+ }
+ },
+ defaultLang: "javascript"
+ });
+
+
+ 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 #db-views-tabs-nav": 'toggleIndexNav',
+ "click .beautify_map": "beautifyCode",
+ "click .beautify_reduce": "beautifyCode"
+ },
+
+ 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);
+
+ FauxtonAPI.Events.on('index:delete', this.deleteEvent);
+ },
+
+ 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();
+ }
+ },
+
+ deleteEvent: function(){
+ this.deleteView();
+ },
+
+ deleteView: function (event) {
+ 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
+ //check if the code is valid & the inputs are filled out
+ 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;
+ this.viewNameChange = false;
+
+
+ if (this.viewName !== viewName) {
+ ddoc.removeDdocView(this.viewName);
+ this.viewName = viewName;
+ this.viewNameChange = true;
+ }
+
+ notification = FauxtonAPI.addNotification({
+ msg: "Saving document.",
+ clear: true
+ });
+
+ ddoc.setDdocView(viewName, mapVal, reduceVal);
+
+ ddoc.save().then(function () {
+ //on success
+ that.afterSave(ddoc, viewName, ddocName);
+ },
+ function(xhr) {
+ //on failure
+ var responseText = JSON.parse(xhr.responseText).reason;
+ notification = FauxtonAPI.addNotification({
+ msg: "Save failed: " + responseText,
+ type: "error",
+ clear: true
+ });
+ });
+ } else {
+ //if nothing is filled out give an error message
+ 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",
+ clear: true
+ });
+ }
+ },
+
+ afterSave: function(ddoc, viewName, ddocName){
+ var reduceVal = this.reduceVal();
+ //add ddoc to the collection
+ this.ddocs.add(ddoc);
+
+ //trigger the EditSaved function on the map editor & reduce editor
+ this.mapEditor.editSaved();
+ this.reduceEditor && this.reduceEditor.editSaved();
+
+
+ //show a notification
+ FauxtonAPI.addNotification({
+ msg: "View has been saved.",
+ type: "success",
+ clear: true
+ });
+
+
+ //if it's new or the name changed (aka created a new doc)
+ if (this.newView || this.viewNameChange) {
+ var fragment = '/database/' + this.database.safeID() +'/' + ddoc.safeID() + '/_view/' + app.utils.safeURLName(viewName);
+
+ FauxtonAPI.navigate(fragment, {trigger: false});
+ this.newView = false;
+ this.ddocID = ddoc.safeID();
+ this.viewName = viewName;
+ this.ddocInfo = ddoc;
+ this.showIndex = true;
+ this.render();
+ }
+
+ // TODO:// this should change to a trigger because we shouldn't define advanced options in this view
+ if (this.reduceFunStr !== reduceVal) {
+ this.reduceFunStr = reduceVal;
+ // this.advancedOptions.renderOnUpdatehasReduce(this.hasReduce());
+ }
+
+ // Route Event will reload the right content
+ FauxtonAPI.triggerRouteEvent('updateAllDocs', {ddoc: ddocName, view: 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);
+ },
+
+
+ serialize: function() {
+ return {
+ database: this.database.get('id'),
+ 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,
+ newView: this.newView,
+ ddocName: this.currentDdoc || this.model.id,
+ database: this.database
+ }));
+
+ },
+
+ afterRender: function() {
+ //TODO: have this happen on a trigger once we move advanced options to the header
+ // if (this.params && !this.newView) {
+ // this.advancedOptions.updateFromParams(this.params);
+ // }
+
+ this.designDocSelector.updateDesignDoc();
+ this.showEditors();
+ this.showIndex = false;
+
+ },
+
+ 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 () {
+ FauxtonAPI.Events.unbind('index:delete');
+ 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.newView = options.newView;
+ 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 {
+ newView: this.newView,
+ ddocName: this.ddocName,
+ ddocs: this.collection
+ };
+ },
+
+ updateDesignDoc: function () {
+ if (this.newDesignDoc()) {
+ this.$('#new-ddoc').show();
+ } else {
+ this.$('#new-ddoc').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;
+});