Updated to Drupal 8.5. Core Media not yet in use.
[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', { reason: 'networkerror' });
197
198                   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') });
199                   Drupal.quickedit.util.networkErrorModal(Drupal.t('Network problem!'), message);
200                 }
201               });
202             }
203             break;
204           }
205
206         case 'deactivating':
207           _.defer(function () {
208             entityModel.set('state', 'closing', {
209               'accept-field-states': Drupal.quickedit.app.readyFieldStates
210             });
211           });
212           break;
213
214         case 'closing':
215           _.defer(function () {
216             entityModel.set('state', 'closed', {
217               'accept-field-states': ['inactive']
218             });
219           });
220           break;
221       }
222     },
223     save: function save(options) {
224       var entityModel = this;
225
226       var entitySaverAjax = Drupal.ajax({
227         url: Drupal.url('quickedit/entity/' + entityModel.get('entityID')),
228         error: function error() {
229           options.error.call(entityModel);
230         }
231       });
232
233       entitySaverAjax.commands.quickeditEntitySaved = function (ajax, response, status) {
234         entityModel.get('fields').each(function (fieldModel) {
235           fieldModel.set('inTempStore', false);
236         });
237         entityModel.set('inTempStore', false);
238         entityModel.set('fieldsInTempStore', []);
239
240         if (options.success) {
241           options.success.call(entityModel);
242         }
243       };
244
245       entitySaverAjax.execute();
246     },
247     validate: function validate(attrs, options) {
248       var acceptedFieldStates = options['accept-field-states'] || [];
249
250       var currentState = this.get('state');
251       var nextState = attrs.state;
252       if (currentState !== nextState) {
253         if (_.indexOf(this.constructor.states, nextState) === -1) {
254           return '"' + nextState + '" is an invalid state';
255         }
256
257         if (!this._acceptStateChange(currentState, nextState, options)) {
258           return 'state change not accepted';
259         } else if (!this._fieldsHaveAcceptableStates(acceptedFieldStates)) {
260             return 'state change not accepted because fields are not in acceptable state';
261           }
262       }
263
264       var currentIsCommitting = this.get('isCommitting');
265       var nextIsCommitting = attrs.isCommitting;
266       if (currentIsCommitting === false && nextIsCommitting === true) {
267         if (!this._fieldsHaveAcceptableStates(acceptedFieldStates)) {
268           return 'isCommitting change not accepted because fields are not in acceptable state';
269         }
270       } else if (currentIsCommitting === true && nextIsCommitting === true) {
271         return 'isCommitting is a mutex, hence only changes are allowed';
272       }
273     },
274     _acceptStateChange: function _acceptStateChange(from, to, context) {
275       var accept = true;
276
277       if (!this.constructor.followsStateSequence(from, to)) {
278         accept = false;
279
280         if (from === 'closing' && to === 'closed') {
281           accept = true;
282         } else if (from === 'committing' && to === 'opened' && context.reason && (context.reason === 'invalid' || context.reason === 'networkerror')) {
283             accept = true;
284           } else if (from === 'deactivating' && to === 'opened' && context.confirming) {
285               accept = true;
286             } else if (from === 'opened' && to === 'deactivating' && context.confirmed) {
287                 accept = true;
288               }
289       }
290
291       return accept;
292     },
293     _fieldsHaveAcceptableStates: function _fieldsHaveAcceptableStates(acceptedFieldStates) {
294       var accept = true;
295
296       if (acceptedFieldStates.length > 0) {
297         var fieldStates = this.get('fields').pluck('state') || [];
298
299         if (_.difference(fieldStates, acceptedFieldStates).length) {
300           accept = false;
301         }
302       }
303
304       return accept;
305     },
306     destroy: function destroy(options) {
307       Drupal.quickedit.BaseModel.prototype.destroy.call(this, options);
308
309       this.stopListening();
310
311       this.get('fields').reset();
312     },
313     sync: function sync() {}
314   }, {
315     states: ['closed', 'launching', 'opening', 'opened', 'committing', 'deactivating', 'closing'],
316
317     followsStateSequence: function followsStateSequence(from, to) {
318       return _.indexOf(this.states, from) < _.indexOf(this.states, to);
319     }
320   });
321
322   Drupal.quickedit.EntityCollection = Backbone.Collection.extend({
323     model: Drupal.quickedit.EntityModel
324   });
325 })(_, jQuery, Backbone, Drupal);