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@0
|
72 var fields = this.get('fields');
|
Chris@0
|
73
|
Chris@0
|
74 fields.chain().filter(function (fieldModel) {
|
Chris@0
|
75 return _.intersection([fieldModel.get('state')], ['active']).length;
|
Chris@0
|
76 }).each(function (fieldModel) {
|
Chris@0
|
77 fieldModel.set('state', 'candidate');
|
Chris@0
|
78 });
|
Chris@0
|
79
|
Chris@0
|
80 fields.chain().filter(function (fieldModel) {
|
Chris@0
|
81 return _.intersection([fieldModel.get('state')], Drupal.quickedit.app.changedFieldStates).length;
|
Chris@0
|
82 }).each(function (fieldModel) {
|
Chris@0
|
83 fieldModel.set('state', 'saving');
|
Chris@0
|
84 });
|
Chris@0
|
85 break;
|
Chris@0
|
86
|
Chris@0
|
87 case 'deactivating':
|
Chris@0
|
88 var changedFields = this.get('fields').filter(function (fieldModel) {
|
Chris@0
|
89 return _.intersection([fieldModel.get('state')], ['changed', 'invalid']).length;
|
Chris@0
|
90 });
|
Chris@0
|
91
|
Chris@0
|
92 if ((changedFields.length || this.get('fieldsInTempStore').length) && !options.saved && !options.confirmed) {
|
Chris@0
|
93 this.set('state', 'opened', { confirming: true });
|
Chris@0
|
94
|
Chris@0
|
95 _.defer(function () {
|
Chris@0
|
96 Drupal.quickedit.app.confirmEntityDeactivation(entityModel);
|
Chris@0
|
97 });
|
Chris@0
|
98 } else {
|
Chris@0
|
99 var invalidFields = this.get('fields').filter(function (fieldModel) {
|
Chris@0
|
100 return _.intersection([fieldModel.get('state')], ['invalid']).length;
|
Chris@0
|
101 });
|
Chris@0
|
102
|
Chris@0
|
103 entityModel.set('reload', this.get('fieldsInTempStore').length || invalidFields.length);
|
Chris@0
|
104
|
Chris@0
|
105 entityModel.get('fields').each(function (fieldModel) {
|
Chris@0
|
106 if (_.intersection([fieldModel.get('state')], ['candidate', 'highlighted']).length) {
|
Chris@0
|
107 fieldModel.trigger('change:state', fieldModel, fieldModel.get('state'), options);
|
Chris@0
|
108 } else {
|
Chris@0
|
109 fieldModel.set('state', 'candidate', options);
|
Chris@0
|
110 }
|
Chris@0
|
111 });
|
Chris@0
|
112 }
|
Chris@0
|
113 break;
|
Chris@0
|
114
|
Chris@0
|
115 case 'closing':
|
Chris@0
|
116 options.reason = 'stop';
|
Chris@0
|
117 this.get('fields').each(function (fieldModel) {
|
Chris@0
|
118 fieldModel.set({
|
Chris@0
|
119 inTempStore: false,
|
Chris@0
|
120 state: 'inactive'
|
Chris@0
|
121 }, options);
|
Chris@0
|
122 });
|
Chris@0
|
123 break;
|
Chris@0
|
124 }
|
Chris@0
|
125 },
|
Chris@0
|
126 _updateInTempStoreAttributes: function _updateInTempStoreAttributes(entityModel, fieldModel) {
|
Chris@0
|
127 var current = fieldModel.get('state');
|
Chris@0
|
128 var previous = fieldModel.previous('state');
|
Chris@0
|
129 var fieldsInTempStore = entityModel.get('fieldsInTempStore');
|
Chris@0
|
130
|
Chris@0
|
131 if (current === 'saved') {
|
Chris@0
|
132 entityModel.set('inTempStore', true);
|
Chris@0
|
133
|
Chris@0
|
134 fieldModel.set('inTempStore', true);
|
Chris@0
|
135
|
Chris@0
|
136 fieldsInTempStore.push(fieldModel.get('fieldID'));
|
Chris@0
|
137 fieldsInTempStore = _.uniq(fieldsInTempStore);
|
Chris@0
|
138 entityModel.set('fieldsInTempStore', fieldsInTempStore);
|
Chris@0
|
139 } else if (current === 'candidate' && previous === 'inactive') {
|
Chris@0
|
140 fieldModel.set('inTempStore', _.intersection([fieldModel.get('fieldID')], fieldsInTempStore).length > 0);
|
Chris@0
|
141 }
|
Chris@0
|
142 },
|
Chris@0
|
143 fieldStateChange: function fieldStateChange(fieldModel, state) {
|
Chris@0
|
144 var entityModel = this;
|
Chris@0
|
145 var fieldState = state;
|
Chris@0
|
146
|
Chris@0
|
147 switch (this.get('state')) {
|
Chris@0
|
148 case 'closed':
|
Chris@0
|
149 case 'launching':
|
Chris@0
|
150 break;
|
Chris@0
|
151
|
Chris@0
|
152 case 'opening':
|
Chris@0
|
153 _.defer(function () {
|
Chris@0
|
154 entityModel.set('state', 'opened', {
|
Chris@0
|
155 'accept-field-states': Drupal.quickedit.app.readyFieldStates
|
Chris@0
|
156 });
|
Chris@0
|
157 });
|
Chris@0
|
158 break;
|
Chris@0
|
159
|
Chris@0
|
160 case 'opened':
|
Chris@0
|
161 if (fieldState === 'changed') {
|
Chris@0
|
162 entityModel.set('isDirty', true);
|
Chris@0
|
163 } else {
|
Chris@0
|
164 this._updateInTempStoreAttributes(entityModel, fieldModel);
|
Chris@0
|
165 }
|
Chris@0
|
166 break;
|
Chris@0
|
167
|
Chris@0
|
168 case 'committing':
|
Chris@0
|
169 if (fieldState === 'invalid') {
|
Chris@0
|
170 _.defer(function () {
|
Chris@0
|
171 entityModel.set('state', 'opened', { reason: 'invalid' });
|
Chris@0
|
172 });
|
Chris@0
|
173 } else {
|
Chris@0
|
174 this._updateInTempStoreAttributes(entityModel, fieldModel);
|
Chris@0
|
175 }
|
Chris@0
|
176
|
Chris@0
|
177 var options = {
|
Chris@0
|
178 'accept-field-states': Drupal.quickedit.app.readyFieldStates
|
Chris@0
|
179 };
|
Chris@0
|
180 if (entityModel.set('isCommitting', true, options)) {
|
Chris@0
|
181 entityModel.save({
|
Chris@0
|
182 success: function success() {
|
Chris@0
|
183 entityModel.set({
|
Chris@0
|
184 state: 'deactivating',
|
Chris@0
|
185 isCommitting: false
|
Chris@0
|
186 }, { saved: true });
|
Chris@0
|
187 },
|
Chris@0
|
188 error: function error() {
|
Chris@0
|
189 entityModel.set('isCommitting', false);
|
Chris@0
|
190
|
Chris@0
|
191 entityModel.set('state', 'opened', { reason: 'networkerror' });
|
Chris@0
|
192
|
Chris@0
|
193 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@0
|
194 Drupal.quickedit.util.networkErrorModal(Drupal.t('Network problem!'), message);
|
Chris@0
|
195 }
|
Chris@0
|
196 });
|
Chris@0
|
197 }
|
Chris@0
|
198 break;
|
Chris@0
|
199
|
Chris@0
|
200 case 'deactivating':
|
Chris@0
|
201 _.defer(function () {
|
Chris@0
|
202 entityModel.set('state', 'closing', {
|
Chris@0
|
203 'accept-field-states': Drupal.quickedit.app.readyFieldStates
|
Chris@0
|
204 });
|
Chris@0
|
205 });
|
Chris@0
|
206 break;
|
Chris@0
|
207
|
Chris@0
|
208 case 'closing':
|
Chris@0
|
209 _.defer(function () {
|
Chris@0
|
210 entityModel.set('state', 'closed', {
|
Chris@0
|
211 'accept-field-states': ['inactive']
|
Chris@0
|
212 });
|
Chris@0
|
213 });
|
Chris@0
|
214 break;
|
Chris@0
|
215 }
|
Chris@0
|
216 },
|
Chris@0
|
217 save: function save(options) {
|
Chris@0
|
218 var entityModel = this;
|
Chris@0
|
219
|
Chris@0
|
220 var entitySaverAjax = Drupal.ajax({
|
Chris@0
|
221 url: Drupal.url('quickedit/entity/' + entityModel.get('entityID')),
|
Chris@0
|
222 error: function error() {
|
Chris@0
|
223 options.error.call(entityModel);
|
Chris@0
|
224 }
|
Chris@0
|
225 });
|
Chris@0
|
226
|
Chris@0
|
227 entitySaverAjax.commands.quickeditEntitySaved = function (ajax, response, status) {
|
Chris@0
|
228 entityModel.get('fields').each(function (fieldModel) {
|
Chris@0
|
229 fieldModel.set('inTempStore', false);
|
Chris@0
|
230 });
|
Chris@0
|
231 entityModel.set('inTempStore', false);
|
Chris@0
|
232 entityModel.set('fieldsInTempStore', []);
|
Chris@0
|
233
|
Chris@0
|
234 if (options.success) {
|
Chris@0
|
235 options.success.call(entityModel);
|
Chris@0
|
236 }
|
Chris@0
|
237 };
|
Chris@0
|
238
|
Chris@0
|
239 entitySaverAjax.execute();
|
Chris@0
|
240 },
|
Chris@0
|
241 validate: function validate(attrs, options) {
|
Chris@0
|
242 var acceptedFieldStates = options['accept-field-states'] || [];
|
Chris@0
|
243
|
Chris@0
|
244 var currentState = this.get('state');
|
Chris@0
|
245 var nextState = attrs.state;
|
Chris@0
|
246 if (currentState !== nextState) {
|
Chris@0
|
247 if (_.indexOf(this.constructor.states, nextState) === -1) {
|
Chris@0
|
248 return '"' + nextState + '" is an invalid state';
|
Chris@0
|
249 }
|
Chris@0
|
250
|
Chris@0
|
251 if (!this._acceptStateChange(currentState, nextState, options)) {
|
Chris@0
|
252 return 'state change not accepted';
|
Chris@0
|
253 } else if (!this._fieldsHaveAcceptableStates(acceptedFieldStates)) {
|
Chris@0
|
254 return 'state change not accepted because fields are not in acceptable state';
|
Chris@0
|
255 }
|
Chris@0
|
256 }
|
Chris@0
|
257
|
Chris@0
|
258 var currentIsCommitting = this.get('isCommitting');
|
Chris@0
|
259 var nextIsCommitting = attrs.isCommitting;
|
Chris@0
|
260 if (currentIsCommitting === false && nextIsCommitting === true) {
|
Chris@0
|
261 if (!this._fieldsHaveAcceptableStates(acceptedFieldStates)) {
|
Chris@0
|
262 return 'isCommitting change not accepted because fields are not in acceptable state';
|
Chris@0
|
263 }
|
Chris@0
|
264 } else if (currentIsCommitting === true && nextIsCommitting === true) {
|
Chris@0
|
265 return 'isCommitting is a mutex, hence only changes are allowed';
|
Chris@0
|
266 }
|
Chris@0
|
267 },
|
Chris@0
|
268 _acceptStateChange: function _acceptStateChange(from, to, context) {
|
Chris@0
|
269 var accept = true;
|
Chris@0
|
270
|
Chris@0
|
271 if (!this.constructor.followsStateSequence(from, to)) {
|
Chris@0
|
272 accept = false;
|
Chris@0
|
273
|
Chris@0
|
274 if (from === 'closing' && to === 'closed') {
|
Chris@0
|
275 accept = true;
|
Chris@0
|
276 } else if (from === 'committing' && to === 'opened' && context.reason && (context.reason === 'invalid' || context.reason === 'networkerror')) {
|
Chris@0
|
277 accept = true;
|
Chris@0
|
278 } else if (from === 'deactivating' && to === 'opened' && context.confirming) {
|
Chris@0
|
279 accept = true;
|
Chris@0
|
280 } else if (from === 'opened' && to === 'deactivating' && context.confirmed) {
|
Chris@0
|
281 accept = true;
|
Chris@0
|
282 }
|
Chris@0
|
283 }
|
Chris@0
|
284
|
Chris@0
|
285 return accept;
|
Chris@0
|
286 },
|
Chris@0
|
287 _fieldsHaveAcceptableStates: function _fieldsHaveAcceptableStates(acceptedFieldStates) {
|
Chris@0
|
288 var accept = true;
|
Chris@0
|
289
|
Chris@0
|
290 if (acceptedFieldStates.length > 0) {
|
Chris@0
|
291 var fieldStates = this.get('fields').pluck('state') || [];
|
Chris@0
|
292
|
Chris@0
|
293 if (_.difference(fieldStates, acceptedFieldStates).length) {
|
Chris@0
|
294 accept = false;
|
Chris@0
|
295 }
|
Chris@0
|
296 }
|
Chris@0
|
297
|
Chris@0
|
298 return accept;
|
Chris@0
|
299 },
|
Chris@0
|
300 destroy: function destroy(options) {
|
Chris@0
|
301 Drupal.quickedit.BaseModel.prototype.destroy.call(this, options);
|
Chris@0
|
302
|
Chris@0
|
303 this.stopListening();
|
Chris@0
|
304
|
Chris@0
|
305 this.get('fields').reset();
|
Chris@0
|
306 },
|
Chris@0
|
307 sync: function sync() {}
|
Chris@0
|
308 }, {
|
Chris@0
|
309 states: ['closed', 'launching', 'opening', 'opened', 'committing', 'deactivating', 'closing'],
|
Chris@0
|
310
|
Chris@0
|
311 followsStateSequence: function followsStateSequence(from, to) {
|
Chris@0
|
312 return _.indexOf(this.states, from) < _.indexOf(this.states, to);
|
Chris@0
|
313 }
|
Chris@0
|
314 });
|
Chris@0
|
315
|
Chris@0
|
316 Drupal.quickedit.EntityCollection = Backbone.Collection.extend({
|
Chris@0
|
317 model: Drupal.quickedit.EntityModel
|
Chris@0
|
318 });
|
Chris@0
|
319 })(_, jQuery, Backbone, Drupal); |