Repository: couchdb-fauxton Updated Branches: refs/heads/master febdaf9b3 -> 380b277c4
Moved Add Config Option modal to tray This also fixes a few things. - validation is cleaned up a bit - the typeahead option now properly works again for sections. Closes COUCHDB-2443 Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/380b277c Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/380b277c Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/380b277c Branch: refs/heads/master Commit: 380b277c459e5e74e9a47ff6fb858401e58716fa Parents: febdaf9 Author: Benjamin Keen <[email protected]> Authored: Fri Nov 7 10:20:05 2014 -0800 Committer: Benjamin Keen <[email protected]> Committed: Tue Nov 11 08:48:50 2014 -0800 ---------------------------------------------------------------------- app/addons/config/assets/less/config.less | 61 +++++-- app/addons/config/routes.js | 2 +- .../config/templates/add_config_option.html | 26 +++ app/addons/config/templates/addsection.html | 18 -- app/addons/config/templates/header.html | 5 +- app/addons/config/templates/modal.html | 31 ---- app/addons/config/tests/configSpec.js | 28 ++-- app/addons/config/views.js | 163 +++++++++++-------- 8 files changed, 181 insertions(+), 153 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/380b277c/app/addons/config/assets/less/config.less ---------------------------------------------------------------------- diff --git a/app/addons/config/assets/less/config.less b/app/addons/config/assets/less/config.less index 163dd05..aa61fbb 100644 --- a/app/addons/config/assets/less/config.less +++ b/app/addons/config/assets/less/config.less @@ -11,6 +11,8 @@ * the License. */ @import "../../../../../assets/less/variables.less"; +@import "../../../../../assets/less/bootstrap/mixins.less"; + .config-item { @@ -31,24 +33,6 @@ button { width: 7%;} } -.modal.add-section-modal { - width: 400px; - margin-left: -200px; - left: 50%; - - input { - width: 100%; - } - - form { - margin-bottom: 0px; - } - - .modal-footer { - padding: 14px 0px 0px; - } -} - #config-trash { width: 5%; } @@ -79,3 +63,44 @@ table.config { border-left: 1px solid #ccc; padding: 10px 14px; } + +.add-section-tray { + padding: 20px; + width: 300px; + + &:before { + right: 138px; + } + + input { + width: 100%; + } + + form { + margin-bottom: 0px; + } + + a.btn { + color: white; + background-color: #af2d24; + line-height: 1.5em; + border: 0px; + padding: 10px 10px 9px; + font-size: 14px; + .border-radius(5px); + + &:hover { + background-color: #cbcbcb; + color: white; + } + } + + .typeahead { + width: 260px; + margin-top: 0px; + + a { + color: #ffffff; + } + } +} http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/380b277c/app/addons/config/routes.js ---------------------------------------------------------------------- diff --git a/app/addons/config/routes.js b/app/addons/config/routes.js index ab7f496..62fd9b1 100644 --- a/app/addons/config/routes.js +++ b/app/addons/config/routes.js @@ -42,7 +42,7 @@ function(app, FauxtonAPI, Config, Views) { }, config: function () { - this.newSection = this.setView('#right-header', new Views.AddSectionButton({ collection: this.configs })); + this.newSection = this.setView('#right-header', new Views.ConfigHeader({ collection: this.configs })); this.setView('#dashboard-content', new Views.Table({ collection: this.configs })); }, http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/380b277c/app/addons/config/templates/add_config_option.html ---------------------------------------------------------------------- diff --git a/app/addons/config/templates/add_config_option.html b/app/addons/config/templates/add_config_option.html new file mode 100644 index 0000000..13e36bd --- /dev/null +++ b/app/addons/config/templates/add_config_option.html @@ -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. +*/%> + +<a id="add-new-section" class="add-new-section-btn"><i class="icon icon-plus header-icon"></i> Add Option</a> + +<div class="add-section-tray tray"> + <div class="add-on">Add Option</div> + + <div class="js-form-error-config"></div> + <input type="text" name="section" placeholder="Section" autocomplete="off" autofocus> + <input type="text" name="name" placeholder="Name"> + <input type="text" name="value" placeholder="Value"> + + <a class="btn" id="js-create-config-section">Create</a> +</div> http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/380b277c/app/addons/config/templates/addsection.html ---------------------------------------------------------------------- diff --git a/app/addons/config/templates/addsection.html b/app/addons/config/templates/addsection.html deleted file mode 100644 index 1249d93..0000000 --- a/app/addons/config/templates/addsection.html +++ /dev/null @@ -1,18 +0,0 @@ -<%/* -Licensed under the Apache License, Version 2.0 (the "License"); you may not -use this file except in compliance with the License. You may obtain a copy of -the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -License for the specific language governing permissions and limitations under -the License. -*/%> - -<div id="header-api-bar" class="button"></div> -<div id="add-section-button" class="button"> - <a id="add-new-section" class="add-new-section-btn"><i class="icon icon-plus header-icon"></i> Add Section</a> -</div> http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/380b277c/app/addons/config/templates/header.html ---------------------------------------------------------------------- diff --git a/app/addons/config/templates/header.html b/app/addons/config/templates/header.html index 2e19b75..b165123 100644 --- a/app/addons/config/templates/header.html +++ b/app/addons/config/templates/header.html @@ -12,8 +12,5 @@ License for the specific language governing permissions and limitations under the License. */%> -<!-- floats right --> <div id="header-api-bar" class="button"></div> - -<!-- add database--> -<div id="add-db-button" class="button"></div> +<div id="add-section-button" class="button"></div> http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/380b277c/app/addons/config/templates/modal.html ---------------------------------------------------------------------- diff --git a/app/addons/config/templates/modal.html b/app/addons/config/templates/modal.html deleted file mode 100644 index 97e071a..0000000 --- a/app/addons/config/templates/modal.html +++ /dev/null @@ -1,31 +0,0 @@ -<%/* -Licensed under the Apache License, Version 2.0 (the "License"); you may not -use this file except in compliance with the License. You may obtain a copy of -the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -License for the specific language governing permissions and limitations under -the License. -*/%> - -<div class="modal-header"> - <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> - <h3>Create Config Option</h3> -</div> -<div class="modal-body"> - <div class="js-form-error-config"></div> - <form id="js-add-section-form" class="form well"> - <input type="text" name="section" placeholder="Section" autocomplete="off" autofocus> - <input type="text" name="name" placeholder="Name"> - <br/> - <input type="text" name="value" placeholder="Value"> - <div class="modal-footer"> - <button type="button" class="btn" data-dismiss="modal">Cancel</button> - <button type="submit" class="btn btn-primary">Save</button> - </div> - </form> -</div> http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/380b277c/app/addons/config/tests/configSpec.js ---------------------------------------------------------------------- diff --git a/app/addons/config/tests/configSpec.js b/app/addons/config/tests/configSpec.js index 346ab43..aefce92 100644 --- a/app/addons/config/tests/configSpec.js +++ b/app/addons/config/tests/configSpec.js @@ -38,17 +38,17 @@ define([ collection = new Resources.Collection(optionModels); }); - describe("Config: Modal", function () { + describe("Config: Add Option Tray", function () { var viewSandbox, - modal; + tray; beforeEach(function (done) { - modal = new Views.Modal({ + tray = new Views.AddConfigOptionsButton({ collection: collection }); viewSandbox = new ViewSandbox(); - viewSandbox.renderView(modal, done); + viewSandbox.renderView(tray, done); }); afterEach(function () { @@ -56,21 +56,21 @@ define([ }); it("looks if entries are new", function () { - modal.$('input[name="section"]').val("foo1"); - modal.$('input[name="name"]').val("testname"); - assert.ok(modal.isUniqueEntryInSection(collection)); + tray.$('input[name="section"]').val("foo1"); + tray.$('input[name="name"]').val("testname"); + assert.ok(tray.isUniqueEntryInSection(collection)); - modal.$('input[name="name"]').val("testname2"); - assert.notOk(modal.isUniqueEntryInSection(collection)); + tray.$('input[name="name"]').val("testname2"); + assert.notOk(tray.isUniqueEntryInSection(collection)); }); it("does not send an error for a new section", function () { - modal.$('input[name="section"]').val("newsection"); - modal.$('input[name="name"]').val("testname"); - modal.$('input[name="value"]').val("testvalue"); - var spy = sinon.spy(modal, "errorMessage"); + tray.$('input[name="section"]').val("newsection"); + tray.$('input[name="name"]').val("testname"); + tray.$('input[name="value"]').val("testvalue"); + var spy = sinon.spy(tray, "showError"); - modal.validate(); + tray.createConfigOption(); assert.notOk(spy.called); }); }); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/380b277c/app/addons/config/views.js ---------------------------------------------------------------------- diff --git a/app/addons/config/views.js b/app/addons/config/views.js index 39a2920..93bfa2b 100644 --- a/app/addons/config/views.js +++ b/app/addons/config/views.js @@ -139,35 +139,121 @@ function(app, FauxtonAPI, Config, Components) { } }); - Views.Modal = FauxtonAPI.View.extend({ - className: 'add-section-modal modal hide fade', - template: 'addons/config/templates/modal', + Views.ConfigHeader = FauxtonAPI.View.extend({ + template: 'addons/config/templates/header', + className: 'header-right', + + initialize: function () { + this.rightHeader = this.setView('#add-section-button', new Views.AddConfigOptionsButton({ collection: this.collection })); + } + }); + + + Views.AddConfigOptionsButton = FauxtonAPI.View.extend({ + template: 'addons/config/templates/add_config_option', events: { - 'submit #js-add-section-form': 'submitClick' + 'click #add-new-section': 'toggleTray', + 'click #js-create-config-section': 'createConfigOption' }, initialize: function () { - this.sourceArray = _.map(this.collection.toJSON(), function (item, key) { - return item.section; + var hideTray = _.bind(this.hideTray, this), + trayVisible = _.bind(this.trayVisible, this); + + $('body').on('click.add-new-section', function(e) { + var $clickEl = $(e.target); + + if (!trayVisible()) { return; } + if ($clickEl.closest('.add-new-section').length) { return; } + if (!$clickEl.closest('.add-section-tray').length) { + hideTray(); + } + }); + }, + + cleanup: function () { + $('body').off('click.add-new-section'); + }, + + processKey: function (e) { + if (e.which === 13) { + e.preventDefault(); + this.createConfigOption(); + } + }, + + toggleTray: function (e) { + e.preventDefault(); + if (this.trayVisible()) { + this.hideTray(); + } else { + this.showTray(); + } + }, + + hideTray: function () { + var $tray = this.$('.tray'); + $tray.velocity('reverse', FauxtonAPI.constants.TRAY_TOGGLE_SPEED, function () { + $tray.hide(); }); + this.$('#add-new-section').removeClass('enabled'); + }, + + showTray: function () { + // to be refactored out later (see COUCHDB-2401) + FauxtonAPI.Events.trigger("APIbar:closeTray"); + + this.$('.tray').velocity('transition.slideDownIn', FauxtonAPI.constants.TRAY_TOGGLE_SPEED); + this.$('#add-new-section').addClass('enabled'); + }, + + trayVisible: function () { + return this.$('.tray').is(':visible'); }, afterRender: function () { + this.sectionNames = _.map(this.collection.toJSON(), function (item) { + return item.section; + }); + this.sectionTypeAhead = new Components.Typeahead({ - source: this.sourceArray, + source: this.sectionNames, el: 'input[name="section"]' }); this.sectionTypeAhead.render(); }, + createConfigOption: function (e) { + if (e) { + e.preventDefault(); + } + + var section = this.$('input[name="section"]').val(), + name = this.$('input[name="name"]').val(), + value = this.$('input[name="value"]').val(), + collection = this.collection; + + // perform a little validation, then submit + if (!section) { + this.showError('Please enter or select a section.'); + } else if (!name) { + this.showError('Please add an option name.'); + } else if (this.isUniqueEntryInSection(collection)) { + this.showError('The option have a unique name.'); + } else if (!value) { + this.showError('Please add a value.'); + } else { + this.submitForm(); + } + }, + submitForm: function () { var option = new Config.OptionModel({ section: this.$('input[name="section"]').val(), name: this.$('input[name="name"]').val(), value: this.$('input[name="value"]').val() }); - option.save(); var section = this.collection.find(function (section) { @@ -183,7 +269,7 @@ function(app, FauxtonAPI, Config, Components) { }); } - this.hide(); + this.hideTray(); FauxtonAPI.Events.trigger('config:newSection'); }, @@ -194,70 +280,13 @@ function(app, FauxtonAPI, Config, Components) { return collection.findEntryInSection(sectionName, entry); }, - isSection: function () { - var section = this.$('input[name="section"]').val(); - return _.find(this.sourceArray, function(item){ return item === section; }); - }, - - submitClick: function (event) { - event.preventDefault(); - this.validate(); - }, - - validate: function () { - var section = this.$('input[name="section"]').val(), - name = this.$('input[name="name"]').val(), - value = this.$('input[name="value"]').val(), - collection = this.collection; - - if (!name) { - this.errorMessage('Add a name'); - } else if (!value) { - this.errorMessage('Add a value'); - } else if (this.isUniqueEntryInSection(collection)) { - this.errorMessage('Must have a unique name'); - } else { - this.submitForm(); - } - }, - - errorMessage: function (msg) { + showError: function (msg) { FauxtonAPI.addNotification({ msg: msg, type: 'error', clear: true, selector: '.js-form-error-config' }); - }, - - show: function(){ - this.$el.modal({show:true}); - }, - - hide: function(){ - this.$el.modal('hide'); - } - }); - - Views.AddSectionButton = FauxtonAPI.View.extend({ - template: 'addons/config/templates/addsection', - className: 'header-right', - - events: { - 'click #add-new-section': 'addSection' - }, - - addSection: function (e) { - e.preventDefault(); - this.modal.show(); - }, - - beforeRender: function () { - this.modal = this.insertView('body', new Views.Modal({ - collection: this.collection - })); - - this.modal.render(); } });
