diff core/modules/quickedit/js/models/EntityModel.js @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 1fec387a4317
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/modules/quickedit/js/models/EntityModel.js	Wed Nov 29 16:09:58 2017 +0000
@@ -0,0 +1,319 @@
+/**
+* DO NOT EDIT THIS FILE.
+* See the following change record for more information,
+* https://www.drupal.org/node/2815083
+* @preserve
+**/
+
+(function (_, $, Backbone, Drupal) {
+  Drupal.quickedit.EntityModel = Drupal.quickedit.BaseModel.extend({
+    defaults: {
+      el: null,
+
+      entityID: null,
+
+      entityInstanceID: null,
+
+      id: null,
+
+      label: null,
+
+      fields: null,
+
+      isActive: false,
+
+      inTempStore: false,
+
+      isDirty: false,
+
+      isCommitting: false,
+
+      state: 'closed',
+
+      fieldsInTempStore: [],
+
+      reload: false
+    },
+
+    initialize: function initialize() {
+      this.set('fields', new Drupal.quickedit.FieldCollection());
+
+      this.listenTo(this, 'change:state', this.stateChange);
+
+      this.listenTo(this.get('fields'), 'change:state', this.fieldStateChange);
+
+      Drupal.quickedit.BaseModel.prototype.initialize.call(this);
+    },
+    stateChange: function stateChange(entityModel, state, options) {
+      var to = state;
+      switch (to) {
+        case 'closed':
+          this.set({
+            isActive: false,
+            inTempStore: false,
+            isDirty: false
+          });
+          break;
+
+        case 'launching':
+          break;
+
+        case 'opening':
+          entityModel.get('fields').each(function (fieldModel) {
+            fieldModel.set('state', 'candidate', options);
+          });
+          break;
+
+        case 'opened':
+          this.set('isActive', true);
+          break;
+
+        case 'committing':
+          var fields = this.get('fields');
+
+          fields.chain().filter(function (fieldModel) {
+            return _.intersection([fieldModel.get('state')], ['active']).length;
+          }).each(function (fieldModel) {
+            fieldModel.set('state', 'candidate');
+          });
+
+          fields.chain().filter(function (fieldModel) {
+            return _.intersection([fieldModel.get('state')], Drupal.quickedit.app.changedFieldStates).length;
+          }).each(function (fieldModel) {
+            fieldModel.set('state', 'saving');
+          });
+          break;
+
+        case 'deactivating':
+          var changedFields = this.get('fields').filter(function (fieldModel) {
+            return _.intersection([fieldModel.get('state')], ['changed', 'invalid']).length;
+          });
+
+          if ((changedFields.length || this.get('fieldsInTempStore').length) && !options.saved && !options.confirmed) {
+            this.set('state', 'opened', { confirming: true });
+
+            _.defer(function () {
+              Drupal.quickedit.app.confirmEntityDeactivation(entityModel);
+            });
+          } else {
+            var invalidFields = this.get('fields').filter(function (fieldModel) {
+              return _.intersection([fieldModel.get('state')], ['invalid']).length;
+            });
+
+            entityModel.set('reload', this.get('fieldsInTempStore').length || invalidFields.length);
+
+            entityModel.get('fields').each(function (fieldModel) {
+              if (_.intersection([fieldModel.get('state')], ['candidate', 'highlighted']).length) {
+                fieldModel.trigger('change:state', fieldModel, fieldModel.get('state'), options);
+              } else {
+                fieldModel.set('state', 'candidate', options);
+              }
+            });
+          }
+          break;
+
+        case 'closing':
+          options.reason = 'stop';
+          this.get('fields').each(function (fieldModel) {
+            fieldModel.set({
+              inTempStore: false,
+              state: 'inactive'
+            }, options);
+          });
+          break;
+      }
+    },
+    _updateInTempStoreAttributes: function _updateInTempStoreAttributes(entityModel, fieldModel) {
+      var current = fieldModel.get('state');
+      var previous = fieldModel.previous('state');
+      var fieldsInTempStore = entityModel.get('fieldsInTempStore');
+
+      if (current === 'saved') {
+        entityModel.set('inTempStore', true);
+
+        fieldModel.set('inTempStore', true);
+
+        fieldsInTempStore.push(fieldModel.get('fieldID'));
+        fieldsInTempStore = _.uniq(fieldsInTempStore);
+        entityModel.set('fieldsInTempStore', fieldsInTempStore);
+      } else if (current === 'candidate' && previous === 'inactive') {
+          fieldModel.set('inTempStore', _.intersection([fieldModel.get('fieldID')], fieldsInTempStore).length > 0);
+        }
+    },
+    fieldStateChange: function fieldStateChange(fieldModel, state) {
+      var entityModel = this;
+      var fieldState = state;
+
+      switch (this.get('state')) {
+        case 'closed':
+        case 'launching':
+          break;
+
+        case 'opening':
+          _.defer(function () {
+            entityModel.set('state', 'opened', {
+              'accept-field-states': Drupal.quickedit.app.readyFieldStates
+            });
+          });
+          break;
+
+        case 'opened':
+          if (fieldState === 'changed') {
+            entityModel.set('isDirty', true);
+          } else {
+            this._updateInTempStoreAttributes(entityModel, fieldModel);
+          }
+          break;
+
+        case 'committing':
+          if (fieldState === 'invalid') {
+            _.defer(function () {
+              entityModel.set('state', 'opened', { reason: 'invalid' });
+            });
+          } else {
+            this._updateInTempStoreAttributes(entityModel, fieldModel);
+          }
+
+          var options = {
+            'accept-field-states': Drupal.quickedit.app.readyFieldStates
+          };
+          if (entityModel.set('isCommitting', true, options)) {
+            entityModel.save({
+              success: function success() {
+                entityModel.set({
+                  state: 'deactivating',
+                  isCommitting: false
+                }, { saved: true });
+              },
+              error: function error() {
+                entityModel.set('isCommitting', false);
+
+                entityModel.set('state', 'opened', { reason: 'networkerror' });
+
+                var message = Drupal.t('Your changes to <q>@entity-title</q> could not be saved, either due to a website problem or a network connection problem.<br>Please try again.', { '@entity-title': entityModel.get('label') });
+                Drupal.quickedit.util.networkErrorModal(Drupal.t('Network problem!'), message);
+              }
+            });
+          }
+          break;
+
+        case 'deactivating':
+          _.defer(function () {
+            entityModel.set('state', 'closing', {
+              'accept-field-states': Drupal.quickedit.app.readyFieldStates
+            });
+          });
+          break;
+
+        case 'closing':
+          _.defer(function () {
+            entityModel.set('state', 'closed', {
+              'accept-field-states': ['inactive']
+            });
+          });
+          break;
+      }
+    },
+    save: function save(options) {
+      var entityModel = this;
+
+      var entitySaverAjax = Drupal.ajax({
+        url: Drupal.url('quickedit/entity/' + entityModel.get('entityID')),
+        error: function error() {
+          options.error.call(entityModel);
+        }
+      });
+
+      entitySaverAjax.commands.quickeditEntitySaved = function (ajax, response, status) {
+        entityModel.get('fields').each(function (fieldModel) {
+          fieldModel.set('inTempStore', false);
+        });
+        entityModel.set('inTempStore', false);
+        entityModel.set('fieldsInTempStore', []);
+
+        if (options.success) {
+          options.success.call(entityModel);
+        }
+      };
+
+      entitySaverAjax.execute();
+    },
+    validate: function validate(attrs, options) {
+      var acceptedFieldStates = options['accept-field-states'] || [];
+
+      var currentState = this.get('state');
+      var nextState = attrs.state;
+      if (currentState !== nextState) {
+        if (_.indexOf(this.constructor.states, nextState) === -1) {
+          return '"' + nextState + '" is an invalid state';
+        }
+
+        if (!this._acceptStateChange(currentState, nextState, options)) {
+          return 'state change not accepted';
+        } else if (!this._fieldsHaveAcceptableStates(acceptedFieldStates)) {
+            return 'state change not accepted because fields are not in acceptable state';
+          }
+      }
+
+      var currentIsCommitting = this.get('isCommitting');
+      var nextIsCommitting = attrs.isCommitting;
+      if (currentIsCommitting === false && nextIsCommitting === true) {
+        if (!this._fieldsHaveAcceptableStates(acceptedFieldStates)) {
+          return 'isCommitting change not accepted because fields are not in acceptable state';
+        }
+      } else if (currentIsCommitting === true && nextIsCommitting === true) {
+        return 'isCommitting is a mutex, hence only changes are allowed';
+      }
+    },
+    _acceptStateChange: function _acceptStateChange(from, to, context) {
+      var accept = true;
+
+      if (!this.constructor.followsStateSequence(from, to)) {
+        accept = false;
+
+        if (from === 'closing' && to === 'closed') {
+          accept = true;
+        } else if (from === 'committing' && to === 'opened' && context.reason && (context.reason === 'invalid' || context.reason === 'networkerror')) {
+            accept = true;
+          } else if (from === 'deactivating' && to === 'opened' && context.confirming) {
+              accept = true;
+            } else if (from === 'opened' && to === 'deactivating' && context.confirmed) {
+                accept = true;
+              }
+      }
+
+      return accept;
+    },
+    _fieldsHaveAcceptableStates: function _fieldsHaveAcceptableStates(acceptedFieldStates) {
+      var accept = true;
+
+      if (acceptedFieldStates.length > 0) {
+        var fieldStates = this.get('fields').pluck('state') || [];
+
+        if (_.difference(fieldStates, acceptedFieldStates).length) {
+          accept = false;
+        }
+      }
+
+      return accept;
+    },
+    destroy: function destroy(options) {
+      Drupal.quickedit.BaseModel.prototype.destroy.call(this, options);
+
+      this.stopListening();
+
+      this.get('fields').reset();
+    },
+    sync: function sync() {}
+  }, {
+    states: ['closed', 'launching', 'opening', 'opened', 'committing', 'deactivating', 'closing'],
+
+    followsStateSequence: function followsStateSequence(from, to) {
+      return _.indexOf(this.states, from) < _.indexOf(this.states, to);
+    }
+  });
+
+  Drupal.quickedit.EntityCollection = Backbone.Collection.extend({
+    model: Drupal.quickedit.EntityModel
+  });
+})(_, jQuery, Backbone, Drupal);
\ No newline at end of file