Repository: couchdb-fauxton Updated Branches: refs/heads/master 3da92763e -> 8cd744acb
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/app/addons/documents/templates/string_edit_modal.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/string_edit_modal.html b/app/addons/documents/templates/string_edit_modal.html deleted file mode 100644 index 1177795..0000000 --- a/app/addons/documents/templates/string_edit_modal.html +++ /dev/null @@ -1,30 +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 hide fade"> - <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> - <h3>Edit text <span id="string-edit-header"></span></h3> - </div> - <div class="modal-body"> - <div id="modal-error" class="hide alert alert-error"/> - <div id="string-editor-wrapper"><div id="string-editor-container" class="doc-code"></div></div> - </div> - <div class="modal-footer"> - <button data-dismiss="modal" class="btn"><i class="icon fonticon-circle-x"></i> Cancel</button> - <button id="string-edit-save-btn" class="btn btn-success save"><i class="fonticon-circle-check"></i> Save</button> - </div> -</div> - - http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/app/addons/documents/templates/upload_modal.html ---------------------------------------------------------------------- diff --git a/app/addons/documents/templates/upload_modal.html b/app/addons/documents/templates/upload_modal.html deleted file mode 100644 index 4625826..0000000 --- a/app/addons/documents/templates/upload_modal.html +++ /dev/null @@ -1,42 +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 hide fade"> - <div class="modal-header"> - <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> - <h3>Upload an Attachment</h3> - </div> - <div class="modal-body"> - <div id="modal-error" class="alert alert-error hide" style="font-size: 16px;"> </div> - <form id="file-upload" class="form" method="post"> - <p class="help-block"> - Please select the file you want to upload as an attachment to this document. - Please note that this will result in the immediate creation of a new revision of the document, - so it's not necessary to save the document after the upload. - </p> - <input id="_attachments" type="file" name="_attachments"> - <input id="_rev" type="hidden" name="_rev" value="" > - <br/> - </form> - - <div class="progress progress-info"> - <div class="bar" style="width: 0%"></div> - </div> - </div> - <div class="modal-footer"> - <button href="#" data-dismiss="modal" data-bypass="true" class="btn"><i class="icon fonticon-cancel-circled"></i> Cancel</button> - <button href="#" id="upload-btn" data-bypass="true" class="btn btn-success save"><i class="icon fonticon-ok-circled"></i> Upload</button> - </div> -</div> - http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/app/addons/documents/tests/nightwatch/createsDocument.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/tests/nightwatch/createsDocument.js b/app/addons/documents/tests/nightwatch/createsDocument.js index e16de06..684233a 100644 --- a/app/addons/documents/tests/nightwatch/createsDocument.js +++ b/app/addons/documents/tests/nightwatch/createsDocument.js @@ -26,8 +26,11 @@ module.exports = { .clickWhenVisible('#new-all-docs-button a[href="#/database/' + newDatabaseName + '/new"]') .waitForElementPresent('#editor-container', waitTime, false) .verify.urlEquals(baseUrl + '/#/database/' + newDatabaseName + '/new') + .waitForElementPresent('.ace_layer.ace_cursor-layer.ace_hidden-cursors', waitTime, false) + + //.pause(1000) // looks like auto-focus happens during the next execute() line, so this slows it down .execute('\ - var editor = ace.edit("editor-container");\ + var editor = ace.edit("doc-editor");\ editor.gotoLine(2,10);\ editor.removeWordRight();\ editor.insert("' + newDocumentName + '");\ http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/app/addons/documents/tests/nightwatch/deletesDocuments.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/tests/nightwatch/deletesDocuments.js b/app/addons/documents/tests/nightwatch/deletesDocuments.js index 72a6a68..5a3a900 100644 --- a/app/addons/documents/tests/nightwatch/deletesDocuments.js +++ b/app/addons/documents/tests/nightwatch/deletesDocuments.js @@ -29,6 +29,8 @@ module.exports = { .waitForElementPresent('.control-select-all', waitTime, false) .clickWhenVisible('.control-delete') .acceptAlert() + .waitForElementVisible('.alert.alert-info', waitTime, false) + .waitForElementVisible('label[for="checkbox-' + newDocumentName + '2' + '"]', waitTime, false) .clickWhenVisible('label[for="checkbox-' + newDocumentName + '2' + '"]', waitTime, false) .waitForElementPresent('.control-select-all', waitTime, false) http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/app/addons/documents/tests/nightwatch/mangoIndex.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/tests/nightwatch/mangoIndex.js b/app/addons/documents/tests/nightwatch/mangoIndex.js index a47e319..dce4cb9 100644 --- a/app/addons/documents/tests/nightwatch/mangoIndex.js +++ b/app/addons/documents/tests/nightwatch/mangoIndex.js @@ -36,8 +36,8 @@ module.exports = { var editor = ace.edit("query-field");\ editor.getSession().setValue(json);\ ') - .execute('$(".save")[0].scrollIntoView();') - .clickWhenVisible('button.btn-success.save') + .execute('$("#create-index-btn")[0].scrollIntoView();') + .clickWhenVisible('#create-index-btn') .checkForStringPresent(newDatabaseName + '/_index', 'rocko-artischocko') .checkForStringPresent(newDatabaseName + '/_index', 'gans_gans_mango') .waitForElementPresent('.prettyprint', waitTime, false) http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/app/addons/documents/tests/nightwatch/mangoQuery.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/tests/nightwatch/mangoQuery.js b/app/addons/documents/tests/nightwatch/mangoQuery.js index f173824..6801436 100644 --- a/app/addons/documents/tests/nightwatch/mangoQuery.js +++ b/app/addons/documents/tests/nightwatch/mangoQuery.js @@ -32,8 +32,8 @@ module.exports = { var editor = ace.edit("query-field");\ editor.getSession().setValue(json);\ ') - .execute('$(".save")[0].scrollIntoView();') - .clickWhenVisible('button.btn-success.save') + .execute('$("#create-index-btn")[0].scrollIntoView();') + .clickWhenVisible('#create-index-btn') .waitForElementPresent('.prettyprint', waitTime, false) .assert.containsText('#dashboard-lower-content', 'number') http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/app/addons/documents/tests/nightwatch/uploadAttachment.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/tests/nightwatch/uploadAttachment.js b/app/addons/documents/tests/nightwatch/uploadAttachment.js index b0a5532..4005984 100644 --- a/app/addons/documents/tests/nightwatch/uploadAttachment.js +++ b/app/addons/documents/tests/nightwatch/uploadAttachment.js @@ -24,11 +24,10 @@ module.exports = { .createDocument('my_doc', newDatabaseName) .url(baseUrl + '/#/database/' + newDatabaseName + '/my_doc') .clickWhenVisible('.panel-button.upload') - .waitForElementVisible('input#_attachments', waitTime) - .setValue('input#_attachments', require('path').resolve(__dirname + '/uploadAttachment.js')) + .waitForElementVisible('input[name="_attachments"]', waitTime) + .setValue('input[name="_attachments"]', require('path').resolve(__dirname + '/uploadAttachment.js')) .clickWhenVisible('#upload-btn') .waitForElementVisible('#global-notification-id', waitTime, false) - .assert.attributeEquals('#_rev', 'value', '') .getText('#global-notification-id', function (result) { var data = result.value; this.verify.ok(data, 'Document saved successfully.'); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/app/addons/documents/tests/nightwatch/viewCreate.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/tests/nightwatch/viewCreate.js b/app/addons/documents/tests/nightwatch/viewCreate.js index dcdfc48..f163ea5 100644 --- a/app/addons/documents/tests/nightwatch/viewCreate.js +++ b/app/addons/documents/tests/nightwatch/viewCreate.js @@ -26,9 +26,9 @@ module.exports = { var editor = ace.edit("map-function");\ editor.getSession().setValue("function (doc) { emit(\'hasehase\'); }");\ ') - .execute('$(".save")[0].scrollIntoView();') - .waitForElementPresent('button.btn.btn-success.save', waitTime, false) - .clickWhenVisible('button.btn.btn-success.save', waitTime, false) + .execute('$("#save-view")[0].scrollIntoView();') + .waitForElementPresent('#save-view', waitTime, false) + .clickWhenVisible('#save-view', waitTime, false) .checkForDocumentCreated('_design/test_design_doc-selenium-1') .waitForElementPresent('.prettyprint', waitTime, false) .waitForElementNotPresent('.loading-lines', waitTime, false) @@ -50,9 +50,9 @@ module.exports = { var editor = ace.edit("map-function");\ editor.getSession().setValue("function (doc) { emit(\'hasehase\'); }");\ ') - .execute('$(".save")[0].scrollIntoView();') - .waitForElementPresent('button.btn.btn-success.save', waitTime, false) - .clickWhenVisible('button.btn.btn-success.save', waitTime, false) + .execute('$("#save-view")[0].scrollIntoView();') + .waitForElementPresent('#save-view', waitTime, false) + .clickWhenVisible('#save-view', waitTime, false) .checkForDocumentCreated('_design/test_design_doc-selenium-1') .waitForElementPresent('.prettyprint', waitTime, false) .waitForElementNotPresent('.loading-lines', waitTime, false) @@ -78,8 +78,8 @@ module.exports = { var editor = ace.edit("map-function");\ editor.getSession().setValue("function (doc) { emit(\'gansgans\'); }");\ ') - .execute('$(".save")[0].scrollIntoView();') - .clickWhenVisible('button.btn-success.save') + .execute('$("#save-view")[0].scrollIntoView();') + .clickWhenVisible('#save-view') .checkForDocumentCreated('_design/test_design_doc-selenium-2') .waitForElementPresent('.prettyprint', waitTime, false) .waitForElementNotPresent('.loading-lines', waitTime, false) @@ -107,8 +107,8 @@ module.exports = { var editor = ace.edit("map-function");\ editor.getSession().setValue("function (doc) { emit(\'enteente\', 1); }");\ ') - .execute('$(".save")[0].scrollIntoView();') - .clickWhenVisible('button.btn-success.save') + .execute('$("#save-view")[0].scrollIntoView();') + .clickWhenVisible('#save-view') .checkForDocumentCreated('_design/testdesigndoc/_view/test-new-view') .waitForElementPresent('.prettyprint', waitTime, false) http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/app/addons/documents/tests/nightwatch/viewCreateBadView.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/tests/nightwatch/viewCreateBadView.js b/app/addons/documents/tests/nightwatch/viewCreateBadView.js index f4a693d..0555cf4 100644 --- a/app/addons/documents/tests/nightwatch/viewCreateBadView.js +++ b/app/addons/documents/tests/nightwatch/viewCreateBadView.js @@ -36,8 +36,8 @@ module.exports = { var editor = ace.edit("map-function");\ editor.getSession().setValue("function (doc) { emit(\'boom\', doc._id); }");\ ') - .execute('$(".save")[0].scrollIntoView();') - .clickWhenVisible('button.btn-success.save') + .execute('$("#save-view")[0].scrollIntoView();') + .clickWhenVisible('#save-view') .waitForAttribute('#global-notifications', 'textContent', function (docContents) { return (/_sum function requires/).test(docContents); }) http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/app/addons/documents/tests/nightwatch/viewEdit.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/tests/nightwatch/viewEdit.js b/app/addons/documents/tests/nightwatch/viewEdit.js index e77ba6b..96cf409 100644 --- a/app/addons/documents/tests/nightwatch/viewEdit.js +++ b/app/addons/documents/tests/nightwatch/viewEdit.js @@ -32,8 +32,8 @@ module.exports = { var editor = ace.edit("map-function");\ editor.getSession().setValue("function (doc) { emit(\'hasehase5000\', 1); }");\ ') - .execute('$(".save")[0].scrollIntoView();') - .clickWhenVisible('button.btn-success.save') + .execute('$("#save-view")[0].scrollIntoView();') + .clickWhenVisible('#save-view') .checkForStringPresent(viewUrl, 'hasehase5000') .waitForElementNotPresent('.loading-lines', waitTime, false) .waitForElementVisible('.prettyprint', waitTime, false) @@ -62,9 +62,9 @@ module.exports = { editor.getSession().setValue("function (doc) { emit(\'hasehase6000\', 1); }");\ editor._emit(\'blur\');\ ') - .execute('$(".save")[0].scrollIntoView();') + .execute('$("#save-view")[0].scrollIntoView();') - .clickWhenVisible('button.btn-success.save') + .clickWhenVisible('#save-view') .checkForStringPresent(viewUrl, 'hasehase6000') .waitForElementNotPresent('.loading-lines', waitTime, false) @@ -95,8 +95,8 @@ module.exports = { var editor = ace.edit("map-function");\ editor.getSession().setValue("function (doc) { emit(\'newstub\', 2); }");\ ') - .execute('$("button.save")[0].scrollIntoView();') - .clickWhenVisible('button.save', waitTime, false) + .execute('$("#save-view")[0].scrollIntoView();') + .clickWhenVisible('#save-view', waitTime, false) .checkForStringPresent(viewUrl, '40') .waitForElementNotPresent('.loading-lines', waitTime, false) .waitForElementVisible('.prettyprint', waitTime, false) http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/app/addons/documents/views-doceditor.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/views-doceditor.js b/app/addons/documents/views-doceditor.js deleted file mode 100644 index 42c3d31..0000000 --- a/app/addons/documents/views-doceditor.js +++ /dev/null @@ -1,621 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -define([ - 'app', - - 'api', - 'addons/fauxton/components', - 'addons/documents/resources', - 'addons/databases/resources', - - // Plugins - 'plugins/prettify' -], - -function (app, FauxtonAPI, Components, Documents, Databases, prettify) { - - var Views = {}; - - Views.UploadModal = Components.ModalView.extend({ - template: 'addons/documents/templates/upload_modal', - - events: { - 'click #upload-btn': 'uploadFile' - }, - - uploadFile: function (event) { - event.preventDefault(); - - var docRev = this.model.get('_rev'), - file = $('#_attachments')[0].files[0]; - - if (!docRev) { - return this.set_error_msg('The document needs to be saved before adding an attachment.'); - } - - if ($('input[type="file"]')[0].files.length === 0) { - return this.set_error_msg('Selected a file to be uploaded.'); - } - - this.$('#_rev').val(docRev); - - $.ajax({ - url: this.model.url() + '/' + file.name + '?rev=' + docRev, - xhrFields: { - withCredentials: true - }, - type: 'PUT', - data: file, - processData: false, - contentType: file.type, - success: this.success, - error: function (resp) { - this.set_error_msg('Could not upload attachment: ' + JSON.parse(resp.responseText).reason); - return; - }.bind(this) - }); - }, - - success: function (resp) { - var hideModal = this.hideModal, - $form = this.$('#file-upload'); - - FauxtonAPI.triggerRouteEvent('reRenderDoc'); - //slight delay to make this transistion a little more fluid and less jumpy - setTimeout(function () { - this.$('#_attachments').val(''); - this.$('#_rev').val(''); - hideModal(); - $('.modal-backdrop').remove(); - }, 1000); - }, - - uploadProgress: function (event, position, total, percentComplete) { - this.$('.bar').css({width: percentComplete + '%'}); - }, - - beforeSend: function () { - this.$('.progress').removeClass('hide'); - }, - - _showModal: function () { - this.$('.bar').css({width: '0%'}); - this.$('.progress').addClass('hide'); - } - }); - - Views.StringEditModal = Components.ModalView.extend({ - template: 'addons/documents/templates/string_edit_modal', - - initialize: function () { - _.bindAll(this); - }, - - events: { - 'click #string-edit-save-btn': 'saveString' - }, - - saveString: function (event) { - event.preventDefault(); - var newStr = this.subEditor.getValue(); - this.subEditor.editSaved(); - this.editor.replaceCurrentLine(this.indent + this.hashKey + JSON.stringify(newStr) + this.comma + '\n'); - this.hideModal(); - }, - - _showModal: function () { - this.$('.bar').css({width: '0%'}); - this.$('.progress').addClass('hide'); - this.clear_error_msg(); - }, - - openWin: function (editor, indent, hashKey, jsonString, comma) { - this.editor = editor; - this.indent = indent; - this.hashKey = hashKey; - this.$('#string-edit-header').text(hashKey); - this.subEditor.setValue(JSON.parse(jsonString)); - /* make sure we don't have save warnings w/out change */ - this.subEditor.editSaved(); - this.comma = comma; - this.showModal(); - }, - - afterRender: function () { - /* make sure we init only ONCE */ - if (!this.subEditor) { - this.subEditor = new Components.Editor({ - editorId: 'string-editor-container', - mode: 'plain' - }); - - this.subEditor.render().promise().then(function () { - /* optimize by disabling auto sizing (35 is the lines fitting into the pop-up) */ - this.subEditor.configureFixedHeightEditor(35); - }.bind(this)); - } - }, - - cleanup: function () { - if (this.subEditor) { this.subEditor.remove(); } - } - - }); - - /* Doc Duplication modal */ - Views.DuplicateDocModal = Components.ModalView.extend({ - template: 'addons/documents/templates/duplicate_doc_modal', - - initialize: function () { - _.bindAll(this); - }, - - events: { - 'click #duplicate-btn':'duplicate', - 'submit #doc-duplicate': 'duplicate' - }, - - duplicate: function (event) { - event.preventDefault(); - var newId = this.$('#dup-id').val(), - isDDoc = newId.match(/^_design\//), - removeDDocID = newId.replace(/^_design\//, ''), - encodedID = isDDoc ? '_design/' + app.utils.safeURLName(removeDDocID) : app.utils.safeURLName(newId); - - this.hideModal(); - FauxtonAPI.triggerRouteEvent('duplicateDoc', encodedID); - }, - - _showModal: function () { - this.$('.bar').css({width: '0%'}); - this.$('.progress').addClass('hide'); - this.clear_error_msg(); - this.$('.modal').modal(); - // hack to get modal visible - $('.modal-backdrop').css('z-index', 1025); - }, - - showModal: function () { - var showModal = this._showModal, - setDefaultIdValue = this.setDefaultIdValue, - uuid = new FauxtonAPI.UUID(); - - uuid.fetch().then(function () { - setDefaultIdValue(uuid.next()); - showModal(); - }); - }, - - setDefaultIdValue: function (id) { - this.$('#dup-id').val(id); - } - }); - - Views.CodeEditor = FauxtonAPI.View.extend({ - template: 'addons/documents/templates/code_editor', - className: 'editor-content-page', - events: { - 'click button.save-doc': 'saveDoc', - 'click button.delete': 'destroy', - 'click button.duplicate': 'duplicate', - 'click button.upload': 'upload', - 'click button.string-edit': 'stringEditing', - 'click a.js-back': 'onClickGoBack', - 'click .code-region': 'focusOnLastLine' - }, - loaderStyles: { - color: '#ffffff', - opacity: 0.15 - }, - - initialize: function (options) { - this.database = options.database; - _.bindAll(this); - }, - - onClickGoBack: function (e) { - e.preventDefault(); - e.stopPropagation(); - - this.goBack(); - }, - - goBack: function () { - FauxtonAPI.navigate(FauxtonAPI.urls('allDocs', 'app', this.database.id)); - }, - - destroy: function () { - if (this.model.isNewDoc()) { - FauxtonAPI.addNotification({ - msg: 'This document has not been saved yet.', - type: 'warning', - clear: true - }); - return; - } - this.confirmDeleteModal.showModal(); - }, - - deleteDocument: function () { - var database = this.model.database; - - this.model.destroy().then(function () { - FauxtonAPI.addNotification({ - msg: 'Your document has been successfully deleted.', - clear: true - }); - FauxtonAPI.navigate(FauxtonAPI.urls('allDocs', 'app', database.id, '?limit=20')); - }, function () { - FauxtonAPI.addNotification({ - msg: 'Failed to delete your document!', - type: 'error', - clear: true - }); - }); - }, - - upload: function (e) { - e.preventDefault(); - if (this.model.isNewDoc()) { - FauxtonAPI.addNotification({ - msg: 'Please save the document before uploading an attachment.', - type: 'warning', - clear: true - }); - return; - } - this.uploadModal.showModal(); - }, - - duplicate: function (e) { - if (this.model.isNewDoc()) { - FauxtonAPI.addNotification({ - msg: 'Please save the document before duplicating it.', - type: 'warning', - clear: true - }); - return; - } - e.preventDefault(); - this.duplicateModal.showModal(); - }, - - saveDoc: function (event) { - var that = this, - editor = this.editor, - validDoc = this.getDocFromEditor(); - - if (validDoc) { - FauxtonAPI.addNotification({msg: 'Saving document.'}); - - this.model.save().then(function () { - editor.editSaved(); - FauxtonAPI.navigate(FauxtonAPI.urls('document', 'app', that.database.safeID(), that.model.id)); - }).fail(function (xhr) { - var responseText = JSON.parse(xhr.responseText).reason; - FauxtonAPI.addNotification({ - msg: 'Save failed: ' + responseText, - type: 'error', - fade: false, - clear: true - }); - }); - } else if (this.model.validationError && this.model.validationError === 'Cannot change a documents id.') { - FauxtonAPI.addNotification({ - msg: 'Cannot save. Cannot change a documents _id, try Clone Document instead!', - type: 'error', - clear: true - }); - delete this.model.validationError; - } else { - FauxtonAPI.addNotification({ - msg: 'Please fix the JSON errors and try saving again.', - type: 'error', - clear: true - }); - } - }, - - getDocFromEditor: function () { - if (!this.hasValidCode()) { - return false; - } - var json = JSON.parse(this.editor.getValue()); - this.model.clear().set(json, {validate: true}); - if (this.model.validationError) { - return false; - } - return this.model; - }, - - beforeRender: function () { - this.uploadModal = this.setView('#upload-modal', new Views.UploadModal({ model: this.model })); - this.duplicateModal = this.setView('#duplicate-modal', new Views.DuplicateDocModal({ model: this.model })); - this.confirmDeleteModal = this.setView('#delete-doc-modal', new Components.ConfirmationModal({ - text: 'Are you sure you want to delete this document?', - action: this.deleteDocument - })); - - // ensures it's initialized only once - this.stringEditModal = this.stringEditModal || this.setView('#string-edit-modal', new Views.StringEditModal()); - - var extensions = FauxtonAPI.getExtensions('DocEditor:icons'); - _.each(extensions, function (View) { - this.insertView('.doc-editor-extension-icons', new View({ doc: this.model })); - }, this); - }, - - updateValues: function () { - if (this.model.changedAttributes()) { - FauxtonAPI.addNotification({ - msg: 'Document saved successfully.', - type: 'success', - clear: true - }); - this.editor.setValue(this.model.prettyJSON()); - } - }, - - establish: function () { - var promise = this.model.fetch(), - deferred = $.Deferred(), - goBack = _.bind(this.goBack, this); - - promise.then(function () { - deferred.resolve(); - }, function (xhr, reason, msg) { - if (xhr.status === 404) { - FauxtonAPI.addNotification({ - msg: 'The document does not exist', - type: 'error', - clear: true - }); - goBack(); - } - deferred.reject(); - }); - - return deferred; - }, - - hasValidCode: function () { - var errors = this.editor.getAnnotations(); - return errors.length === 0; - }, - - afterRender: function () { - this.listenTo(this.model, 'sync', this.updateValues); - this.editor = new Components.Editor({ - editorId: 'editor-container', - isFullPageEditor: true, - forceMissingId: true, - commands: [{ - name: 'save', - bindKey: {win: 'Ctrl-S', mac: 'Ctrl-S'}, - exec: function (editor) { - this.saveDoc(); - }, - readOnly: true // false if this command should not apply in readOnly mode - }] - }); - - this.editor.render(); - - var editor = this.editor; - var model = this.model; - - // only start listening to editor once it has been rendered - this.editor.promise().then(function () { - - this.listenTo(editor.editor, 'change', function (event) { - var changedDoc; - try { - changedDoc = JSON.parse(editor.getValue()); - } catch (exception) { - //not complete doc. Cannot work with it - return; - } - - var keyChecked = ['_id']; - if (model.get('_rev')) { - keyChecked.push('_rev'); - } - - // check the changedDoc has all the required standard keys - if (_.isEmpty(_.difference(keyChecked, _.keys(changedDoc)))) { - return; - } - - editor.setReadOnly(true); - setTimeout(function () { editor.setReadOnly(false) ;}, 400); - - // use extend so that _id stays at the top of the object with displaying the doc - changedDoc = _.extend({_id: model.id, _rev: model.get('_rev')}, changedDoc); - editor.setValue(JSON.stringify(changedDoc, null, ' ')); - FauxtonAPI.addNotification({ - type: 'error', - msg: "Cannot remove a document's id or revision.", - clear: true - }); - }); - - var showHideEditDocString = _.bind(this.showHideEditDocString, this); - this.listenTo(editor.editor, 'changeSelection', function (event) { - showHideEditDocString(event); - }); - this.listenTo(editor.editor.session, 'changeBackMarker', function (event) { - showHideEditDocString(event); - }); - - // place focus on the editor - editor.editor.focus(); - - }.bind(this)); - }, - - focusOnLastLine: function (e) { - var clickedInEditor = $(e.target).closest('#editor-container'); - if (clickedInEditor.length === 0) { - this.editor.editor.focus(); - var session = this.editor.editor.getSession(); - var count = session.getLength(); - this.editor.editor.gotoLine(count, session.getLine(count - 1).length); - } - }, - - serialize: function () { - return { - doc: this.model, - attachments: this.getAttachments() - }; - }, - - getAttachments: function () { - var attachments = this.model.get('_attachments'); - if (!attachments) { return false; } - - return _.map(attachments, function (att, key) { - return { - fileName: key, - size: att.length, - contentType: att.content_type, - url: this.model.url() + '/' + app.utils.safeURLName(key) - }; - }, this); - }, - - determineStringEditMatch: function (event) { - var selStart = this.editor.getSelectionStart().row; - var selEnd = this.editor.getSelectionEnd().row; - - // one JS(ON) string can't span more than one line - we edit one string, so ensure we don't select several lines - if (selStart >= 0 && selEnd >= 0 && selStart === selEnd && this.editor.isRowExpanded(selStart)) { - var editLine = this.editor.getLine(selStart), - editMatch = editLine.match(/^([ \t]*)(["|'][a-zA-Z0-9_]*["|']: )?(["|'].*["|'],?[ \t]*)$/); - - if (editMatch) { - return editMatch; - } - } - return null; - }, - - showHideEditDocString: function (event) { - this.$('button.string-edit').attr('disabled', 'true'); - if (!this.hasValidCode()) { - return false; - } - var editMatch = this.determineStringEditMatch(event); - if (editMatch) { - this.$('button.string-edit').removeAttr('disabled'); - /* remove the following line (along with CSS) to go back to the toolbar: take the offset top of the editor, go down as many lines as we are positioned including fold and adjust by two pixels as the button is slightly larger than a line */ - var positionFromTop = (this.$('#editor-container').offset().top - 2 + this.editor.getRowHeight() * this.editor.documentToScreenRow(this.editor.getSelectionStart().row)) - 62; - this.$('button.string-edit').css('top', positionFromTop + 'px'); - return true; - } - return false; - }, - - stringEditing: function (event) { - event.preventDefault(); - if (!this.hasValidCode()) { - return; - } - var editMatch = this.determineStringEditMatch(event); - if (editMatch) { - var indent = editMatch[1] || '', - hashKey = editMatch[2] || '', - editText = editMatch[3], - comma = ''; - if (editText.substring(editText.length - 1) === ',') { - editText = editText.substring(0, editText.length - 1); - comma = ','; - } - this.stringEditModal.openWin(this.editor, indent, hashKey, editText, comma); - } - }, - - cleanup: function () { - this.editor && this.editor.remove(); - $('#dashboard').off('click'); - } - }); - - - Views.StringEditModal = Components.ModalView.extend({ - template: 'addons/documents/templates/string_edit_modal', - - events: { - 'click #string-edit-save-btn': 'saveString' - }, - - saveString: function (event) { - event.preventDefault(); - var newStr = this.subEditor.getValue(); - this.subEditor.editSaved(); - this.editor.replaceCurrentLine(this.indent + this.hashKey + JSON.stringify(newStr) + this.comma + '\n'); - this.hideModal(); - }, - - _showModal: function () { - this.$('.bar').css({width: '0%'}); - this.$('.progress').addClass('hide'); - this.clear_error_msg(); - }, - - openWin: function (editor, indent, hashKey, jsonString, comma) { - this.editor = editor; - this.indent = indent; - this.hashKey = hashKey; - this.$('#string-edit-header').text(hashKey); - this.subEditor.setValue(JSON.parse(jsonString)); - /* make sure we don't have save warnings w/out change */ - this.subEditor.editSaved(); - this.comma = comma; - this.showModal(); - }, - - afterRender: function () { - var that = this; - this.$('.modal').on('hide', function (e) { - if (that.subEditor.edited) { - if (!confirm("Close without saving changes?")) { - e.preventDefault(); - return; - } - } - /* make sure we don't have save warnings w/out change */ - that.subEditor.editSaved(); - }); - /* make sure we init only ONCE */ - if (!this.subEditor) { - this.subEditor = new Components.Editor({ - editorId: 'string-editor-container', - mode: 'plain' - }); - - this.subEditor.render().promise().then(function () { - /* optimize by disabling auto sizing (35 is the lines fitting into the pop-up) */ - this.subEditor.configureFixedHeightEditor(35); - }.bind(this)); - } - }, - - cleanup: function () { - if (this.subEditor) { this.subEditor.remove(); } - } - }); - - - return Views; -}); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/app/addons/documents/views.js ---------------------------------------------------------------------- diff --git a/app/addons/documents/views.js b/app/addons/documents/views.js index fa9214b..24f8078 100644 --- a/app/addons/documents/views.js +++ b/app/addons/documents/views.js @@ -25,8 +25,7 @@ define([ "plugins/prettify" ], -function (app, FauxtonAPI, Components, Documents, - Databases, QueryOptions, QueryActions) { +function (app, FauxtonAPI, Components, Documents, Databases, QueryOptions, QueryActions) { var Views = {}; http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/app/addons/fauxton/components.js ---------------------------------------------------------------------- diff --git a/app/addons/fauxton/components.js b/app/addons/fauxton/components.js index 42c8102..00ae7f4 100644 --- a/app/addons/fauxton/components.js +++ b/app/addons/fauxton/components.js @@ -580,223 +580,6 @@ function (app, FauxtonAPI, ace, spin, ZeroClipboard) { } }); - Components.Editor = FauxtonAPI.View.extend({ - initialize: function (options) { - this.editorId = options.editorId; - this.mode = options.mode || "json"; - this.commands = options.commands; - this.theme = options.theme || 'idle_fingers'; - this.couchJSHINT = options.couchJSHINT; - - // going forward we can use flexbox for all editors with a fixed height and drop all custom JS to adjust its height - this.setHeightWithJS = _.has(options, 'setHeightWithJS') ? options.setHeightWithJS : true; - - this.edited = false; - - // the full-page document editor does some extra work to adjust the total height of the editor based - // on available space. This setting ensures that only takes place there, and not with other editor locations - this.isFullPageEditor = options.isFullPageEditor || false; - - var that = this; - this.onPageResize = _.debounce(function () { - if (that.isFullPageEditor) { - that.setAvailableEditorHeight(); - } - that.setHeightToLineCount(); - that.editor.resize(true); - }, 300); - - $(window).on('resize.editor', this.onPageResize); - this.listenTo(FauxtonAPI.Events, FauxtonAPI.constants.EVENTS.NAVBAR_SIZE_CHANGED, this.onPageResize); - - _.bindAll(this); - }, - - afterRender: function () { - this.editor = ace.edit(this.editorId); - this.setAvailableEditorHeight(); - this.setHeightToLineCount(); - this.editor.setTheme("ace/theme/" + this.theme); - - if (this.mode != "plain") { - this.editor.getSession().setMode("ace/mode/" + this.mode); - } - - this.editor.setShowPrintMargin(false); - this.editor.autoScrollEditorIntoView = true; - this.addCommands(); - - if (this.couchJSHINT) { - this.removeIncorrectAnnotations(); - } - - this.editor.getSession().setTabSize(2); - - this.editor.getSession().on('change', function () { - this.setHeightToLineCount(); - this.edited = true; - }.bind(this)); - - $(window).on('beforeunload.editor_' + this.editorId, function () { - if (this.edited) { - return 'Your changes have not been saved. Click cancel to return to the document.'; - } - }.bind(this)); - - FauxtonAPI.beforeUnload('editor_' + this.editorId, function (deferred) { - if (this.edited) { - return 'Your changes have not been saved. Click cancel to return to the document.'; - } - }.bind(this)); - }, - - cleanup: function () { - $(window).off('beforeunload.editor_' + this.editorId); - $(window).off('resize.editor', this.onPageResize); - FauxtonAPI.removeBeforeUnload('editor_' + this.editorId); - this.editor.destroy(); - }, - - // we need to track the possible available height of the editor to tell it how large it can grow vertically - setAvailableEditorHeight: function () { - this.availableEditorHeight = $('.code-region').height(); - }, - - setHeightToLineCount: function () { - if (!this.setHeightWithJS) { - return; - } - var lines = this.editor.getSession().getDocument().getLength(); - - if (this.isFullPageEditor) { - var maxLines = this.getMaxAvailableLinesOnPage(); - lines = lines < maxLines ? lines : maxLines; - } - this.editor.setOptions({ - maxLines: lines - }); - }, - - getMaxAvailableLinesOnPage: function () { - var singleLine = this.getRowHeight(); - return Math.floor(this.availableEditorHeight / singleLine); - }, - - getLines: function () { - return this.editor.getSession().getDocument().getLength(); - }, - - addCommands: function () { - _.each(this.commands, function (command) { - this.editor.commands.addCommand(command); - }, this); - }, - - removeIncorrectAnnotations: function () { - var editor = this.editor, - isIgnorableError = this.isIgnorableError; - - this.editor.getSession().on("changeAnnotation", function () { - var annotations = editor.getSession().getAnnotations(); - - var newAnnotations = _.reduce(annotations, function (annotations, error) { - if (!isIgnorableError(error.raw)) { - annotations.push(error); - } - return annotations; - }, []); - - if (annotations.length !== newAnnotations.length) { - editor.getSession().setAnnotations(newAnnotations); - } - }); - }, - - editSaved: function () { - this.edited = false; - }, - - setReadOnly: function (value) { - return this.editor.setReadOnly(value); - }, - - setValue: function (data, lineNumber) { - lineNumber = lineNumber ? lineNumber : -1; - this.editor.setValue(data, lineNumber); - }, - - getValue: function () { - return this.editor.getValue(); - }, - - getAnnotations: function () { - return this.editor.getSession().getAnnotations(); - }, - - hadValidCode: function () { - var errors = this.getAnnotations(); - // By default CouchDB view functions don't pass lint - return _.every(errors, function (error) { - return this.isIgnorableError(error.raw); - }, this); - }, - - // List of JSHINT errors to ignore - // Gets around problem of anonymous functions not being a valid statement - excludedViewErrors: [ - "Missing name in function declaration.", - "['{a}'] is better written in dot notation." - ], - - isIgnorableError: function (msg) { - return _.contains(this.excludedViewErrors, msg); - }, - - configureFixedHeightEditor: function (numLines) { - this.editor.renderer.setVScrollBarAlwaysVisible(true); - this.editor.renderer.setHScrollBarAlwaysVisible(true); - /* customize the ace scrolling for static edit height */ - this.editor.renderer.$autosize = function () { - this.$size.height = numLines * this.lineHeight; - this.desiredHeight = numLines * this.lineHeight; - this.container.style.height = this.desiredHeight + "px"; - this.scrollBarV.setVisible(true); - this.scrollBarH.setVisible(true); - }; - }, - - replaceCurrentLine: function (replacement) { - this.editor.getSelection().selectLine(); - this.editor.insert(replacement); - this.editor.getSelection().moveCursorUp(); - }, - - getLine: function (lineNum) { - return this.editor.session.getLine(lineNum); - }, - - getSelectionStart: function () { - return this.editor.getSelectionRange().start; - }, - - getSelectionEnd: function () { - return this.editor.getSelectionRange().end; - }, - - getRowHeight: function () { - return this.editor.renderer.layerConfig.lineHeight; - }, - - isRowExpanded: function (row) { - return !this.editor.getSession().isRowFolded(row); - }, - - documentToScreenRow: function (row) { - return this.editor.getSession().documentToScreenRow(row, 0); - } - - }); - //Menu Drop down component. It takes links in this format and renders the Dropdown: // [{ http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/app/addons/fauxton/components.react.jsx ---------------------------------------------------------------------- diff --git a/app/addons/fauxton/components.react.jsx b/app/addons/fauxton/components.react.jsx index fa843c0..4d3776c 100644 --- a/app/addons/fauxton/components.react.jsx +++ b/app/addons/fauxton/components.react.jsx @@ -269,12 +269,63 @@ function (app, FauxtonAPI, React, ZeroClipboard) { }); + // A super-simple replacement for window.confirm() + var ConfirmationModal = React.createClass({ + propTypes: { + visible: React.PropTypes.bool.isRequired, + text: React.PropTypes.string.isRequired, + onClose: React.PropTypes.func.isRequired, + onSubmit: React.PropTypes.func.isRequired + }, + + getDefaultProps: function () { + return { + visible: false, + title: 'Please confirm', + text: '', + onClose: function () { }, + onSubmit: function () { } + }; + }, + + componentDidUpdate: function () { + var params = (this.props.visible) ? { show: true, backdrop: 'static', keyboard: true } : 'hide'; + $(this.getDOMNode()).modal(params); + + $(this.getDOMNode()).on('hidden.bs.modal', function () { + this.props.onClose(); + }.bind(this)); + }, + + render: function () { + return ( + <div className="modal hide confirmation-modal fade" tabIndex="-1" data-js-visible={this.props.visible}> + <div className="modal-header"> + <button type="button" className="close" onClick={this.props.onClose} aria-hidden="true">×</button> + <h3>{this.props.title}</h3> + </div> + <div className="modal-body"> + <p> + {this.props.text} + </p> + </div> + <div className="modal-footer"> + <button className="btn" onClick={this.props.onClose}><i className="icon fonticon-cancel-circled"></i> Cancel</button> + <button className="btn btn-success js-btn-success" onClick={this.props.onSubmit}><i className="fonticon-ok-circled"></i> Okay</button> + </div> + </div> + ); + } + }); + + return { Clipboard: Clipboard, ClipboardWithTextField: ClipboardWithTextField, CodeFormat: CodeFormat, Tray: Tray, - Pagination: Pagination + Pagination: Pagination, + ConfirmationModal: ConfirmationModal }; }); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/assets/less/code-editors.less ---------------------------------------------------------------------- diff --git a/assets/less/code-editors.less b/assets/less/code-editors.less new file mode 100644 index 0000000..25edcf5 --- /dev/null +++ b/assets/less/code-editors.less @@ -0,0 +1,53 @@ +// 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. + + +/* site-wide Ace Editor theme overrides */ + +.ace_scrollbar-h { + right: 0 !important; + height: 15px !important; +} + +body { + .ace-idle-fingers .ace_marker-layer .ace_selection { + background: #015F6F; + } + .ace-idle-fingers .ace_gutter { + background: #3A3A3A; + } + .ace-idle-fingers { + background-color: #4d4d4d; + } + .ace-idle-fingers .ace_cursor { + color: #ffffff; + } + .ace-idle-fingers.ace_multiselect .ace_selection.ace_start { + box-shadow: 0 0 3px 0 #4d4d4d; + } + .ace-idle-fingers .ace_marker-layer .ace_active-line { + background: #000000; + opacity: 0.4; + } + .ace-idle-fingers .ace_constant { + color: #72cdf4; + } + .ace-idle-fingers .ace_boolean { + color: #ff6532; + } + .ace-idle-fingers .ace_string { + color: #29be9d; + } + .ace-idle-fingers .ace_collab.ace_user1 { + color: #4d4d4d; + } +} http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/assets/less/codeeditor.less ---------------------------------------------------------------------- diff --git a/assets/less/codeeditor.less b/assets/less/codeeditor.less deleted file mode 100644 index a08e309..0000000 --- a/assets/less/codeeditor.less +++ /dev/null @@ -1,192 +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. - -@import "mixins.less"; - - -#dashboard.doc-editor-page { - background-color: #4d4d4d; - - #dashboard-content { - padding-bottom: 0px; - top: 0px; - } -} - -.doc-editor-page { - border-left: none; - - .fixed-header { - height: 65px; - .box-shadow(none); - } - - #breadcrumbs { - white-space: nowrap; - } - - #doc-editor-actions-panel { - position: absolute; - top: 64px; - right: 0px; - left: 0px; - width: 100%; - background-color: #f1f1f1; - height: 61px; - } - - #editor-container { - margin-top: 0px; - font-size: 13px; - line-height: 22px; - padding-bottom: 15px; - } - - .doc-actions-left { - float: left; - padding: 9px 0px; - button { - margin: 0px 10px 0px 30px; - } - div { - display: inline-block; - } - } - - .cancel-button { - font-size: 14px; - } - - .bgEditorGutter { - width: 49px; - position: absolute; - top: 0px; - bottom: 0px; - background-color: #3b3b3b; - } - - .panel-button { - border: 0px; - background-color: #f1f1f1; - padding: 11px; - color: #555555; - - span:first-of-type { - margin-left: 4px; - } - - .icon { - font-size: 18px; - } - } - .panel-section { - border-left: 1px solid #cccccc; - text-align: center; - padding: 9px 0px; - display: inline-block; - - &.open .dropdown-toggle { - box-shadow: none; - background-color: white; - } - } - .alignRight { - text-align: right; - font-size: 0; // prevents whitespace gaps between elements - } - .row-fluid.content-area { - background-color: #4d4d4d; - } - - // overriding the ace editor inline styles - .ace_gutter-layer { - min-width: 49px; - } - .ace_gutter-cell { - min-width: 49px; - } - - .ace_marker-layer .ace_bracket { - margin: 0px; - border: 1px solid #999999; - } - - // hide the labels on the buttons when the screen is shrunk too small, - @media screen and (max-width: 1000px) { - .panel-button span { - display: none; - } - } - - // hides the API Url header link when the page is too small (prevents wrapping) - @media screen and (max-width: 835px) { - #api-navbar { - display: none; - } - } - - #dashboard-content .code-region { - overflow-y: hidden; - position: absolute; - top: 125px; - height: auto; - width: 100%; - padding: 0; - left: 0; - right: 0; - bottom: 0; - } -} - -.ace_scrollbar-h { - right: 0px !important; - height: 15px !important; -} - -#editor-container { - height: 100% !important; -} - -/* Ace theme overrides */ -body { - .ace-idle-fingers .ace_marker-layer .ace_selection { - background: #015F6F; - } - .ace-idle-fingers .ace_gutter { - background: #3A3A3A; - } - .ace-idle-fingers { - background-color: #4d4d4d; - } - .ace-idle-fingers .ace_cursor { - color: #ffffff; - } - .ace-idle-fingers.ace_multiselect .ace_selection.ace_start { - box-shadow: 0 0 3px 0 #4d4d4d; - } - .ace-idle-fingers .ace_marker-layer .ace_active-line { - background: #000000; - opacity: 0.4; - } - .ace-idle-fingers .ace_constant { - color: #72cdf4; - } - .ace-idle-fingers .ace_boolean { - color: #ff6532; - } - .ace-idle-fingers .ace_string { - color: #29be9d; - } - .ace-idle-fingers .ace_collab.ace_user1 { - color: #4d4d4d; - } -} http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8cd744ac/assets/less/fauxton.less ---------------------------------------------------------------------- diff --git a/assets/less/fauxton.less b/assets/less/fauxton.less index 14e7f07..477b0bf 100644 --- a/assets/less/fauxton.less +++ b/assets/less/fauxton.less @@ -16,7 +16,7 @@ @import "layouts.less"; @import "prettyprint.less"; @import "icons.less"; -@import "codeeditor.less"; +@import "code-editors.less"; @import "templates.less"; @import "formstyles.less"; @import "pagination.less";