Chris@0: /**
Chris@0: * DO NOT EDIT THIS FILE.
Chris@0: * See the following change record for more information,
Chris@0: * https://www.drupal.org/node/2815083
Chris@0: * @preserve
Chris@0: **/
Chris@0:
Chris@0: (function ($, _, Backbone, Drupal, drupalSettings, JSON, storage) {
Chris@0: var options = $.extend(drupalSettings.quickedit, {
Chris@0: strings: {
Chris@0: quickEdit: Drupal.t('Quick edit')
Chris@0: }
Chris@0: });
Chris@0:
Chris@0: var fieldsMetadataQueue = [];
Chris@0:
Chris@0: var fieldsAvailableQueue = [];
Chris@0:
Chris@0: var contextualLinksQueue = [];
Chris@0:
Chris@0: var entityInstancesTracker = {};
Chris@0:
Chris@17: function initQuickEdit(bodyElement) {
Chris@17: Drupal.quickedit.collections.entities = new Drupal.quickedit.EntityCollection();
Chris@17: Drupal.quickedit.collections.fields = new Drupal.quickedit.FieldCollection();
Chris@17:
Chris@17: Drupal.quickedit.app = new Drupal.quickedit.AppView({
Chris@17: el: bodyElement,
Chris@17: model: new Drupal.quickedit.AppModel(),
Chris@17: entitiesCollection: Drupal.quickedit.collections.entities,
Chris@17: fieldsCollection: Drupal.quickedit.collections.fields
Chris@17: });
Chris@17: }
Chris@17:
Chris@17: function processEntity(entityElement) {
Chris@17: var entityID = entityElement.getAttribute('data-quickedit-entity-id');
Chris@17: if (!entityInstancesTracker.hasOwnProperty(entityID)) {
Chris@17: entityInstancesTracker[entityID] = 0;
Chris@17: } else {
Chris@17: entityInstancesTracker[entityID]++;
Chris@17: }
Chris@17:
Chris@17: var entityInstanceID = entityInstancesTracker[entityID];
Chris@17: entityElement.setAttribute('data-quickedit-entity-instance-id', entityInstanceID);
Chris@17: }
Chris@17:
Chris@17: function initializeField(fieldElement, fieldID, entityID, entityInstanceID) {
Chris@17: var entity = Drupal.quickedit.collections.entities.findWhere({
Chris@17: entityID: entityID,
Chris@17: entityInstanceID: entityInstanceID
Chris@17: });
Chris@17:
Chris@17: $(fieldElement).addClass('quickedit-field');
Chris@17:
Chris@17: var field = new Drupal.quickedit.FieldModel({
Chris@17: el: fieldElement,
Chris@17: fieldID: fieldID,
Chris@17: id: fieldID + '[' + entity.get('entityInstanceID') + ']',
Chris@17: entity: entity,
Chris@17: metadata: Drupal.quickedit.metadata.get(fieldID),
Chris@17: acceptStateChange: _.bind(Drupal.quickedit.app.acceptEditorStateChange, Drupal.quickedit.app)
Chris@17: });
Chris@17:
Chris@17: Drupal.quickedit.collections.fields.add(field);
Chris@17: }
Chris@17:
Chris@17: function loadMissingEditors(callback) {
Chris@17: var loadedEditors = _.keys(Drupal.quickedit.editors);
Chris@17: var missingEditors = [];
Chris@17: Drupal.quickedit.collections.fields.each(function (fieldModel) {
Chris@17: var metadata = Drupal.quickedit.metadata.get(fieldModel.get('fieldID'));
Chris@17: if (metadata.access && _.indexOf(loadedEditors, metadata.editor) === -1) {
Chris@17: missingEditors.push(metadata.editor);
Chris@17:
Chris@17: Drupal.quickedit.editors[metadata.editor] = false;
Chris@17: }
Chris@17: });
Chris@17: missingEditors = _.uniq(missingEditors);
Chris@17: if (missingEditors.length === 0) {
Chris@17: callback();
Chris@17: return;
Chris@17: }
Chris@17:
Chris@17: var loadEditorsAjax = Drupal.ajax({
Chris@17: url: Drupal.url('quickedit/attachments'),
Chris@17: submit: { 'editors[]': missingEditors }
Chris@17: });
Chris@17:
Chris@17: var realInsert = Drupal.AjaxCommands.prototype.insert;
Chris@17: loadEditorsAjax.commands.insert = function (ajax, response, status) {
Chris@17: _.defer(callback);
Chris@17: realInsert(ajax, response, status);
Chris@17: };
Chris@17:
Chris@17: loadEditorsAjax.execute();
Chris@17: }
Chris@17:
Chris@17: function initializeEntityContextualLink(contextualLink) {
Chris@17: var metadata = Drupal.quickedit.metadata;
Chris@17:
Chris@17: function hasFieldWithPermission(fieldIDs) {
Chris@17: for (var i = 0; i < fieldIDs.length; i++) {
Chris@17: var fieldID = fieldIDs[i];
Chris@17: if (metadata.get(fieldID, 'access') === true) {
Chris@17: return true;
Chris@17: }
Chris@17: }
Chris@17: return false;
Chris@17: }
Chris@17:
Chris@17: function allMetadataExists(fieldIDs) {
Chris@17: return fieldIDs.length === metadata.intersection(fieldIDs).length;
Chris@17: }
Chris@17:
Chris@17: var fields = _.where(fieldsAvailableQueue, {
Chris@17: entityID: contextualLink.entityID,
Chris@17: entityInstanceID: contextualLink.entityInstanceID
Chris@17: });
Chris@17: var fieldIDs = _.pluck(fields, 'fieldID');
Chris@17:
Chris@17: if (fieldIDs.length === 0) {
Chris@17: return false;
Chris@17: }
Chris@17:
Chris@17: if (hasFieldWithPermission(fieldIDs)) {
Chris@17: var entityModel = new Drupal.quickedit.EntityModel({
Chris@17: el: contextualLink.region,
Chris@17: entityID: contextualLink.entityID,
Chris@17: entityInstanceID: contextualLink.entityInstanceID,
Chris@17: id: contextualLink.entityID + '[' + contextualLink.entityInstanceID + ']',
Chris@17: label: Drupal.quickedit.metadata.get(contextualLink.entityID, 'label')
Chris@17: });
Chris@17: Drupal.quickedit.collections.entities.add(entityModel);
Chris@17:
Chris@17: var entityDecorationView = new Drupal.quickedit.EntityDecorationView({
Chris@17: el: contextualLink.region,
Chris@17: model: entityModel
Chris@17: });
Chris@17: entityModel.set('entityDecorationView', entityDecorationView);
Chris@17:
Chris@17: _.each(fields, function (field) {
Chris@17: initializeField(field.el, field.fieldID, contextualLink.entityID, contextualLink.entityInstanceID);
Chris@17: });
Chris@17: fieldsAvailableQueue = _.difference(fieldsAvailableQueue, fields);
Chris@17:
Chris@17: var initContextualLink = _.once(function () {
Chris@17: var $links = $(contextualLink.el).find('.contextual-links');
Chris@17: var contextualLinkView = new Drupal.quickedit.ContextualLinkView($.extend({
Chris@17: el: $('
').prependTo($links),
Chris@17: model: entityModel,
Chris@17: appModel: Drupal.quickedit.app.model
Chris@17: }, options));
Chris@17: entityModel.set('contextualLinkView', contextualLinkView);
Chris@17: });
Chris@17:
Chris@17: loadMissingEditors(initContextualLink);
Chris@17:
Chris@17: return true;
Chris@17: }
Chris@17:
Chris@17: if (allMetadataExists(fieldIDs)) {
Chris@17: return true;
Chris@17: }
Chris@17:
Chris@17: return false;
Chris@17: }
Chris@17:
Chris@17: function extractEntityID(fieldID) {
Chris@17: return fieldID.split('/').slice(0, 2).join('/');
Chris@17: }
Chris@17:
Chris@17: function processField(fieldElement) {
Chris@17: var metadata = Drupal.quickedit.metadata;
Chris@17: var fieldID = fieldElement.getAttribute('data-quickedit-field-id');
Chris@17: var entityID = extractEntityID(fieldID);
Chris@17:
Chris@17: var entityElementSelector = '[data-quickedit-entity-id="' + entityID + '"]';
Chris@17: var $entityElement = $(entityElementSelector);
Chris@17:
Chris@17: if (!$entityElement.length) {
Chris@17: 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.');
Chris@17: }
Chris@17: var entityElement = $(fieldElement).closest($entityElement);
Chris@17:
Chris@17: if (entityElement.length === 0) {
Chris@17: var $lowestCommonParent = $entityElement.parents().has(fieldElement).first();
Chris@17: entityElement = $lowestCommonParent.find($entityElement);
Chris@17: }
Chris@17: var entityInstanceID = entityElement.get(0).getAttribute('data-quickedit-entity-instance-id');
Chris@17:
Chris@17: if (!metadata.has(fieldID)) {
Chris@17: fieldsMetadataQueue.push({
Chris@17: el: fieldElement,
Chris@17: fieldID: fieldID,
Chris@17: entityID: entityID,
Chris@17: entityInstanceID: entityInstanceID
Chris@17: });
Chris@17: return;
Chris@17: }
Chris@17:
Chris@17: if (metadata.get(fieldID, 'access') !== true) {
Chris@17: return;
Chris@17: }
Chris@17:
Chris@17: if (Drupal.quickedit.collections.entities.findWhere({
Chris@17: entityID: entityID,
Chris@17: entityInstanceID: entityInstanceID
Chris@17: })) {
Chris@17: initializeField(fieldElement, fieldID, entityID, entityInstanceID);
Chris@17: } else {
Chris@17: fieldsAvailableQueue.push({
Chris@17: el: fieldElement,
Chris@17: fieldID: fieldID,
Chris@17: entityID: entityID,
Chris@17: entityInstanceID: entityInstanceID
Chris@17: });
Chris@17: }
Chris@17: }
Chris@17:
Chris@17: function deleteContainedModelsAndQueues($context) {
Chris@17: $context.find('[data-quickedit-entity-id]').addBack('[data-quickedit-entity-id]').each(function (index, entityElement) {
Chris@17: var entityModel = Drupal.quickedit.collections.entities.findWhere({
Chris@17: el: entityElement
Chris@17: });
Chris@17: if (entityModel) {
Chris@17: var contextualLinkView = entityModel.get('contextualLinkView');
Chris@17: contextualLinkView.undelegateEvents();
Chris@17: contextualLinkView.remove();
Chris@17:
Chris@17: entityModel.get('entityDecorationView').remove();
Chris@17:
Chris@17: entityModel.destroy();
Chris@17: }
Chris@17:
Chris@17: function hasOtherRegion(contextualLink) {
Chris@17: return contextualLink.region !== entityElement;
Chris@17: }
Chris@17:
Chris@17: contextualLinksQueue = _.filter(contextualLinksQueue, hasOtherRegion);
Chris@17: });
Chris@17:
Chris@17: $context.find('[data-quickedit-field-id]').addBack('[data-quickedit-field-id]').each(function (index, fieldElement) {
Chris@17: Drupal.quickedit.collections.fields.chain().filter(function (fieldModel) {
Chris@17: return fieldModel.get('el') === fieldElement;
Chris@17: }).invoke('destroy');
Chris@17:
Chris@17: function hasOtherFieldElement(field) {
Chris@17: return field.el !== fieldElement;
Chris@17: }
Chris@17:
Chris@17: fieldsMetadataQueue = _.filter(fieldsMetadataQueue, hasOtherFieldElement);
Chris@17: fieldsAvailableQueue = _.filter(fieldsAvailableQueue, hasOtherFieldElement);
Chris@17: });
Chris@17: }
Chris@17:
Chris@17: function fetchMissingMetadata(callback) {
Chris@17: if (fieldsMetadataQueue.length) {
Chris@17: var fieldIDs = _.pluck(fieldsMetadataQueue, 'fieldID');
Chris@17: var fieldElementsWithoutMetadata = _.pluck(fieldsMetadataQueue, 'el');
Chris@17: var entityIDs = _.uniq(_.pluck(fieldsMetadataQueue, 'entityID'), true);
Chris@17:
Chris@17: entityIDs = _.difference(entityIDs, Drupal.quickedit.metadata.intersection(entityIDs));
Chris@17: fieldsMetadataQueue = [];
Chris@17:
Chris@17: $.ajax({
Chris@17: url: Drupal.url('quickedit/metadata'),
Chris@17: type: 'POST',
Chris@17: data: {
Chris@17: 'fields[]': fieldIDs,
Chris@17: 'entities[]': entityIDs
Chris@17: },
Chris@17: dataType: 'json',
Chris@17: success: function success(results) {
Chris@17: _.each(results, function (fieldMetadata, fieldID) {
Chris@17: Drupal.quickedit.metadata.add(fieldID, fieldMetadata);
Chris@17: });
Chris@17:
Chris@17: callback(fieldElementsWithoutMetadata);
Chris@17: }
Chris@17: });
Chris@17: }
Chris@17: }
Chris@17:
Chris@0: Drupal.behaviors.quickedit = {
Chris@0: attach: function attach(context) {
Chris@0: $('body').once('quickedit-init').each(initQuickEdit);
Chris@0:
Chris@0: var $fields = $(context).find('[data-quickedit-field-id]').once('quickedit');
Chris@0: if ($fields.length === 0) {
Chris@0: return;
Chris@0: }
Chris@0:
Chris@0: $(context).find('[data-quickedit-entity-id]').once('quickedit').each(function (index, entityElement) {
Chris@0: processEntity(entityElement);
Chris@0: });
Chris@0:
Chris@0: $fields.each(function (index, fieldElement) {
Chris@0: processField(fieldElement);
Chris@0: });
Chris@0:
Chris@0: contextualLinksQueue = _.filter(contextualLinksQueue, function (contextualLink) {
Chris@0: return !initializeEntityContextualLink(contextualLink);
Chris@0: });
Chris@0:
Chris@0: fetchMissingMetadata(function (fieldElementsWithFreshMetadata) {
Chris@0: _.each(fieldElementsWithFreshMetadata, processField);
Chris@0:
Chris@0: contextualLinksQueue = _.filter(contextualLinksQueue, function (contextualLink) {
Chris@0: return !initializeEntityContextualLink(contextualLink);
Chris@0: });
Chris@0: });
Chris@0: },
Chris@0: detach: function detach(context, settings, trigger) {
Chris@0: if (trigger === 'unload') {
Chris@0: deleteContainedModelsAndQueues($(context));
Chris@0: }
Chris@0: }
Chris@0: };
Chris@0:
Chris@0: Drupal.quickedit = {
Chris@0: app: null,
Chris@0:
Chris@0: collections: {
Chris@0: entities: null,
Chris@0:
Chris@0: fields: null
Chris@0: },
Chris@0:
Chris@0: editors: {},
Chris@0:
Chris@0: metadata: {
Chris@0: has: function has(fieldID) {
Chris@0: return storage.getItem(this._prefixFieldID(fieldID)) !== null;
Chris@0: },
Chris@0: add: function add(fieldID, metadata) {
Chris@0: storage.setItem(this._prefixFieldID(fieldID), JSON.stringify(metadata));
Chris@0: },
Chris@0: get: function get(fieldID, key) {
Chris@0: var metadata = JSON.parse(storage.getItem(this._prefixFieldID(fieldID)));
Chris@0: return typeof key === 'undefined' ? metadata : metadata[key];
Chris@0: },
Chris@0: _prefixFieldID: function _prefixFieldID(fieldID) {
Chris@0: return 'Drupal.quickedit.metadata.' + fieldID;
Chris@0: },
Chris@0: _unprefixFieldID: function _unprefixFieldID(fieldID) {
Chris@0: return fieldID.substring(26);
Chris@0: },
Chris@0: intersection: function intersection(fieldIDs) {
Chris@0: var prefixedFieldIDs = _.map(fieldIDs, this._prefixFieldID);
Chris@0: var intersection = _.intersection(prefixedFieldIDs, _.keys(sessionStorage));
Chris@0: return _.map(intersection, this._unprefixFieldID);
Chris@0: }
Chris@0: }
Chris@0: };
Chris@0:
Chris@0: var permissionsHashKey = Drupal.quickedit.metadata._prefixFieldID('permissionsHash');
Chris@0: var permissionsHashValue = storage.getItem(permissionsHashKey);
Chris@0: var permissionsHash = drupalSettings.user.permissionsHash;
Chris@0: if (permissionsHashValue !== permissionsHash) {
Chris@0: if (typeof permissionsHash === 'string') {
Chris@0: _.chain(storage).keys().each(function (key) {
Chris@0: if (key.substring(0, 26) === 'Drupal.quickedit.metadata.') {
Chris@0: storage.removeItem(key);
Chris@0: }
Chris@0: });
Chris@0: }
Chris@0: storage.setItem(permissionsHashKey, permissionsHash);
Chris@0: }
Chris@0:
Chris@0: $(document).on('drupalContextualLinkAdded', function (event, data) {
Chris@0: if (data.$region.is('[data-quickedit-entity-id]')) {
Chris@0: if (!data.$region.is('[data-quickedit-entity-instance-id]')) {
Chris@0: data.$region.once('quickedit');
Chris@0: processEntity(data.$region.get(0));
Chris@0: }
Chris@0: var contextualLink = {
Chris@0: entityID: data.$region.attr('data-quickedit-entity-id'),
Chris@0: entityInstanceID: data.$region.attr('data-quickedit-entity-instance-id'),
Chris@0: el: data.$el[0],
Chris@0: region: data.$region[0]
Chris@0: };
Chris@0:
Chris@0: if (!initializeEntityContextualLink(contextualLink)) {
Chris@0: contextualLinksQueue.push(contextualLink);
Chris@0: }
Chris@0: }
Chris@0: });
Chris@0: })(jQuery, _, Backbone, Drupal, drupalSettings, window.JSON, window.sessionStorage);