Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / quickedit / js / views / EditorView.es6.js
index 1a1a9845d53d9748d7f437ba01707b87bdb2985b..84211fabef9e191f8d97a78c4afeac9e59b8a619 100644 (file)
  * An abstract Backbone View that controls an in-place editor.
  */
 
-(function ($, Backbone, Drupal) {
-  Drupal.quickedit.EditorView = Backbone.View.extend(/** @lends Drupal.quickedit.EditorView# */{
+(function($, Backbone, Drupal) {
+  Drupal.quickedit.EditorView = Backbone.View.extend(
+    /** @lends Drupal.quickedit.EditorView# */ {
+      /**
+       * A base implementation that outlines the structure for in-place editors.
+       *
+       * Specific in-place editor implementations should subclass (extend) this
+       * View and override whichever method they deem necessary to override.
+       *
+       * Typically you would want to override this method to set the
+       * originalValue attribute in the FieldModel to such a value that your
+       * in-place editor can revert to the original value when necessary.
+       *
+       * @example
+       * <caption>If you override this method, you should call this
+       * method (the parent class' initialize()) first.</caption>
+       * Drupal.quickedit.EditorView.prototype.initialize.call(this, options);
+       *
+       * @constructs
+       *
+       * @augments Backbone.View
+       *
+       * @param {object} options
+       *   An object with the following keys:
+       * @param {Drupal.quickedit.EditorModel} options.model
+       *   The in-place editor state model.
+       * @param {Drupal.quickedit.FieldModel} options.fieldModel
+       *   The field model.
+       *
+       * @see Drupal.quickedit.EditorModel
+       * @see Drupal.quickedit.editors.plain_text
+       */
+      initialize(options) {
+        this.fieldModel = options.fieldModel;
+        this.listenTo(this.fieldModel, 'change:state', this.stateChange);
+      },
 
-    /**
-     * A base implementation that outlines the structure for in-place editors.
-     *
-     * Specific in-place editor implementations should subclass (extend) this
-     * View and override whichever method they deem necessary to override.
-     *
-     * Typically you would want to override this method to set the
-     * originalValue attribute in the FieldModel to such a value that your
-     * in-place editor can revert to the original value when necessary.
-     *
-     * @example
-     * <caption>If you override this method, you should call this
-     * method (the parent class' initialize()) first.</caption>
-     * Drupal.quickedit.EditorView.prototype.initialize.call(this, options);
-     *
-     * @constructs
-     *
-     * @augments Backbone.View
-     *
-     * @param {object} options
-     *   An object with the following keys:
-     * @param {Drupal.quickedit.EditorModel} options.model
-     *   The in-place editor state model.
-     * @param {Drupal.quickedit.FieldModel} options.fieldModel
-     *   The field model.
-     *
-     * @see Drupal.quickedit.EditorModel
-     * @see Drupal.quickedit.editors.plain_text
-     */
-    initialize(options) {
-      this.fieldModel = options.fieldModel;
-      this.listenTo(this.fieldModel, 'change:state', this.stateChange);
-    },
-
-    /**
-     * @inheritdoc
-     */
-    remove() {
-      // The el property is the field, which should not be removed. Remove the
-      // pointer to it, then call Backbone.View.prototype.remove().
-      this.setElement();
-      Backbone.View.prototype.remove.call(this);
-    },
-
-    /**
-     * Returns the edited element.
-     *
-     * For some single cardinality fields, it may be necessary or useful to
-     * not in-place edit (and hence decorate) the DOM element with the
-     * data-quickedit-field-id attribute (which is the field's wrapper), but a
-     * specific element within the field's wrapper.
-     * e.g. using a WYSIWYG editor on a body field should happen on the DOM
-     * element containing the text itself, not on the field wrapper.
-     *
-     * @return {jQuery}
-     *   A jQuery-wrapped DOM element.
-     *
-     * @see Drupal.quickedit.editors.plain_text
-     */
-    getEditedElement() {
-      return this.$el;
-    },
-
-    /**
-     *
-     * @return {object}
-     * Returns 3 Quick Edit UI settings that depend on the in-place editor:
-     *  - Boolean padding: indicates whether padding should be applied to the
-     *    edited element, to guarantee legibility of text.
-     *  - Boolean unifiedToolbar: provides the in-place editor with the ability
-     *    to insert its own toolbar UI into Quick Edit's tightly integrated
-     *    toolbar.
-     *  - Boolean fullWidthToolbar: indicates whether Quick Edit's tightly
-     *    integrated toolbar should consume the full width of the element,
-     *    rather than being just long enough to accommodate a label.
-     */
-    getQuickEditUISettings() {
-      return { padding: false, unifiedToolbar: false, fullWidthToolbar: false, popup: false };
-    },
+      /**
+       * @inheritdoc
+       */
+      remove() {
+        // The el property is the field, which should not be removed. Remove the
+        // pointer to it, then call Backbone.View.prototype.remove().
+        this.setElement();
+        Backbone.View.prototype.remove.call(this);
+      },
 
-    /**
-     * Determines the actions to take given a change of state.
-     *
-     * @param {Drupal.quickedit.FieldModel} fieldModel
-     *   The quickedit `FieldModel` that holds the state.
-     * @param {string} state
-     *   The state of the associated field. One of
-     *   {@link Drupal.quickedit.FieldModel.states}.
-     */
-    stateChange(fieldModel, state) {
-      const from = fieldModel.previous('state');
-      const to = state;
-      switch (to) {
-        case 'inactive':
-          // An in-place editor view will not yet exist in this state, hence
-          // this will never be reached. Listed for sake of completeness.
-          break;
+      /**
+       * Returns the edited element.
+       *
+       * For some single cardinality fields, it may be necessary or useful to
+       * not in-place edit (and hence decorate) the DOM element with the
+       * data-quickedit-field-id attribute (which is the field's wrapper), but a
+       * specific element within the field's wrapper.
+       * e.g. using a WYSIWYG editor on a body field should happen on the DOM
+       * element containing the text itself, not on the field wrapper.
+       *
+       * @return {jQuery}
+       *   A jQuery-wrapped DOM element.
+       *
+       * @see Drupal.quickedit.editors.plain_text
+       */
+      getEditedElement() {
+        return this.$el;
+      },
 
-        case 'candidate':
-          // Nothing to do for the typical in-place editor: it should not be
-          // visible yet. Except when we come from the 'invalid' state, then we
-          // clean up.
-          if (from === 'invalid') {
-            this.removeValidationErrors();
-          }
-          break;
-
-        case 'highlighted':
-          // Nothing to do for the typical in-place editor: it should not be
-          // visible yet.
-          break;
+      /**
+       *
+       * @return {object}
+       * Returns 3 Quick Edit UI settings that depend on the in-place editor:
+       *  - Boolean padding: indicates whether padding should be applied to the
+       *    edited element, to guarantee legibility of text.
+       *  - Boolean unifiedToolbar: provides the in-place editor with the ability
+       *    to insert its own toolbar UI into Quick Edit's tightly integrated
+       *    toolbar.
+       *  - Boolean fullWidthToolbar: indicates whether Quick Edit's tightly
+       *    integrated toolbar should consume the full width of the element,
+       *    rather than being just long enough to accommodate a label.
+       */
+      getQuickEditUISettings() {
+        return {
+          padding: false,
+          unifiedToolbar: false,
+          fullWidthToolbar: false,
+          popup: false,
+        };
+      },
 
-        case 'activating': {
-          // The user has indicated he wants to do in-place editing: if
-          // something needs to be loaded (CSS/JavaScript/server data/…), then
-          // do so at this stage, and once the in-place editor is ready,
-          // set the 'active' state. A "loading" indicator will be shown in the
-          // UI for as long as the field remains in this state.
-          const loadDependencies = function (callback) {
-            // Do the loading here.
-            callback();
-          };
-          loadDependencies(() => {
-            fieldModel.set('state', 'active');
-          });
-          break;
-        }
+      /**
+       * Determines the actions to take given a change of state.
+       *
+       * @param {Drupal.quickedit.FieldModel} fieldModel
+       *   The quickedit `FieldModel` that holds the state.
+       * @param {string} state
+       *   The state of the associated field. One of
+       *   {@link Drupal.quickedit.FieldModel.states}.
+       */
+      stateChange(fieldModel, state) {
+        const from = fieldModel.previous('state');
+        const to = state;
+        switch (to) {
+          case 'inactive':
+            // An in-place editor view will not yet exist in this state, hence
+            // this will never be reached. Listed for sake of completeness.
+            break;
 
-        case 'active':
-          // The user can now actually use the in-place editor.
-          break;
+          case 'candidate':
+            // Nothing to do for the typical in-place editor: it should not be
+            // visible yet. Except when we come from the 'invalid' state, then we
+            // clean up.
+            if (from === 'invalid') {
+              this.removeValidationErrors();
+            }
+            break;
 
-        case 'changed':
-          // Nothing to do for the typical in-place editor. The UI will show an
-          // indicator that the field has changed.
-          break;
+          case 'highlighted':
+            // Nothing to do for the typical in-place editor: it should not be
+            // visible yet.
+            break;
 
-        case 'saving':
-          // When the user has indicated he wants to save his changes to this
-          // field, this state will be entered. If the previous saving attempt
-          // resulted in validation errors, the previous state will be
-          // 'invalid'. Clean up those validation errors while the user is
-          // saving.
-          if (from === 'invalid') {
-            this.removeValidationErrors();
+          case 'activating': {
+            // The user has indicated he wants to do in-place editing: if
+            // something needs to be loaded (CSS/JavaScript/server data/…), then
+            // do so at this stage, and once the in-place editor is ready,
+            // set the 'active' state. A "loading" indicator will be shown in the
+            // UI for as long as the field remains in this state.
+            const loadDependencies = function(callback) {
+              // Do the loading here.
+              callback();
+            };
+            loadDependencies(() => {
+              fieldModel.set('state', 'active');
+            });
+            break;
           }
-          this.save();
-          break;
 
-        case 'saved':
-          // Nothing to do for the typical in-place editor. Immediately after
-          // being saved, a field will go to the 'candidate' state, where it
-          // should no longer be visible (after all, the field will then again
-          // just be a *candidate* to be in-place edited).
-          break;
+          case 'active':
+            // The user can now actually use the in-place editor.
+            break;
 
-        case 'invalid':
-          // The modified field value was attempted to be saved, but there were
-          // validation errors.
-          this.showValidationErrors();
-          break;
-      }
-    },
+          case 'changed':
+            // Nothing to do for the typical in-place editor. The UI will show an
+            // indicator that the field has changed.
+            break;
 
-    /**
-     * Reverts the modified value to the original, before editing started.
-     */
-    revert() {
-      // A no-op by default; each editor should implement reverting itself.
-      // Note that if the in-place editor does not cause the FieldModel's
-      // element to be modified, then nothing needs to happen.
-    },
+          case 'saving':
+            // When the user has indicated he wants to save his changes to this
+            // field, this state will be entered. If the previous saving attempt
+            // resulted in validation errors, the previous state will be
+            // 'invalid'. Clean up those validation errors while the user is
+            // saving.
+            if (from === 'invalid') {
+              this.removeValidationErrors();
+            }
+            this.save();
+            break;
 
-    /**
-     * Saves the modified value in the in-place editor for this field.
-     */
-    save() {
-      const fieldModel = this.fieldModel;
-      const editorModel = this.model;
-      const backstageId = `quickedit_backstage-${this.fieldModel.id.replace(/[/[\]_\s]/g, '-')}`;
+          case 'saved':
+            // Nothing to do for the typical in-place editor. Immediately after
+            // being saved, a field will go to the 'candidate' state, where it
+            // should no longer be visible (after all, the field will then again
+            // just be a *candidate* to be in-place edited).
+            break;
 
-      function fillAndSubmitForm(value) {
-        const $form = $(`#${backstageId}`).find('form');
-        // Fill in the value in any <input> that isn't hidden or a submit
-        // button.
-        $form.find(':input[type!="hidden"][type!="submit"]:not(select)')
-          // Don't mess with the node summary.
-          .not('[name$="\\[summary\\]"]').val(value);
-        // Submit the form.
-        $form.find('.quickedit-form-submit').trigger('click.quickedit');
-      }
+          case 'invalid':
+            // The modified field value was attempted to be saved, but there were
+            // validation errors.
+            this.showValidationErrors();
+            break;
+        }
+      },
 
-      const formOptions = {
-        fieldID: this.fieldModel.get('fieldID'),
-        $el: this.$el,
-        nocssjs: true,
-        other_view_modes: fieldModel.findOtherViewModes(),
-        // Reset an existing entry for this entity in the PrivateTempStore (if
-        // any) when saving the field. Logically speaking, this should happen in
-        // a separate request because this is an entity-level operation, not a
-        // field-level operation. But that would require an additional request,
-        // that might not even be necessary: it is only when a user saves a
-        // first changed field for an entity that this needs to happen:
-        // precisely now!
-        reset: !this.fieldModel.get('entity').get('inTempStore'),
-      };
+      /**
+       * Reverts the modified value to the original, before editing started.
+       */
+      revert() {
+        // A no-op by default; each editor should implement reverting itself.
+        // Note that if the in-place editor does not cause the FieldModel's
+        // element to be modified, then nothing needs to happen.
+      },
 
-      const self = this;
-      Drupal.quickedit.util.form.load(formOptions, (form, ajax) => {
-        // Create a backstage area for storing forms that are hidden from view
-        // (hence "backstage" — since the editing doesn't happen in the form, it
-        // happens "directly" in the content, the form is only used for saving).
-        const $backstage = $(Drupal.theme('quickeditBackstage', { id: backstageId })).appendTo('body');
-        // Hidden forms are stuffed into the backstage container for this field.
-        const $form = $(form).appendTo($backstage);
-        // Disable the browser's HTML5 validation; we only care about server-
-        // side validation. (Not disabling this will actually cause problems
-        // because browsers don't like to set HTML5 validation errors on hidden
-        // forms.)
-        $form.prop('novalidate', true);
-        const $submit = $form.find('.quickedit-form-submit');
-        self.formSaveAjax = Drupal.quickedit.util.form.ajaxifySaving(formOptions, $submit);
+      /**
+       * Saves the modified value in the in-place editor for this field.
+       */
+      save() {
+        const fieldModel = this.fieldModel;
+        const editorModel = this.model;
+        const backstageId = `quickedit_backstage-${this.fieldModel.id.replace(
+          /[/[\]_\s]/g,
+          '-',
+        )}`;
 
-        function removeHiddenForm() {
-          Drupal.quickedit.util.form.unajaxifySaving(self.formSaveAjax);
-          delete self.formSaveAjax;
-          $backstage.remove();
+        function fillAndSubmitForm(value) {
+          const $form = $(`#${backstageId}`).find('form');
+          // Fill in the value in any <input> that isn't hidden or a submit
+          // button.
+          $form
+            .find(':input[type!="hidden"][type!="submit"]:not(select)')
+            // Don't mess with the node summary.
+            .not('[name$="\\[summary\\]"]')
+            .val(value);
+          // Submit the form.
+          $form.find('.quickedit-form-submit').trigger('click.quickedit');
         }
 
-        // Successfully saved.
-        self.formSaveAjax.commands.quickeditFieldFormSaved = function (ajax, response, status) {
-          removeHiddenForm();
-          // First, transition the state to 'saved'.
-          fieldModel.set('state', 'saved');
-          // Second, set the 'htmlForOtherViewModes' attribute, so that when
-          // this field is rerendered, the change can be propagated to other
-          // instances of this field, which may be displayed in different view
-          // modes.
-          fieldModel.set('htmlForOtherViewModes', response.other_view_modes);
-          // Finally, set the 'html' attribute on the field model. This will
-          // cause the field to be rerendered.
-          fieldModel.set('html', response.data);
+        const formOptions = {
+          fieldID: this.fieldModel.get('fieldID'),
+          $el: this.$el,
+          nocssjs: true,
+          other_view_modes: fieldModel.findOtherViewModes(),
+          // Reset an existing entry for this entity in the PrivateTempStore (if
+          // any) when saving the field. Logically speaking, this should happen in
+          // a separate request because this is an entity-level operation, not a
+          // field-level operation. But that would require an additional request,
+          // that might not even be necessary: it is only when a user saves a
+          // first changed field for an entity that this needs to happen:
+          // precisely now!
+          reset: !this.fieldModel.get('entity').get('inTempStore'),
         };
 
-        // Unsuccessfully saved; validation errors.
-        self.formSaveAjax.commands.quickeditFieldFormValidationErrors = function (ajax, response, status) {
-          removeHiddenForm();
-          editorModel.set('validationErrors', response.data);
-          fieldModel.set('state', 'invalid');
-        };
+        const self = this;
+        Drupal.quickedit.util.form.load(formOptions, (form, ajax) => {
+          // Create a backstage area for storing forms that are hidden from view
+          // (hence "backstage" — since the editing doesn't happen in the form, it
+          // happens "directly" in the content, the form is only used for saving).
+          const $backstage = $(
+            Drupal.theme('quickeditBackstage', { id: backstageId }),
+          ).appendTo('body');
+          // Hidden forms are stuffed into the backstage container for this field.
+          const $form = $(form).appendTo($backstage);
+          // Disable the browser's HTML5 validation; we only care about server-
+          // side validation. (Not disabling this will actually cause problems
+          // because browsers don't like to set HTML5 validation errors on hidden
+          // forms.)
+          $form.prop('novalidate', true);
+          const $submit = $form.find('.quickedit-form-submit');
+          self.formSaveAjax = Drupal.quickedit.util.form.ajaxifySaving(
+            formOptions,
+            $submit,
+          );
 
-        // The quickeditFieldForm AJAX command is only called upon loading the
-        // form for the first time, and when there are validation errors in the
-        // form; Form API then marks which form items have errors. This is
-        // useful for the form-based in-place editor, but pointless for any
-        // other: the form itself won't be visible at all anyway! So, we just
-        // ignore it.
-        self.formSaveAjax.commands.quickeditFieldForm = function () {};
+          function removeHiddenForm() {
+            Drupal.quickedit.util.form.unajaxifySaving(self.formSaveAjax);
+            delete self.formSaveAjax;
+            $backstage.remove();
+          }
 
-        fillAndSubmitForm(editorModel.get('currentValue'));
-      });
-    },
+          // Successfully saved.
+          self.formSaveAjax.commands.quickeditFieldFormSaved = function(
+            ajax,
+            response,
+            status,
+          ) {
+            removeHiddenForm();
+            // First, transition the state to 'saved'.
+            fieldModel.set('state', 'saved');
+            // Second, set the 'htmlForOtherViewModes' attribute, so that when
+            // this field is rerendered, the change can be propagated to other
+            // instances of this field, which may be displayed in different view
+            // modes.
+            fieldModel.set('htmlForOtherViewModes', response.other_view_modes);
+            // Finally, set the 'html' attribute on the field model. This will
+            // cause the field to be rerendered.
+            fieldModel.set('html', response.data);
+          };
 
-    /**
-     * Shows validation error messages.
-     *
-     * Should be called when the state is changed to 'invalid'.
-     */
-    showValidationErrors() {
-      const $errors = $('<div class="quickedit-validation-errors"></div>')
-        .append(this.model.get('validationErrors'));
-      this.getEditedElement()
-        .addClass('quickedit-validation-error')
-        .after($errors);
-    },
+          // Unsuccessfully saved; validation errors.
+          self.formSaveAjax.commands.quickeditFieldFormValidationErrors = function(
+            ajax,
+            response,
+            status,
+          ) {
+            removeHiddenForm();
+            editorModel.set('validationErrors', response.data);
+            fieldModel.set('state', 'invalid');
+          };
 
-    /**
-     * Cleans up validation error messages.
-     *
-     * Should be called when the state is changed to 'candidate' or 'saving'. In
-     * the case of the latter: the user has modified the value in the in-place
-     * editor again to attempt to save again. In the case of the latter: the
-     * invalid value was discarded.
-     */
-    removeValidationErrors() {
-      this.getEditedElement()
-        .removeClass('quickedit-validation-error')
-        .next('.quickedit-validation-errors')
-        .remove();
-    },
+          // The quickeditFieldForm AJAX command is only called upon loading the
+          // form for the first time, and when there are validation errors in the
+          // form; Form API then marks which form items have errors. This is
+          // useful for the form-based in-place editor, but pointless for any
+          // other: the form itself won't be visible at all anyway! So, we just
+          // ignore it.
+          self.formSaveAjax.commands.quickeditFieldForm = function() {};
 
-  });
-}(jQuery, Backbone, Drupal));
+          fillAndSubmitForm(editorModel.get('currentValue'));
+        });
+      },
+
+      /**
+       * Shows validation error messages.
+       *
+       * Should be called when the state is changed to 'invalid'.
+       */
+      showValidationErrors() {
+        const $errors = $(
+          '<div class="quickedit-validation-errors"></div>',
+        ).append(this.model.get('validationErrors'));
+        this.getEditedElement()
+          .addClass('quickedit-validation-error')
+          .after($errors);
+      },
+
+      /**
+       * Cleans up validation error messages.
+       *
+       * Should be called when the state is changed to 'candidate' or 'saving'. In
+       * the case of the latter: the user has modified the value in the in-place
+       * editor again to attempt to save again. In the case of the latter: the
+       * invalid value was discarded.
+       */
+      removeValidationErrors() {
+        this.getEditedElement()
+          .removeClass('quickedit-validation-error')
+          .next('.quickedit-validation-errors')
+          .remove();
+      },
+    },
+  );
+})(jQuery, Backbone, Drupal);