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