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