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