annotate core/modules/quickedit/js/models/EntityModel.js @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 /**
Chris@0 2 * DO NOT EDIT THIS FILE.
Chris@0 3 * See the following change record for more information,
Chris@0 4 * https://www.drupal.org/node/2815083
Chris@0 5 * @preserve
Chris@0 6 **/
Chris@0 7
Chris@0 8 (function (_, $, Backbone, Drupal) {
Chris@0 9 Drupal.quickedit.EntityModel = Drupal.quickedit.BaseModel.extend({
Chris@0 10 defaults: {
Chris@0 11 el: null,
Chris@0 12
Chris@0 13 entityID: null,
Chris@0 14
Chris@0 15 entityInstanceID: null,
Chris@0 16
Chris@0 17 id: null,
Chris@0 18
Chris@0 19 label: null,
Chris@0 20
Chris@0 21 fields: null,
Chris@0 22
Chris@0 23 isActive: false,
Chris@0 24
Chris@0 25 inTempStore: false,
Chris@0 26
Chris@0 27 isDirty: false,
Chris@0 28
Chris@0 29 isCommitting: false,
Chris@0 30
Chris@0 31 state: 'closed',
Chris@0 32
Chris@0 33 fieldsInTempStore: [],
Chris@0 34
Chris@0 35 reload: false
Chris@0 36 },
Chris@0 37
Chris@0 38 initialize: function initialize() {
Chris@0 39 this.set('fields', new Drupal.quickedit.FieldCollection());
Chris@0 40
Chris@0 41 this.listenTo(this, 'change:state', this.stateChange);
Chris@0 42
Chris@0 43 this.listenTo(this.get('fields'), 'change:state', this.fieldStateChange);
Chris@0 44
Chris@0 45 Drupal.quickedit.BaseModel.prototype.initialize.call(this);
Chris@0 46 },
Chris@0 47 stateChange: function stateChange(entityModel, state, options) {
Chris@0 48 var to = state;
Chris@0 49 switch (to) {
Chris@0 50 case 'closed':
Chris@0 51 this.set({
Chris@0 52 isActive: false,
Chris@0 53 inTempStore: false,
Chris@0 54 isDirty: false
Chris@0 55 });
Chris@0 56 break;
Chris@0 57
Chris@0 58 case 'launching':
Chris@0 59 break;
Chris@0 60
Chris@0 61 case 'opening':
Chris@0 62 entityModel.get('fields').each(function (fieldModel) {
Chris@0 63 fieldModel.set('state', 'candidate', options);
Chris@0 64 });
Chris@0 65 break;
Chris@0 66
Chris@0 67 case 'opened':
Chris@0 68 this.set('isActive', true);
Chris@0 69 break;
Chris@0 70
Chris@0 71 case 'committing':
Chris@14 72 {
Chris@14 73 var fields = this.get('fields');
Chris@0 74
Chris@14 75 fields.chain().filter(function (fieldModel) {
Chris@14 76 return _.intersection([fieldModel.get('state')], ['active']).length;
Chris@14 77 }).each(function (fieldModel) {
Chris@14 78 fieldModel.set('state', 'candidate');
Chris@14 79 });
Chris@0 80
Chris@14 81 fields.chain().filter(function (fieldModel) {
Chris@14 82 return _.intersection([fieldModel.get('state')], Drupal.quickedit.app.changedFieldStates).length;
Chris@14 83 }).each(function (fieldModel) {
Chris@14 84 fieldModel.set('state', 'saving');
Chris@14 85 });
Chris@14 86 break;
Chris@14 87 }
Chris@0 88
Chris@0 89 case 'deactivating':
Chris@14 90 {
Chris@14 91 var changedFields = this.get('fields').filter(function (fieldModel) {
Chris@14 92 return _.intersection([fieldModel.get('state')], ['changed', 'invalid']).length;
Chris@0 93 });
Chris@0 94
Chris@14 95 if ((changedFields.length || this.get('fieldsInTempStore').length) && !options.saved && !options.confirmed) {
Chris@14 96 this.set('state', 'opened', { confirming: true });
Chris@0 97
Chris@14 98 _.defer(function () {
Chris@14 99 Drupal.quickedit.app.confirmEntityDeactivation(entityModel);
Chris@14 100 });
Chris@14 101 } else {
Chris@14 102 var invalidFields = this.get('fields').filter(function (fieldModel) {
Chris@14 103 return _.intersection([fieldModel.get('state')], ['invalid']).length;
Chris@14 104 });
Chris@14 105
Chris@14 106 entityModel.set('reload', this.get('fieldsInTempStore').length || invalidFields.length);
Chris@14 107
Chris@14 108 entityModel.get('fields').each(function (fieldModel) {
Chris@14 109 if (_.intersection([fieldModel.get('state')], ['candidate', 'highlighted']).length) {
Chris@14 110 fieldModel.trigger('change:state', fieldModel, fieldModel.get('state'), options);
Chris@14 111 } else {
Chris@14 112 fieldModel.set('state', 'candidate', options);
Chris@14 113 }
Chris@14 114 });
Chris@14 115 }
Chris@14 116 break;
Chris@0 117 }
Chris@0 118
Chris@0 119 case 'closing':
Chris@0 120 options.reason = 'stop';
Chris@0 121 this.get('fields').each(function (fieldModel) {
Chris@0 122 fieldModel.set({
Chris@0 123 inTempStore: false,
Chris@0 124 state: 'inactive'
Chris@0 125 }, options);
Chris@0 126 });
Chris@0 127 break;
Chris@0 128 }
Chris@0 129 },
Chris@0 130 _updateInTempStoreAttributes: function _updateInTempStoreAttributes(entityModel, fieldModel) {
Chris@0 131 var current = fieldModel.get('state');
Chris@0 132 var previous = fieldModel.previous('state');
Chris@0 133 var fieldsInTempStore = entityModel.get('fieldsInTempStore');
Chris@0 134
Chris@0 135 if (current === 'saved') {
Chris@0 136 entityModel.set('inTempStore', true);
Chris@0 137
Chris@0 138 fieldModel.set('inTempStore', true);
Chris@0 139
Chris@0 140 fieldsInTempStore.push(fieldModel.get('fieldID'));
Chris@0 141 fieldsInTempStore = _.uniq(fieldsInTempStore);
Chris@0 142 entityModel.set('fieldsInTempStore', fieldsInTempStore);
Chris@0 143 } else if (current === 'candidate' && previous === 'inactive') {
Chris@0 144 fieldModel.set('inTempStore', _.intersection([fieldModel.get('fieldID')], fieldsInTempStore).length > 0);
Chris@0 145 }
Chris@0 146 },
Chris@0 147 fieldStateChange: function fieldStateChange(fieldModel, state) {
Chris@0 148 var entityModel = this;
Chris@0 149 var fieldState = state;
Chris@0 150
Chris@0 151 switch (this.get('state')) {
Chris@0 152 case 'closed':
Chris@0 153 case 'launching':
Chris@0 154 break;
Chris@0 155
Chris@0 156 case 'opening':
Chris@0 157 _.defer(function () {
Chris@0 158 entityModel.set('state', 'opened', {
Chris@0 159 'accept-field-states': Drupal.quickedit.app.readyFieldStates
Chris@0 160 });
Chris@0 161 });
Chris@0 162 break;
Chris@0 163
Chris@0 164 case 'opened':
Chris@0 165 if (fieldState === 'changed') {
Chris@0 166 entityModel.set('isDirty', true);
Chris@0 167 } else {
Chris@0 168 this._updateInTempStoreAttributes(entityModel, fieldModel);
Chris@0 169 }
Chris@0 170 break;
Chris@0 171
Chris@0 172 case 'committing':
Chris@14 173 {
Chris@14 174 if (fieldState === 'invalid') {
Chris@14 175 _.defer(function () {
Chris@14 176 entityModel.set('state', 'opened', { reason: 'invalid' });
Chris@14 177 });
Chris@14 178 } else {
Chris@14 179 this._updateInTempStoreAttributes(entityModel, fieldModel);
Chris@14 180 }
Chris@14 181
Chris@14 182 var options = {
Chris@14 183 'accept-field-states': Drupal.quickedit.app.readyFieldStates
Chris@14 184 };
Chris@14 185 if (entityModel.set('isCommitting', true, options)) {
Chris@14 186 entityModel.save({
Chris@14 187 success: function success() {
Chris@14 188 entityModel.set({
Chris@14 189 state: 'deactivating',
Chris@14 190 isCommitting: false
Chris@14 191 }, { saved: true });
Chris@14 192 },
Chris@14 193 error: function error() {
Chris@14 194 entityModel.set('isCommitting', false);
Chris@14 195
Chris@17 196 entityModel.set('state', 'opened', {
Chris@17 197 reason: 'networkerror'
Chris@17 198 });
Chris@14 199
Chris@14 200 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') });
Chris@14 201 Drupal.quickedit.util.networkErrorModal(Drupal.t('Network problem!'), message);
Chris@14 202 }
Chris@14 203 });
Chris@14 204 }
Chris@14 205 break;
Chris@0 206 }
Chris@0 207
Chris@0 208 case 'deactivating':
Chris@0 209 _.defer(function () {
Chris@0 210 entityModel.set('state', 'closing', {
Chris@0 211 'accept-field-states': Drupal.quickedit.app.readyFieldStates
Chris@0 212 });
Chris@0 213 });
Chris@0 214 break;
Chris@0 215
Chris@0 216 case 'closing':
Chris@0 217 _.defer(function () {
Chris@0 218 entityModel.set('state', 'closed', {
Chris@0 219 'accept-field-states': ['inactive']
Chris@0 220 });
Chris@0 221 });
Chris@0 222 break;
Chris@0 223 }
Chris@0 224 },
Chris@0 225 save: function save(options) {
Chris@0 226 var entityModel = this;
Chris@0 227
Chris@0 228 var entitySaverAjax = Drupal.ajax({
Chris@0 229 url: Drupal.url('quickedit/entity/' + entityModel.get('entityID')),
Chris@0 230 error: function error() {
Chris@0 231 options.error.call(entityModel);
Chris@0 232 }
Chris@0 233 });
Chris@0 234
Chris@0 235 entitySaverAjax.commands.quickeditEntitySaved = function (ajax, response, status) {
Chris@0 236 entityModel.get('fields').each(function (fieldModel) {
Chris@0 237 fieldModel.set('inTempStore', false);
Chris@0 238 });
Chris@0 239 entityModel.set('inTempStore', false);
Chris@0 240 entityModel.set('fieldsInTempStore', []);
Chris@0 241
Chris@0 242 if (options.success) {
Chris@0 243 options.success.call(entityModel);
Chris@0 244 }
Chris@0 245 };
Chris@0 246
Chris@0 247 entitySaverAjax.execute();
Chris@0 248 },
Chris@0 249 validate: function validate(attrs, options) {
Chris@0 250 var acceptedFieldStates = options['accept-field-states'] || [];
Chris@0 251
Chris@0 252 var currentState = this.get('state');
Chris@0 253 var nextState = attrs.state;
Chris@0 254 if (currentState !== nextState) {
Chris@0 255 if (_.indexOf(this.constructor.states, nextState) === -1) {
Chris@0 256 return '"' + nextState + '" is an invalid state';
Chris@0 257 }
Chris@0 258
Chris@0 259 if (!this._acceptStateChange(currentState, nextState, options)) {
Chris@0 260 return 'state change not accepted';
Chris@17 261 }
Chris@17 262
Chris@17 263 if (!this._fieldsHaveAcceptableStates(acceptedFieldStates)) {
Chris@17 264 return 'state change not accepted because fields are not in acceptable state';
Chris@17 265 }
Chris@0 266 }
Chris@0 267
Chris@0 268 var currentIsCommitting = this.get('isCommitting');
Chris@0 269 var nextIsCommitting = attrs.isCommitting;
Chris@0 270 if (currentIsCommitting === false && nextIsCommitting === true) {
Chris@0 271 if (!this._fieldsHaveAcceptableStates(acceptedFieldStates)) {
Chris@0 272 return 'isCommitting change not accepted because fields are not in acceptable state';
Chris@0 273 }
Chris@0 274 } else if (currentIsCommitting === true && nextIsCommitting === true) {
Chris@0 275 return 'isCommitting is a mutex, hence only changes are allowed';
Chris@0 276 }
Chris@0 277 },
Chris@0 278 _acceptStateChange: function _acceptStateChange(from, to, context) {
Chris@0 279 var accept = true;
Chris@0 280
Chris@0 281 if (!this.constructor.followsStateSequence(from, to)) {
Chris@0 282 accept = false;
Chris@0 283
Chris@0 284 if (from === 'closing' && to === 'closed') {
Chris@0 285 accept = true;
Chris@0 286 } else if (from === 'committing' && to === 'opened' && context.reason && (context.reason === 'invalid' || context.reason === 'networkerror')) {
Chris@0 287 accept = true;
Chris@0 288 } else if (from === 'deactivating' && to === 'opened' && context.confirming) {
Chris@0 289 accept = true;
Chris@0 290 } else if (from === 'opened' && to === 'deactivating' && context.confirmed) {
Chris@0 291 accept = true;
Chris@0 292 }
Chris@0 293 }
Chris@0 294
Chris@0 295 return accept;
Chris@0 296 },
Chris@0 297 _fieldsHaveAcceptableStates: function _fieldsHaveAcceptableStates(acceptedFieldStates) {
Chris@0 298 var accept = true;
Chris@0 299
Chris@0 300 if (acceptedFieldStates.length > 0) {
Chris@0 301 var fieldStates = this.get('fields').pluck('state') || [];
Chris@0 302
Chris@0 303 if (_.difference(fieldStates, acceptedFieldStates).length) {
Chris@0 304 accept = false;
Chris@0 305 }
Chris@0 306 }
Chris@0 307
Chris@0 308 return accept;
Chris@0 309 },
Chris@0 310 destroy: function destroy(options) {
Chris@0 311 Drupal.quickedit.BaseModel.prototype.destroy.call(this, options);
Chris@0 312
Chris@0 313 this.stopListening();
Chris@0 314
Chris@0 315 this.get('fields').reset();
Chris@0 316 },
Chris@0 317 sync: function sync() {}
Chris@0 318 }, {
Chris@0 319 states: ['closed', 'launching', 'opening', 'opened', 'committing', 'deactivating', 'closing'],
Chris@0 320
Chris@0 321 followsStateSequence: function followsStateSequence(from, to) {
Chris@0 322 return _.indexOf(this.states, from) < _.indexOf(this.states, to);
Chris@0 323 }
Chris@0 324 });
Chris@0 325
Chris@0 326 Drupal.quickedit.EntityCollection = Backbone.Collection.extend({
Chris@0 327 model: Drupal.quickedit.EntityModel
Chris@0 328 });
Chris@0 329 })(_, jQuery, Backbone, Drupal);