Mercurial > hg > isophonics-drupal-site
comparison core/modules/quickedit/js/quickedit.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, drupalSettings, JSON, storage) { | |
9 var options = $.extend(drupalSettings.quickedit, { | |
10 strings: { | |
11 quickEdit: Drupal.t('Quick edit') | |
12 } | |
13 }); | |
14 | |
15 var fieldsMetadataQueue = []; | |
16 | |
17 var fieldsAvailableQueue = []; | |
18 | |
19 var contextualLinksQueue = []; | |
20 | |
21 var entityInstancesTracker = {}; | |
22 | |
23 Drupal.behaviors.quickedit = { | |
24 attach: function attach(context) { | |
25 $('body').once('quickedit-init').each(initQuickEdit); | |
26 | |
27 var $fields = $(context).find('[data-quickedit-field-id]').once('quickedit'); | |
28 if ($fields.length === 0) { | |
29 return; | |
30 } | |
31 | |
32 $(context).find('[data-quickedit-entity-id]').once('quickedit').each(function (index, entityElement) { | |
33 processEntity(entityElement); | |
34 }); | |
35 | |
36 $fields.each(function (index, fieldElement) { | |
37 processField(fieldElement); | |
38 }); | |
39 | |
40 contextualLinksQueue = _.filter(contextualLinksQueue, function (contextualLink) { | |
41 return !initializeEntityContextualLink(contextualLink); | |
42 }); | |
43 | |
44 fetchMissingMetadata(function (fieldElementsWithFreshMetadata) { | |
45 _.each(fieldElementsWithFreshMetadata, processField); | |
46 | |
47 contextualLinksQueue = _.filter(contextualLinksQueue, function (contextualLink) { | |
48 return !initializeEntityContextualLink(contextualLink); | |
49 }); | |
50 }); | |
51 }, | |
52 detach: function detach(context, settings, trigger) { | |
53 if (trigger === 'unload') { | |
54 deleteContainedModelsAndQueues($(context)); | |
55 } | |
56 } | |
57 }; | |
58 | |
59 Drupal.quickedit = { | |
60 app: null, | |
61 | |
62 collections: { | |
63 entities: null, | |
64 | |
65 fields: null | |
66 }, | |
67 | |
68 editors: {}, | |
69 | |
70 metadata: { | |
71 has: function has(fieldID) { | |
72 return storage.getItem(this._prefixFieldID(fieldID)) !== null; | |
73 }, | |
74 add: function add(fieldID, metadata) { | |
75 storage.setItem(this._prefixFieldID(fieldID), JSON.stringify(metadata)); | |
76 }, | |
77 get: function get(fieldID, key) { | |
78 var metadata = JSON.parse(storage.getItem(this._prefixFieldID(fieldID))); | |
79 return typeof key === 'undefined' ? metadata : metadata[key]; | |
80 }, | |
81 _prefixFieldID: function _prefixFieldID(fieldID) { | |
82 return 'Drupal.quickedit.metadata.' + fieldID; | |
83 }, | |
84 _unprefixFieldID: function _unprefixFieldID(fieldID) { | |
85 return fieldID.substring(26); | |
86 }, | |
87 intersection: function intersection(fieldIDs) { | |
88 var prefixedFieldIDs = _.map(fieldIDs, this._prefixFieldID); | |
89 var intersection = _.intersection(prefixedFieldIDs, _.keys(sessionStorage)); | |
90 return _.map(intersection, this._unprefixFieldID); | |
91 } | |
92 } | |
93 }; | |
94 | |
95 var permissionsHashKey = Drupal.quickedit.metadata._prefixFieldID('permissionsHash'); | |
96 var permissionsHashValue = storage.getItem(permissionsHashKey); | |
97 var permissionsHash = drupalSettings.user.permissionsHash; | |
98 if (permissionsHashValue !== permissionsHash) { | |
99 if (typeof permissionsHash === 'string') { | |
100 _.chain(storage).keys().each(function (key) { | |
101 if (key.substring(0, 26) === 'Drupal.quickedit.metadata.') { | |
102 storage.removeItem(key); | |
103 } | |
104 }); | |
105 } | |
106 storage.setItem(permissionsHashKey, permissionsHash); | |
107 } | |
108 | |
109 $(document).on('drupalContextualLinkAdded', function (event, data) { | |
110 if (data.$region.is('[data-quickedit-entity-id]')) { | |
111 if (!data.$region.is('[data-quickedit-entity-instance-id]')) { | |
112 data.$region.once('quickedit'); | |
113 processEntity(data.$region.get(0)); | |
114 } | |
115 var contextualLink = { | |
116 entityID: data.$region.attr('data-quickedit-entity-id'), | |
117 entityInstanceID: data.$region.attr('data-quickedit-entity-instance-id'), | |
118 el: data.$el[0], | |
119 region: data.$region[0] | |
120 }; | |
121 | |
122 if (!initializeEntityContextualLink(contextualLink)) { | |
123 contextualLinksQueue.push(contextualLink); | |
124 } | |
125 } | |
126 }); | |
127 | |
128 function extractEntityID(fieldID) { | |
129 return fieldID.split('/').slice(0, 2).join('/'); | |
130 } | |
131 | |
132 function initQuickEdit(bodyElement) { | |
133 Drupal.quickedit.collections.entities = new Drupal.quickedit.EntityCollection(); | |
134 Drupal.quickedit.collections.fields = new Drupal.quickedit.FieldCollection(); | |
135 | |
136 Drupal.quickedit.app = new Drupal.quickedit.AppView({ | |
137 el: bodyElement, | |
138 model: new Drupal.quickedit.AppModel(), | |
139 entitiesCollection: Drupal.quickedit.collections.entities, | |
140 fieldsCollection: Drupal.quickedit.collections.fields | |
141 }); | |
142 } | |
143 | |
144 function processEntity(entityElement) { | |
145 var entityID = entityElement.getAttribute('data-quickedit-entity-id'); | |
146 if (!entityInstancesTracker.hasOwnProperty(entityID)) { | |
147 entityInstancesTracker[entityID] = 0; | |
148 } else { | |
149 entityInstancesTracker[entityID]++; | |
150 } | |
151 | |
152 var entityInstanceID = entityInstancesTracker[entityID]; | |
153 entityElement.setAttribute('data-quickedit-entity-instance-id', entityInstanceID); | |
154 } | |
155 | |
156 function processField(fieldElement) { | |
157 var metadata = Drupal.quickedit.metadata; | |
158 var fieldID = fieldElement.getAttribute('data-quickedit-field-id'); | |
159 var entityID = extractEntityID(fieldID); | |
160 | |
161 var entityElementSelector = '[data-quickedit-entity-id="' + entityID + '"]'; | |
162 var $entityElement = $(entityElementSelector); | |
163 | |
164 if (!$entityElement.length) { | |
165 throw 'Quick Edit could not associate the rendered entity field markup (with [data-quickedit-field-id="' + fieldID + '"]) with the corresponding rendered entity markup: no parent DOM node found with [data-quickedit-entity-id="' + entityID + '"]. This is typically caused by the theme\'s template for this entity type forgetting to print the attributes.'; | |
166 } | |
167 var entityElement = $(fieldElement).closest($entityElement); | |
168 | |
169 if (entityElement.length === 0) { | |
170 var $lowestCommonParent = $entityElement.parents().has(fieldElement).first(); | |
171 entityElement = $lowestCommonParent.find($entityElement); | |
172 } | |
173 var entityInstanceID = entityElement.get(0).getAttribute('data-quickedit-entity-instance-id'); | |
174 | |
175 if (!metadata.has(fieldID)) { | |
176 fieldsMetadataQueue.push({ | |
177 el: fieldElement, | |
178 fieldID: fieldID, | |
179 entityID: entityID, | |
180 entityInstanceID: entityInstanceID | |
181 }); | |
182 return; | |
183 } | |
184 | |
185 if (metadata.get(fieldID, 'access') !== true) { | |
186 return; | |
187 } | |
188 | |
189 if (Drupal.quickedit.collections.entities.findWhere({ entityID: entityID, entityInstanceID: entityInstanceID })) { | |
190 initializeField(fieldElement, fieldID, entityID, entityInstanceID); | |
191 } else { | |
192 fieldsAvailableQueue.push({ el: fieldElement, fieldID: fieldID, entityID: entityID, entityInstanceID: entityInstanceID }); | |
193 } | |
194 } | |
195 | |
196 function initializeField(fieldElement, fieldID, entityID, entityInstanceID) { | |
197 var entity = Drupal.quickedit.collections.entities.findWhere({ | |
198 entityID: entityID, | |
199 entityInstanceID: entityInstanceID | |
200 }); | |
201 | |
202 $(fieldElement).addClass('quickedit-field'); | |
203 | |
204 var field = new Drupal.quickedit.FieldModel({ | |
205 el: fieldElement, | |
206 fieldID: fieldID, | |
207 id: fieldID + '[' + entity.get('entityInstanceID') + ']', | |
208 entity: entity, | |
209 metadata: Drupal.quickedit.metadata.get(fieldID), | |
210 acceptStateChange: _.bind(Drupal.quickedit.app.acceptEditorStateChange, Drupal.quickedit.app) | |
211 }); | |
212 | |
213 Drupal.quickedit.collections.fields.add(field); | |
214 } | |
215 | |
216 function fetchMissingMetadata(callback) { | |
217 if (fieldsMetadataQueue.length) { | |
218 var fieldIDs = _.pluck(fieldsMetadataQueue, 'fieldID'); | |
219 var fieldElementsWithoutMetadata = _.pluck(fieldsMetadataQueue, 'el'); | |
220 var entityIDs = _.uniq(_.pluck(fieldsMetadataQueue, 'entityID'), true); | |
221 | |
222 entityIDs = _.difference(entityIDs, Drupal.quickedit.metadata.intersection(entityIDs)); | |
223 fieldsMetadataQueue = []; | |
224 | |
225 $.ajax({ | |
226 url: Drupal.url('quickedit/metadata'), | |
227 type: 'POST', | |
228 data: { | |
229 'fields[]': fieldIDs, | |
230 'entities[]': entityIDs | |
231 }, | |
232 dataType: 'json', | |
233 success: function success(results) { | |
234 _.each(results, function (fieldMetadata, fieldID) { | |
235 Drupal.quickedit.metadata.add(fieldID, fieldMetadata); | |
236 }); | |
237 | |
238 callback(fieldElementsWithoutMetadata); | |
239 } | |
240 }); | |
241 } | |
242 } | |
243 | |
244 function loadMissingEditors(callback) { | |
245 var loadedEditors = _.keys(Drupal.quickedit.editors); | |
246 var missingEditors = []; | |
247 Drupal.quickedit.collections.fields.each(function (fieldModel) { | |
248 var metadata = Drupal.quickedit.metadata.get(fieldModel.get('fieldID')); | |
249 if (metadata.access && _.indexOf(loadedEditors, metadata.editor) === -1) { | |
250 missingEditors.push(metadata.editor); | |
251 | |
252 Drupal.quickedit.editors[metadata.editor] = false; | |
253 } | |
254 }); | |
255 missingEditors = _.uniq(missingEditors); | |
256 if (missingEditors.length === 0) { | |
257 callback(); | |
258 return; | |
259 } | |
260 | |
261 var loadEditorsAjax = Drupal.ajax({ | |
262 url: Drupal.url('quickedit/attachments'), | |
263 submit: { 'editors[]': missingEditors } | |
264 }); | |
265 | |
266 var realInsert = Drupal.AjaxCommands.prototype.insert; | |
267 loadEditorsAjax.commands.insert = function (ajax, response, status) { | |
268 _.defer(callback); | |
269 realInsert(ajax, response, status); | |
270 }; | |
271 | |
272 loadEditorsAjax.execute(); | |
273 } | |
274 | |
275 function initializeEntityContextualLink(contextualLink) { | |
276 var metadata = Drupal.quickedit.metadata; | |
277 | |
278 function hasFieldWithPermission(fieldIDs) { | |
279 for (var i = 0; i < fieldIDs.length; i++) { | |
280 var fieldID = fieldIDs[i]; | |
281 if (metadata.get(fieldID, 'access') === true) { | |
282 return true; | |
283 } | |
284 } | |
285 return false; | |
286 } | |
287 | |
288 function allMetadataExists(fieldIDs) { | |
289 return fieldIDs.length === metadata.intersection(fieldIDs).length; | |
290 } | |
291 | |
292 var fields = _.where(fieldsAvailableQueue, { | |
293 entityID: contextualLink.entityID, | |
294 entityInstanceID: contextualLink.entityInstanceID | |
295 }); | |
296 var fieldIDs = _.pluck(fields, 'fieldID'); | |
297 | |
298 if (fieldIDs.length === 0) { | |
299 return false; | |
300 } else if (hasFieldWithPermission(fieldIDs)) { | |
301 var entityModel = new Drupal.quickedit.EntityModel({ | |
302 el: contextualLink.region, | |
303 entityID: contextualLink.entityID, | |
304 entityInstanceID: contextualLink.entityInstanceID, | |
305 id: contextualLink.entityID + '[' + contextualLink.entityInstanceID + ']', | |
306 label: Drupal.quickedit.metadata.get(contextualLink.entityID, 'label') | |
307 }); | |
308 Drupal.quickedit.collections.entities.add(entityModel); | |
309 | |
310 var entityDecorationView = new Drupal.quickedit.EntityDecorationView({ | |
311 el: contextualLink.region, | |
312 model: entityModel | |
313 }); | |
314 entityModel.set('entityDecorationView', entityDecorationView); | |
315 | |
316 _.each(fields, function (field) { | |
317 initializeField(field.el, field.fieldID, contextualLink.entityID, contextualLink.entityInstanceID); | |
318 }); | |
319 fieldsAvailableQueue = _.difference(fieldsAvailableQueue, fields); | |
320 | |
321 var initContextualLink = _.once(function () { | |
322 var $links = $(contextualLink.el).find('.contextual-links'); | |
323 var contextualLinkView = new Drupal.quickedit.ContextualLinkView($.extend({ | |
324 el: $('<li class="quickedit"><a href="" role="button" aria-pressed="false"></a></li>').prependTo($links), | |
325 model: entityModel, | |
326 appModel: Drupal.quickedit.app.model | |
327 }, options)); | |
328 entityModel.set('contextualLinkView', contextualLinkView); | |
329 }); | |
330 | |
331 loadMissingEditors(initContextualLink); | |
332 | |
333 return true; | |
334 } else if (allMetadataExists(fieldIDs)) { | |
335 return true; | |
336 } | |
337 | |
338 return false; | |
339 } | |
340 | |
341 function deleteContainedModelsAndQueues($context) { | |
342 $context.find('[data-quickedit-entity-id]').addBack('[data-quickedit-entity-id]').each(function (index, entityElement) { | |
343 var entityModel = Drupal.quickedit.collections.entities.findWhere({ el: entityElement }); | |
344 if (entityModel) { | |
345 var contextualLinkView = entityModel.get('contextualLinkView'); | |
346 contextualLinkView.undelegateEvents(); | |
347 contextualLinkView.remove(); | |
348 | |
349 entityModel.get('entityDecorationView').remove(); | |
350 | |
351 entityModel.destroy(); | |
352 } | |
353 | |
354 function hasOtherRegion(contextualLink) { | |
355 return contextualLink.region !== entityElement; | |
356 } | |
357 | |
358 contextualLinksQueue = _.filter(contextualLinksQueue, hasOtherRegion); | |
359 }); | |
360 | |
361 $context.find('[data-quickedit-field-id]').addBack('[data-quickedit-field-id]').each(function (index, fieldElement) { | |
362 Drupal.quickedit.collections.fields.chain().filter(function (fieldModel) { | |
363 return fieldModel.get('el') === fieldElement; | |
364 }).invoke('destroy'); | |
365 | |
366 function hasOtherFieldElement(field) { | |
367 return field.el !== fieldElement; | |
368 } | |
369 | |
370 fieldsMetadataQueue = _.filter(fieldsMetadataQueue, hasOtherFieldElement); | |
371 fieldsAvailableQueue = _.filter(fieldsAvailableQueue, hasOtherFieldElement); | |
372 }); | |
373 } | |
374 })(jQuery, _, Backbone, Drupal, drupalSettings, window.JSON, window.sessionStorage); |