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); |