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 13C5C11DDF for ; Mon, 4 Aug 2014 13:10:42 +0000 (UTC) Received: (qmail 63451 invoked by uid 500); 4 Aug 2014 13:10:41 -0000 Delivered-To: apmail-couchdb-commits-archive@couchdb.apache.org Received: (qmail 63308 invoked by uid 500); 4 Aug 2014 13:10:41 -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 62988 invoked by uid 99); 4 Aug 2014 13:10:41 -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, 04 Aug 2014 13:10:41 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 6515D889738; Mon, 4 Aug 2014 13:10:41 +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, 04 Aug 2014 13:10:48 -0000 Message-Id: <4ba2676003e448768c0c4e966c49b85d@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [8/9] buncha editor stuff making the preview page look less butts. Styling the view form documents This stuff can't be tables. Boo. less for indexes resize stuff And more refactor stuff View editor updates, Splitting out less files An absolute abortion h http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/bcc6dc21/app/addons/indexes/index-components.js ---------------------------------------------------------------------- diff --git a/app/addons/indexes/index-components.js b/app/addons/indexes/index-components.js new file mode 100644 index 0000000..1ec34e2 --- /dev/null +++ b/app/addons/indexes/index-components.js @@ -0,0 +1,30 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + + +/* + Index components includes any common, generic, and reusable code for creating secondary indexes + View functions, List functions, Show Functions, and Filter functions, as well as anything created by + couchdb affiliates. +*/ + +define([ + "app", + "api" +], + +function(app, FauxtonAPI) { + var Components = {}; + + + return Components; +}); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/bcc6dc21/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..626d984 --- /dev/null +++ b/app/addons/indexes/resources.js @@ -0,0 +1,285 @@ +// 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.PouchIndexCollection = PagingCollection.extend({ + model: Resources.ViewRow, + documentation: function(){ + return "docs"; + }, + initialize: function(_models, options) { + this.database = options.database; + this.rows = options.rows; + this.view = options.view; + this.design = options.design.replace('_design/',''); + this.params = _.extend({limit: 20, reduce: false}, options.params); + + this.idxType = "_view"; + }, + + url: function () { + return ''; + }, + + simple: function () { + var docs = this.map(function (item) { + return { + _id: item.id, + key: item.get('key'), + value: item.get('value') + }; + }); + + return new Resources.PouchIndexCollection(docs, { + database: this.database, + params: this.params, + view: this.view, + design: this.design, + rows: this.rows + }); + + }, + + fetch: function() { + var deferred = FauxtonAPI.Deferred(); + this.reset(this.rows, {silent: true}); + + this.viewMeta = { + total_rows: this.rows.length, + offset: 0, + update_seq: false + }; + + deferred.resolve(); + return deferred; + }, + + totalRows: function() { + return this.viewMeta.total_rows || "unknown"; + }, + + updateSeq: function() { + return this.viewMeta.update_seq || false; + }, + + buildAllDocs: function(){ + this.fetch(); + }, + + allDocs: function(){ + return this.models; + } + }); + + + 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/bcc6dc21/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..354afb0 --- /dev/null +++ b/app/addons/indexes/routes-core.js @@ -0,0 +1,129 @@ +// 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) { + 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 + } + }); + }, + + events: { + "route:updatePreviewDocs": "updateAllDocsFromPreview" + }, + + 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}); + }, + + 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 + })); + }, + + 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("#right-content", new Documents.Views.AllDocsList({ + database: this.data.database, + collection: this.data.indexedDocs, + nestedView: Views.Row, + viewList: true + })); + } + }); + + return CoreIndexRouteObj; + +}); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/bcc6dc21/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..e7a2282 --- /dev/null +++ b/app/addons/indexes/routes-list.js @@ -0,0 +1,70 @@ +// 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" +], + +function (app, FauxtonAPI, Databases, Views, Documents, Resources, RouteCore) { + + var ListIndexes = RouteCore.extend({ + routes: { + "database/:database/_design/:ddoc/_lists/:fn": { + route: "tempFn", + roles: ['_admin'] + }, + "database/:database/new_list": "newListsEditor", + "database/:database/_design/:designDoc/new_list": "newListsEditor" + }, + + apiUrl: function() { + //TODO: Hook up proper API urls + return ''; + }, + + newListsEditor: function (database, designDoc) { + var params = app.getParams(); + + this.setView("#left-content", new Views.ListEditor({ + currentddoc: "_design/"+designDoc || "", + ddocs: this.data.designDocs, + params: params, + database: this.data.database, + newView: true + })); + + this.setView("#right-content", new Views.PreviewScreen({})); + this.crumbs = function () { + return [ + {"name": "Create List Index", "link": Databases.databaseUrl(this.data.database)}, + ]; + }; + }, + tempFn: function(databaseName, ddoc, fn){ + this.setView("#left-content", new Views.ListEditor({})); + + this.setView("#right-content", new Views.PreviewScreen({})); + 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/bcc6dc21/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..9c9e451 --- /dev/null +++ b/app/addons/indexes/routes-show.js @@ -0,0 +1,71 @@ +// 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" +], + +function (app, FauxtonAPI, Databases, Views, Documents, Resources, RouteCore) { + + var ShowIndexes = RouteCore.extend({ + routes: { + "database/:database/_design/:ddoc/_show/:fn": { + route: "tempFn", + roles: ['_admin'] + }, + "database/:database/new_show": "newShowEditor", + "database/:database/_design/:designDoc/new_show": "newShowEditor" + }, + + newShowEditor: function (database, designDoc) { + var params = app.getParams(); + + this.setView("#left-content", new Views.ShowEditor({ + currentddoc: "_design/"+designDoc || "", + ddocs: this.data.designDocs, + params: params, + database: this.data.database, + newView: true + })); + + this.setView("#right-content", new Views.PreviewScreen({})); + this.crumbs = function () { + return [ + {"name": "Create Show Index", "link": Databases.databaseUrl(this.data.database)}, + ]; + }; + }, + + apiUrl: function() { + //TODO: Hook up proper API urls + return ''; + }, + + tempFn: function(databaseName, ddoc, fn){ + this.setView("#left-content", new Views.ShowEditor({})); + + this.setView("#right-content", new Views.PreviewScreen({})); + 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/bcc6dc21/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..86006f3 --- /dev/null +++ b/app/addons/indexes/routes-viewindexes.js @@ -0,0 +1,106 @@ +// 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" +], + +function (app, FauxtonAPI, Databases, Views, Documents, Resources, RouteCore) { + + var ViewIndexes = RouteCore.extend({ + routes: { + "database/:database/_design/:ddoc/_view/:view": { + route: "viewFn", + roles: ['_admin'] + }, + "database/:database/new_view": "newViewEditor", + "database/:database/_design/:designDoc/new_view": "newViewEditor" + }, + + newViewEditor: function (database, designDoc) { + var params = app.getParams(); + + this.setView("#right-content", new Views.PreviewScreen({})); + + 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.crumbs = function () { + return [ + {"name": "Create View Index", "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 Resources.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": view, "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/bcc6dc21/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/bcc6dc21/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..d12cd64 --- /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/bcc6dc21/app/addons/indexes/templates/index_header.html ---------------------------------------------------------------------- diff --git a/app/addons/indexes/templates/index_header.html b/app/addons/indexes/templates/index_header.html new file mode 100644 index 0000000..662f3ea --- /dev/null +++ b/app/addons/indexes/templates/index_header.html @@ -0,0 +1,30 @@ + + +
+ + + + + + +
+ + +
+ + +
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/bcc6dc21/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 @@ + +<% if (doc.isEditable()) { %> +
+<% } %> + +
+
+ _id "<%=docID%>" + +
+ + <% if (doc.isEditable()) { %> + + <% } %> + +
+
+
+
+
<%- doc.prettyJSON() %>
+
+
+
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/bcc6dc21/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..d36004c --- /dev/null +++ b/app/addons/indexes/templates/list_editor.html @@ -0,0 +1,39 @@ + +
+
+
+
+
+

Views are the primary tool used for querying and reporting on CouchDB databases.

+
+ +
+
+ + +
+ + +
+ +
+ + <% if (!newView) { %> + + <% } %> +
+
+
+
= http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/bcc6dc21/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..654e557 --- /dev/null +++ b/app/addons/indexes/templates/preview_screen.html @@ -0,0 +1,16 @@ + + +

No Index Created Yet!

+

Run Preview to query result

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/bcc6dc21/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..9afa2bf --- /dev/null +++ b/app/addons/indexes/templates/show_editor.html @@ -0,0 +1,41 @@ + + +
+
+
+
+
+

Views are the primary tool used for querying and reporting on CouchDB databases.

+
+ +
+
+ + +
+ + +
+ + +
+ + <% if (!newView) { %> + + <% } %> +
+
+
+
= http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/bcc6dc21/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..f33d3f9 --- /dev/null +++ b/app/addons/indexes/templates/view_editor.html @@ -0,0 +1,80 @@ + +
+
+
+
+
+

Views are the primary tool used for querying and reporting on CouchDB databases.

+
+ + +
+ +

<%- database %>

+
+ + +
+
+ + +
+ + +
+ +
+ + <% 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/bcc6dc21/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..73ed6ea --- /dev/null +++ b/app/addons/indexes/views.js @@ -0,0 +1,678 @@ +// 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 = {}; + + //Index view CORE extend this + Views.IndexCore = FauxtonAPI.View.extend({ + 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(); + } + }, + 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 + }; + } + }); + + + + Views.IndexHeader = Views.IndexCore.extend({ + template: "addons/indexes/templates/index_header" + }); + + Views.PreviewScreen = Views.IndexCore.extend({ + template: "addons/indexes/templates/preview_screen", + className: "watermark-logo" + }); + + Views.ShowEditor = FauxtonAPI.View.extend({ + template: "addons/indexes/templates/show_editor", + 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); + }, + }); + + Views.ListEditor = FauxtonAPI.View.extend({ + template: "addons/indexes/templates/list_editor", + }); + + + + 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: 'Table', + icon: 'fonticon-table' + },{ + 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') + }; + } + }); + + + + + + + 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" + }, + + 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 + //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.", + selector: "#define-view .errors-container", + 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", + selector: "#define-view .errors-container", + 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", + selector: "#define-view .errors-container", + 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(); + FauxtonAPI.triggerRouteEvent('reloadDesignDocs', { + selectedTab: app.utils.removeSpecialCharacters(ddocName.replace(/_design\//,'')) + '_' + app.utils.removeSpecialCharacters(viewName) + }); + } + + // 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}); + }, + + 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); + }, + + + 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, + 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 () { + 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/bcc6dc21/app/templates/layouts/two_pane.html ---------------------------------------------------------------------- diff --git a/app/templates/layouts/two_pane.html b/app/templates/layouts/two_pane.html index 031ad12..52b7d2a 100644 --- a/app/templates/layouts/two_pane.html +++ b/app/templates/layouts/two_pane.html @@ -12,18 +12,16 @@ License for the specific language governing permissions and limitations under the License. --> -
-
-
+
+ +
-
+ - -
-
-
+
+
+
- http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/bcc6dc21/app/templates/layouts/with_tabs_sidebar.html ---------------------------------------------------------------------- diff --git a/app/templates/layouts/with_tabs_sidebar.html b/app/templates/layouts/with_tabs_sidebar.html index a0ed03d..65d702e 100644 --- a/app/templates/layouts/with_tabs_sidebar.html +++ b/app/templates/layouts/with_tabs_sidebar.html @@ -21,9 +21,6 @@ the License.
- -
-
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/bcc6dc21/assets/img/couchWatermark.png ---------------------------------------------------------------------- diff --git a/assets/img/couchWatermark.png b/assets/img/couchWatermark.png new file mode 100644 index 0000000..cab9ce4 Binary files /dev/null and b/assets/img/couchWatermark.png differ http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/bcc6dc21/assets/less/fauxton.less ---------------------------------------------------------------------- diff --git a/assets/less/fauxton.less b/assets/less/fauxton.less index 463b1e0..3ddcff9 100644 --- a/assets/less/fauxton.less +++ b/assets/less/fauxton.less @@ -22,7 +22,8 @@ @import "bootstrap/mixins.less"; @import "prettyprint.less"; @import "icons.less"; - +@import "templates.less"; +@import "formstyles.less"; /** * HTML-wide overrides **/ @@ -56,28 +57,7 @@ a:hover { color: @red; } -input[type=text], -input[type=password] { - .border-radius(0); - padding: 12px; - border: 1px solid #ccc; - height: auto; - font-size: 16px; - margin-top: 0; -} - -input[type="checkbox"], -input[type="radio"] { - box-sizing: border-box; - padding: 0; -} -input[type="file"], -input[type="checkbox"], -input[type="radio"], -select { - margin: 0 0 1em 0; -} /* bootstrap overrides */ @@ -166,109 +146,7 @@ tbody { background-color: #F7F7F7; } -/*form elements and buttons*/ -.btn-group { - > .btn + .dropdown-toggle, - > .btn:first-child, - > .btn:last-child, - > .dropdown-toggle { - .border-radius(0); - background-image: none; - text-shadow: none; - } -} - -.btn { - .box-shadow(none); - .border-radius(@baseBorderRadius); - background-image: none; - text-shadow: none; - background-repeat: no-repeat; - padding: 10px; - margin-top: 0px; - .icon { - margin-right: 0.2em; - } - &.btn-small { - padding: 5px 10px; - .icon { - margin-right: 0; - font-size: inherit; - } - } - &.btn-mini { - padding: 3px 8px; - .icon { - margin-right: 0; - font-size: inherit; - } - } -} -.btn-primary { - background: @redButton; -} - -.btn-primary a:visited { - color: #fff; -} -.form-actions { - background: none; - border: none; -} - -.input-append, -.input-prepend { - .add-on { - font-size: 18px; - padding: 14px 5px 30px; - } - .btn .icon { - font-size: 21.5px; - margin-right: 0; - } -} - -.row-fluid .input-append [class*="span"], -.input-prepend input[class*="span"] { - width: auto; -} - -.form-inline { - input[type=password], - input[type=text] { - width: auto; - } -} -.checkbox { - label { - display: inline-block; - padding-left:25px; - } -} - -label { - margin-right: 15px; - padding-left:0; - display: block; - cursor: pointer; - position: relative; - font-size: 14px; - &.inline { - display: inline-block; - } -} -.help-block { - font-size: 12px; -} - -a.help-link:hover { - text-decoration: none; -} - -input[type=text].error { - border: red 1px solid; -} /** * Fauxton-specific Bootstrap additions @@ -297,458 +175,9 @@ table.databases { } } -/* ajax loader */ -.loader { - background: url('../img/loader.gif') center center no-repeat; - min-height: 100px; -} -#app-container.loader{ - min-height: 400px; - > *{ - display: none; - } -} - -#global-notifications { - position: fixed; - top: 0px; - display: block; - z-index: 100000; - left: @navWidth; - .closeMenu & { - left: @collapsedNavWidth; - } - width: 100%; -} - -#app-container{ - padding: 0; - height: 100%; - width: 100%; - position: absolute; - top: 0; - left: 0; - > .row-fluid { - height: 100%; - } -} - -/* Fixed side navigation */ -#primary-navbar { - /* hack for the scrollbar that shines through from the sidebar */ - -webkit-transform: translate3d(0, 0, 0); - height: 100%; - position: fixed; - width: @navWidth; - top: 0; - bottom: 0; - background-color: @primaryNav; - overflow-y: scroll; - .version { - color: #fff; - font-size: 10px; - padding-left: 10px; - } - #footer-links{ - position: absolute; - bottom: 0; - width: 100%; - } - #user-create-admin{ - font-size: 12px - } - .navbar { - .burger{ - .transition(all @transitionSpeed @transitionEaseType); - padding: 22px 0 0 18px; - position: fixed; - top: 0; - z-index: 100; - background-color: @primaryNav; - width: @navWidth; - div{ - .transition(all @transitionSpeed @transitionEaseType); - height: 4px; - width: 24px; - .border-radius(2); - background-color: @navBG; - margin: 2px 0px; - } - &:hover div{ - background-color: @orange; - } - } - .bottom-container { - height: 110px; - position: fixed; - bottom: 0; - width: 220px; - background: #3a2c2b; - .brand { - .box-sizing(content-box); - .hide-text; - .customTransition(left, 1s, 0.805, 0.005, 0.165, 0.985); - margin: 10px 0 0 0; - width: 200px; - height: 40px; - padding: 10px; - float: none; - background: #3a2c2b; - .icon { - .box-sizing(content-box); - background: url(../img/couchdb-site.png) no-repeat 0 0; - display: block; - height: 100%; - width: 100%; - } - .closeMenu & { - .icon { - background: url(../img/minilogo.png) no-repeat 0 0; - } - width: 45px; - } - } - #footer-nav-links { - li { - a { - font-size: 12px; - color: @red; - padding: 12px; - text-shadow: none; - } - &.active, &:hover{ - a { - text-decoration: underline; - } - } - } - } - } - nav { - margin-top: 64px; - .nav{ - margin: 0; - li{ - .transition(all @transitionSpeed @transitionEaseType); - padding: 0; - font-size: 16px; - letter-spacing: 1px; - line-height: 23px; - width: @navWidth; - font-weight: normal; - font-family: helvetica; - .box-sizing(border-box); - background-color: @navBG; - border-bottom: 1px solid @primaryNav; - min-height: 48px; - &.active, &:hover{ - a{ - .box-shadow(none); - } - background-color: @red; - } - &:hover .fonticon:before{ - color: @white; - } - &.active .fonticon:before, - &:hover .fonticon:before, - { - text-shadow: @boxShadow; - color: @NavIconActive; - } - a{ - padding: 12px 25px 12px 60px; - background-color: transparent; - color: #fff; - text-shadow: @textShadowOff; - &.closeMenu{ - color: transparent; - } - .fonticon { - position: relative; - &:before { - position: absolute; - top: -5px; - left: -41px; - font-size: 24px; - color: @NavIcon; - text-shadow: @boxShadowOff; - } - } - .closeMenu &{ - color: transparent; - } - } - } - } - ul#footer-nav-links{ - li{ - background-color: @primaryNav; - border-top: 1px solid @red; - border-bottom: none; - font-size: 12px; - padding: 12px; - min-height: 44px; - &.active, &:hover{ - background-color: @linkRed; - border-top: 1px solid @red; - a{ - color: white; - } - } - a{ - color: @red; - } - } - - } - ul#bottom-nav-links{ - margin-top: 0; - padding-bottom: 70px; - li{ - min-height: 55px; - background-color: @bottomNav; - &.active{ - background-color:@linkRed; - } - &:hover{ - background-color: @navBGHover; - } - a{ - &.fonticon { - position: relative; - &:before { - top: -5px; - left: -40px; - font-size: 22px; - } - } - } - } - } - } - } -} - - -#dashboard { - .box-shadow(-6px 0 rgba(0, 0, 0, 0.1)); - border-left: 1px solid #999; - position: absolute; - left: @navWidth; - margin-left: 0; - padding-left: 0; - padding-right: 0; - background-color: @sidebarBG; - min-width: 600px; - height: 100%; - .closeMenu &{ - left: @collapsedNavWidth; - } - &.one-pane{ - min-width: 800px; - margin-top: 0; - overflow-x: hidden; - } -} - -/*dashboard content can be in multiple templates*/ - -#dashboard-content{ - &.row-fluid, - &.window-resizeable{ - /*remove gutter without rewriting variable*/ - margin-left: 0px; - } - padding: 20px; - .with-sidebar &{ - border-left: 1px solid #999; - border-right: 1px solid #999; - width: auto; - .box-shadow(-6px 0 rgba(0, 0, 0, 0.1)); - padding: 0px; - bottom: 0px; - top: 60px; - position: fixed; - overflow-x: hidden; - overflow-y: auto; - left: @sidebarWidth+@navWidth; - right: 0; - .box-sizing(border-box); - .closeMenu & { - left: @sidebarWidth+@collapsedNavWidth; - } - } - > div.inner { - display: block; - } -} - -.with-sidebar.content-area { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; -} - -// .closeMenu .with-sidebar.content-area { -// left: 0; -// } -/*tools*/ - -.row-fluid.content-area{ - background-color: @background; -} - - -.fixed-header{ - background-color: @breadcrumbBG; - position: fixed; - top: 0; - right: 0; - left: @navWidth; - .closeMenu & { - left: @collapsedNavWidth; - } - border-bottom: 5px solid @breadcrumbBorder; - .box-shadow(0 4px 6px -2px #808080); - z-index: 100; - .one-pane & { - position: relative; - border: none; - .box-shadow(none); - left: auto; - } -} - -#breadcrumbs { - .breadcrumb { - margin: 15px 20px; - margin-bottom: 0; - background-color: transparent; - padding: 0; - li { - .divider { - font-size: 12px; - color: @breadcrumbArrow; - } - &:first-child { - font-size: 30px; - } - color: @breadcrumbText; - font-size: 18px; - text-shadow: none; - &.active{ - color: #333; - } - a{ - color: @breadcrumbText; - } - } - } -} - - -/*SIDEBAR TEMPLATE STYLES*/ -.topmenu-defaults { - height: 70px; - padding: 12px 10px 0; - .box-sizing(border-box); -} - -.dashboard-upper-menu{ - right: 0; - left: @sidebarWidth+@navWidth; - position: fixed; - z-index: 11; - display: block; - .topmenu-defaults; - background-color: #CBCBCB; - .closeMenu & { - left: @sidebarWidth+@collapsedNavWidth; - } -} - -#dashboard-lower-content{ - padding: 20px; - background-color: #F1F1F1; -} - -#dashboard-upper-content{ - .tab-content { - padding-top: 70px; - } - .well{ - padding: 20px; - .border-radius(0); - .box-shadow(none); - } -} - -.sidenav { - padding: 0; - header { - width: @sidebarWidth; - border-bottom: 1px solid #d3d7db; - } - .nav-list{ - .divider { - border: none; - } - > li > a:hover, - > li > a:focus{ - background-color: @darkRed; - color: #fff; - } - li.active > a { - color: @darkRed; - } - > li > a{ - color: @linkRed; - padding: 10px 13px 10px 24px; - border-bottom: 1px solid #d3d7db; - span{ - margin-right: 8px; - width: 14px; - display: inline-block; - text-align: center; - } - } - a{ - display: block; - padding: 10px 5px 5px 15px; - color: @subListGray; - .divider { - background: none; - color: #ccc; - padding: 0 2px; - } - } - .nav-header{ - padding: 0px; - text-shadow: none; - color: #333333; - & > span:hover { - color: @red; - } - } - } -} -#sidebar-content { - position: absolute; - top: 60px; - width: @sidebarWidth; - left: 0; - background-color: @secondarySidebar; - > div.inner { - display: block; - } -} -/*ONE PANEL TEMPLATE ONLY STYLES AKA _all_dbs */ .result-tools{ border-bottom: 1px solid #999999; @@ -804,76 +233,7 @@ table.databases { } } -.custom-inputs{ - - input[type=radio], - input[type=checkbox] { - display: none; - } - - .checkbox label:before { - border-radius: 3px; - } - - .controls > .radio:first-child, .controls > .checkbox:first-child { - padding-top: 15px; - } - - .radio.inline, .checkbox.inline { - display: inline-block; - padding-top: 15px; - margin-bottom: 12px; - vertical-align: middle; - } - - input[type=checkbox]:checked + label:before { - /*content: "\2713"; */ - content: "\00d7"; - text-shadow: 1px 1px 1px rgba(0, 0, 0, .2); - font-size: 16px; - background-color: @red; - color: white; - text-align: center; - line-height: 15px; - } - - label:before { - content: ""; - display: inline-block; - width: 16px; - height: 16px; - - margin-right: 10px; - position: absolute; - left: 0; - bottom: 1px; - background-color: #aaa; - box-shadow: inset 0px 2px 3px 0px rgba(0, 0, 0, .3), 0px 1px 0px 0px rgba(255, 255, 255, .8); - } - - .radio label:before { - border-radius: 8px; - } - - input[type=radio]:checked + label:before { - content: "\2022"; - color: #f3f3f3; - font-size: 30px; - text-align: center; - line-height: 18px; - } - - label.drop-down{ - &:before{ - display: none; - } - } -} - -form.view-query-update, form.view-query-save { - max-width: 100%; -} /*documents and databases */ .view.show{ @@ -986,39 +346,4 @@ div.spinner { } } -div.add-dropdown { - position: absolute; - top: 2px; - right: 0px; - .dropdown-menu{ - left: -110px; - padding-bottom: 0; - width: 148px; - min-width: 0; - top: 38px; - .box-shadow(@boxShadow); - &.arrow:before{ - right: 4px; - } - a { - background-color: #202326; - color: rgba(255, 255, 255, 0.8); - &:hover{ - background-color: @red; - color: white; - } - } - li a { - padding: 10px 15px 10px 12px; - } - } - .dropdown-toggle{ - border-top: none !important; - text-decoration: none; - } - > a { - border-bottom: none; - text-decoration: none; - font-size: 16px; - } -} + http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/bcc6dc21/assets/less/formstyles.less ---------------------------------------------------------------------- diff --git a/assets/less/formstyles.less b/assets/less/formstyles.less new file mode 100644 index 0000000..4645664 --- /dev/null +++ b/assets/less/formstyles.less @@ -0,0 +1,247 @@ +/* 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 "variables.less"; + +input[type=text], +input[type=password] { + .border-radius(0); + padding: 12px; + border: 1px solid #ccc; + height: auto; + font-size: 16px; + margin-top: 0; +} + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + padding: 0; +} + +input[type="file"], +input[type="checkbox"], +input[type="radio"], +select { + margin: 0 0 1em 0; +} + +/*form elements and buttons*/ +.btn-group { + > .btn + .dropdown-toggle, + > .btn:first-child, + > .btn:last-child, + > .dropdown-toggle { + .border-radius(0); + background-image: none; + text-shadow: none; + } +} + +.btn { + .box-shadow(none); + .border-radius(@baseBorderRadius); + background-image: none; + text-shadow: none; + background-repeat: no-repeat; + padding: 10px; + margin-top: 0px; + .icon { + margin-right: 0.2em; + } + &.btn-small { + padding: 5px 10px; + .icon { + margin-right: 0; + font-size: inherit; + } + } + &.btn-mini { + padding: 3px 8px; + .icon { + margin-right: 0; + font-size: inherit; + } + } +} +.btn-primary { + background: @redButton; +} + +.btn-primary a:visited { + color: #fff; +} + +.form-actions { + background: none; + border: none; +} + +.input-append, +.input-prepend { + .add-on { + font-size: 18px; + padding: 14px 5px 30px; + } + .btn .icon { + font-size: 21.5px; + margin-right: 0; + } +} + +.row-fluid .input-append [class*="span"], +.input-prepend input[class*="span"] { + width: auto; +} + +.form-inline { + input[type=password], + input[type=text] { + width: auto; + } +} +.checkbox { + label { + display: inline-block; + padding-left:25px; + } +} + +label { + margin-right: 15px; + padding-left:0; + display: block; + cursor: pointer; + position: relative; + font-size: 14px; + &.inline { + display: inline-block; + } +} +.help-block { + font-size: 12px; +} + +a.help-link:hover { + text-decoration: none; +} + +input[type=text].error { + border: red 1px solid; +} + +form.view-query-update, form.view-query-save { + max-width: 100%; +} +.custom-inputs{ + + input[type=radio], + input[type=checkbox] { + display: none; + } + + .checkbox label:before { + border-radius: 3px; + } + + .controls > .radio:first-child, .controls > .checkbox:first-child { + padding-top: 15px; + } + + .radio.inline, .checkbox.inline { + display: inline-block; + padding-top: 15px; + margin-bottom: 12px; + vertical-align: middle; + } + + input[type=checkbox]:checked + label:before { + /*content: "\2713"; */ + content: "\00d7"; + text-shadow: 1px 1px 1px rgba(0, 0, 0, .2); + font-size: 16px; + background-color: @red; + color: white; + text-align: center; + line-height: 15px; + } + + label:before { + content: ""; + display: inline-block; + + width: 16px; + height: 16px; + + margin-right: 10px; + position: absolute; + left: 0; + bottom: 1px; + background-color: #aaa; + box-shadow: inset 0px 2px 3px 0px rgba(0, 0, 0, .3), 0px 1px 0px 0px rgba(255, 255, 255, .8); + } + + .radio label:before { + border-radius: 8px; + } + + input[type=radio]:checked + label:before { + content: "\2022"; + color: #f3f3f3; + font-size: 30px; + text-align: center; + line-height: 18px; + } + + label.drop-down{ + &:before{ + display: none; + } + } +} + +div.add-dropdown { + position: absolute; + top: 2px; + right: 0px; + .dropdown-menu{ + left: -110px; + padding-bottom: 0; + width: 148px; + min-width: 0; + top: 38px; + .box-shadow(@boxShadow); + &.arrow:before{ + right: 4px; + } + a { + background-color: #202326; + color: rgba(255, 255, 255, 0.8); + &:hover{ + background-color: @red; + color: white; + } + } + li a { + padding: 10px 15px 10px 12px; + } + } + .dropdown-toggle{ + border-top: none !important; + text-decoration: none; + } + > a { + border-bottom: none; + text-decoration: none; + font-size: 16px; + } +}