core/modules/edit/js/edit.js | 90 +++++++++----------- core/modules/edit/js/editors/formEditor.js | 4 +- .../edit/js/views/propertyeditordecoration-view.js | 6 +- core/modules/edit/js/views/toolbar-view.js | 4 +- 4 files changed, 49 insertions(+), 55 deletions(-) diff --git a/core/modules/edit/js/edit.js b/core/modules/edit/js/edit.js index 1f836c1..cad2b07 100644 --- a/core/modules/edit/js/edit.js +++ b/core/modules/edit/js/edit.js @@ -322,7 +322,7 @@ $.extend(Drupal.edit, { // First, set up decoration views. app.decorate(fieldModel); // Second, change the field's state. - fieldModel.setState('candidate'); + fieldModel.set('state', 'candidate'); }); } else { @@ -330,7 +330,7 @@ $.extend(Drupal.edit, { // the 'inactive' state. entityModel.get('fields').each(function (fieldModel) { // First, change the field's state. - fieldModel.setState('inactive', { reason: 'stop' }); + fieldModel.set('state', 'inactive', { reason: 'stop' }); // Second, tear down decoration views. app.undecorate(fieldModel); }); @@ -426,16 +426,18 @@ $.extend(Drupal.edit, { } // Confirm this transition. else { + // Do not accept this change right now, instead open a modal + // that will ask the user to confirm his choice. + accept = false; // The callback will be called from the helper function. this._confirmStopEditing(callback); - return; } } } } } - callback(accept); + return accept; }, // @todo rename to decorateField @@ -496,13 +498,9 @@ $.extend(Drupal.edit, { /** * Asks the user to confirm whether he wants to stop editing via a modal. * - * @param acceptCallback - * The callback function as passed to acceptEditorStateChange(). This - * callback function will be called with the user's choice. - * * @see acceptEditorStateChange() */ - _confirmStopEditing: function(acceptCallback) { + _confirmStopEditing: function () { // Only instantiate if there isn't a modal instance visible yet. if (!this.model.get('activeModal')) { var that = this; @@ -516,14 +514,9 @@ $.extend(Drupal.edit, { callback: function(action) { // The active modal has been removed. that.model.set('activeModal', null); - if (action === 'discard') { - acceptCallback(true); - } - else { - acceptCallback(false); - var editor = that.model.get('activeEditor'); - editor.options.widget.setState('saving', editor.options.property); - } + // Set the state that matches the user's action. + var targetState = (action === 'discard') ? 'candidate' : 'saving'; + that.model.get('activeEditor').set('state', 'candidate', { confirmed: true }); } }); this.model.set('activeModal', modal); @@ -531,10 +524,6 @@ $.extend(Drupal.edit, { // to prevent multiple modals from being instantiated. modal.render(); } - else { - // Reject as there is still an open transition waiting for confirmation. - acceptCallback(false); - } }, /** @@ -568,11 +557,12 @@ $.extend(Drupal.edit, { else if (this.model.get('activeEditor') === fieldModel && to === 'candidate') { // Discarded if it transitions from a changed state to 'candidate'. if (from === 'changed' || from === 'invalid') { + // @todo FIX THIS! // Retrieve the storage widget from DOM. - var createStorageWidget = this.$el.data('DrupalCreateStorage'); + // var createStorageWidget = this.$el.data('DrupalCreateStorage'); // Revert changes in the model, this will trigger the direct editable // content to be reset and redrawn. - createStorageWidget.revertChanges(fieldModel.options.entity); + // createStorageWidget.revertChanges(fieldModel.options.entity); } this.model.set('activeEditor', null); } @@ -682,6 +672,28 @@ $.extend(Drupal.edit, { }, initialize: function () { this.get('entity').get('fields').add(this); + this.on('error', function(model, error) { + console.log('%c' + model.get("editID") + " " + error, 'color: orange'); + }); + }, + validate: function (attrs, options) { + // We only care about validating the 'state' attribute. + if (!_.has(attrs, 'state')) { + return; + } + + var current = this.get('state'); + var next = attrs.state; + if (current !== next) { + // Ensure it's a valid state. + if (_.indexOf(this.constructor.states, next) === -1) { + return '"' + next + '" is an invalid state'; + } + // Check if the acceptStateChange callback accepts it. + if (!this.get('acceptStateChange')(current, next, options)) { + return 'state change not accepted'; + } + } }, // @see VIE.prototype.EditService.prototype.getElementSubject() // Parses the `/` part from the edit ID. @@ -692,32 +704,14 @@ $.extend(Drupal.edit, { // Parses the `//` part from the edit ID. getFieldID: function() { return this.get('editID').split('/').slice(2, 5).join('/'); - }, - // Always call this method, never call .set('state'), because we need to call - // the acceptStateChange callback first - // @see Create.js' setState() - setState: function (state, context, callback) { - // @todo propagate to the entity in some way? I don't think this is - // actually necessary; the entity can listen on its collection of fields - // for changes to the state of any of its fields! - var current = this.get('state'); - var next = state; - // Only attempt to change the state if it's a different state. - if (current !== next) { - var acceptStateChange = this.get('acceptStateChange'); - var that = this; - acceptStateChange(current, next, context, function (accepted) { - if (accepted) { - that.set('state', next); - } - // @todo can't we get rid of this? - if (_.isFunction(callback)) { - callback(accepted); - } - }); - } - return this; } + }, { + states: [ + 'inactive', 'candidate', 'highlighted', + 'activating', 'active', 'changed', 'saving', 'saved', 'invalid' + ], + activeEditorStates: ['activating', 'active'], + singleEditorStates: ['highlighted', 'activating', 'active'] }), // A collection of EditableModels. diff --git a/core/modules/edit/js/editors/formEditor.js b/core/modules/edit/js/editors/formEditor.js index 1430e8d..b62bfe3 100644 --- a/core/modules/edit/js/editors/formEditor.js +++ b/core/modules/edit/js/editors/formEditor.js @@ -73,7 +73,7 @@ Drupal.edit.editors.form = Backbone.View.extend({ that.$formContainer .on('formUpdated.edit', ':input', function () { // Sets the state to 'changed'. - that.model.setState('changed'); + that.model.set('state', 'changed'); }) .on('keypress.edit', 'input', function (event) { if (event.keyCode === 13) { @@ -82,7 +82,7 @@ Drupal.edit.editors.form = Backbone.View.extend({ }); // The in-place editor has loaded; change state to 'active'. - that.model.setState('active'); + that.model.set('state', 'active'); }); }, diff --git a/core/modules/edit/js/views/propertyeditordecoration-view.js b/core/modules/edit/js/views/propertyeditordecoration-view.js index 75f926b..91d544e 100644 --- a/core/modules/edit/js/views/propertyeditordecoration-view.js +++ b/core/modules/edit/js/views/propertyeditordecoration-view.js @@ -103,7 +103,7 @@ Drupal.edit.PropertyEditorDecorationView = Backbone.View.extend({ onMouseEnter: function(event) { var that = this; this._ignoreHoveringVia(event, '#' + this.toolbarId, function () { - that.model.setState('highlighted'); + that.model.set('state', 'highlighted'); event.stopPropagation(); }); }, @@ -116,7 +116,7 @@ Drupal.edit.PropertyEditorDecorationView = Backbone.View.extend({ onMouseLeave: function(event) { var that = this; this._ignoreHoveringVia(event, '#' + this.toolbarId, function () { - that.model.setState('candidate', { reason: 'mouseleave' }); + that.model.set('state', 'candidate', { reason: 'mouseleave' }); event.stopPropagation(); }); }, @@ -127,7 +127,7 @@ Drupal.edit.PropertyEditorDecorationView = Backbone.View.extend({ * @param event */ onClick: function(event) { - this.model.setState('activating'); + this.model.set('state', 'activating'); event.preventDefault(); event.stopPropagation(); }, diff --git a/core/modules/edit/js/views/toolbar-view.js b/core/modules/edit/js/views/toolbar-view.js index ce15fe5..359ad81 100644 --- a/core/modules/edit/js/views/toolbar-view.js +++ b/core/modules/edit/js/views/toolbar-view.js @@ -171,7 +171,7 @@ Drupal.edit.ToolbarView = Backbone.View.extend({ onClickSave: function(event) { event.stopPropagation(); event.preventDefault(); - this.model.setState('saving'); + this.model.set('state', 'saving'); }, /** @@ -182,7 +182,7 @@ Drupal.edit.ToolbarView = Backbone.View.extend({ onClickClose: function(event) { event.stopPropagation(); event.preventDefault(); - this.model.setState('candidate', { reason: 'cancel' }); + this.model.set('state', 'candidate', { reason: 'cancel' }); }, /**