Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / quickedit / js / views / EntityToolbarView.es6.js
index 9975ff353569da83c387c3306c94266f84f32433..0c9628d075228d063baaada3f1fc8dbdd315ab70 100644 (file)
  * A Backbone View that provides an entity level toolbar.
  */
 
-(function ($, _, Backbone, Drupal, debounce) {
-  Drupal.quickedit.EntityToolbarView = Backbone.View.extend(/** @lends Drupal.quickedit.EntityToolbarView# */{
-
-    /**
-     * @type {jQuery}
-     */
-    _fieldToolbarRoot: null,
-
-    /**
-     * @return {object}
-     *   A map of events.
-     */
-    events() {
-      const map = {
-        'click button.action-save': 'onClickSave',
-        'click button.action-cancel': 'onClickCancel',
-        mouseenter: 'onMouseenter',
-      };
-      return map;
-    },
+(function($, _, Backbone, Drupal, debounce) {
+  Drupal.quickedit.EntityToolbarView = Backbone.View.extend(
+    /** @lends Drupal.quickedit.EntityToolbarView# */ {
+      /**
+       * @type {jQuery}
+       */
+      _fieldToolbarRoot: null,
 
-    /**
-     * @constructs
-     *
-     * @augments Backbone.View
-     *
-     * @param {object} options
-     *   Options to construct the view.
-     * @param {Drupal.quickedit.AppModel} options.appModel
-     *   A quickedit `AppModel` to use in the view.
-     */
-    initialize(options) {
-      const that = this;
-      this.appModel = options.appModel;
-      this.$entity = $(this.model.get('el'));
-
-      // Rerender whenever the entity state changes.
-      this.listenTo(this.model, 'change:isActive change:isDirty change:state', this.render);
-      // Also rerender whenever a different field is highlighted or activated.
-      this.listenTo(this.appModel, 'change:highlightedField change:activeField', this.render);
-      // Rerender when a field of the entity changes state.
-      this.listenTo(this.model.get('fields'), 'change:state', this.fieldStateChange);
-
-      // Reposition the entity toolbar as the viewport and the position within
-      // the viewport changes.
-      $(window).on('resize.quickedit scroll.quickedit drupalViewportOffsetChange.quickedit', debounce($.proxy(this.windowChangeHandler, this), 150));
-
-      // Adjust the fence placement within which the entity toolbar may be
-      // positioned.
-      $(document).on('drupalViewportOffsetChange.quickedit', (event, offsets) => {
-        if (that.$fence) {
-          that.$fence.css(offsets);
-        }
-      });
+      /**
+       * @return {object}
+       *   A map of events.
+       */
+      events() {
+        const map = {
+          'click button.action-save': 'onClickSave',
+          'click button.action-cancel': 'onClickCancel',
+          mouseenter: 'onMouseenter',
+        };
+        return map;
+      },
+
+      /**
+       * @constructs
+       *
+       * @augments Backbone.View
+       *
+       * @param {object} options
+       *   Options to construct the view.
+       * @param {Drupal.quickedit.AppModel} options.appModel
+       *   A quickedit `AppModel` to use in the view.
+       */
+      initialize(options) {
+        const that = this;
+        this.appModel = options.appModel;
+        this.$entity = $(this.model.get('el'));
+
+        // Rerender whenever the entity state changes.
+        this.listenTo(
+          this.model,
+          'change:isActive change:isDirty change:state',
+          this.render,
+        );
+        // Also rerender whenever a different field is highlighted or activated.
+        this.listenTo(
+          this.appModel,
+          'change:highlightedField change:activeField',
+          this.render,
+        );
+        // Rerender when a field of the entity changes state.
+        this.listenTo(
+          this.model.get('fields'),
+          'change:state',
+          this.fieldStateChange,
+        );
+
+        // Reposition the entity toolbar as the viewport and the position within
+        // the viewport changes.
+        $(window).on(
+          'resize.quickedit scroll.quickedit drupalViewportOffsetChange.quickedit',
+          debounce($.proxy(this.windowChangeHandler, this), 150),
+        );
+
+        // Adjust the fence placement within which the entity toolbar may be
+        // positioned.
+        $(document).on(
+          'drupalViewportOffsetChange.quickedit',
+          (event, offsets) => {
+            if (that.$fence) {
+              that.$fence.css(offsets);
+            }
+          },
+        );
 
-      // Set the entity toolbar DOM element as the el for this view.
-      const $toolbar = this.buildToolbarEl();
-      this.setElement($toolbar);
-      this._fieldToolbarRoot = $toolbar.find('.quickedit-toolbar-field').get(0);
+        // Set the entity toolbar DOM element as the el for this view.
+        const $toolbar = this.buildToolbarEl();
+        this.setElement($toolbar);
+        this._fieldToolbarRoot = $toolbar
+          .find('.quickedit-toolbar-field')
+          .get(0);
 
-      // Initial render.
-      this.render();
-    },
+        // Initial render.
+        this.render();
+      },
 
-    /**
-     * @inheritdoc
-     *
-     * @return {Drupal.quickedit.EntityToolbarView}
-     *   The entity toolbar view.
-     */
-    render() {
-      if (this.model.get('isActive')) {
-        // If the toolbar container doesn't exist, create it.
-        const $body = $('body');
-        if ($body.children('#quickedit-entity-toolbar').length === 0) {
-          $body.append(this.$el);
-        }
-        // The fence will define a area on the screen that the entity toolbar
-        // will be position within.
-        if ($body.children('#quickedit-toolbar-fence').length === 0) {
-          this.$fence = $(Drupal.theme('quickeditEntityToolbarFence'))
-            .css(Drupal.displace())
-            .appendTo($body);
+      /**
+       * @inheritdoc
+       *
+       * @return {Drupal.quickedit.EntityToolbarView}
+       *   The entity toolbar view.
+       */
+      render() {
+        if (this.model.get('isActive')) {
+          // If the toolbar container doesn't exist, create it.
+          const $body = $('body');
+          if ($body.children('#quickedit-entity-toolbar').length === 0) {
+            $body.append(this.$el);
+          }
+          // The fence will define a area on the screen that the entity toolbar
+          // will be position within.
+          if ($body.children('#quickedit-toolbar-fence').length === 0) {
+            this.$fence = $(Drupal.theme('quickeditEntityToolbarFence'))
+              .css(Drupal.displace())
+              .appendTo($body);
+          }
+          // Adds the entity title to the toolbar.
+          this.label();
+
+          // Show the save and cancel buttons.
+          this.show('ops');
+          // If render is being called and the toolbar is already visible, just
+          // reposition it.
+          this.position();
         }
-        // Adds the entity title to the toolbar.
-        this.label();
 
-        // Show the save and cancel buttons.
-        this.show('ops');
-        // If render is being called and the toolbar is already visible, just
-        // reposition it.
-        this.position();
-      }
-
-      // The save button text and state varies with the state of the entity
-      // model.
-      const $button = this.$el.find('.quickedit-button.action-save');
-      const isDirty = this.model.get('isDirty');
-      // Adjust the save button according to the state of the model.
-      switch (this.model.get('state')) {
-        // Quick editing is active, but no field is being edited.
-        case 'opened':
-          // The saving throbber is not managed by AJAX system. The
-          // EntityToolbarView manages this visual element.
-          $button
-            .removeClass('action-saving icon-throbber icon-end')
-            .text(Drupal.t('Save'))
-            .removeAttr('disabled')
-            .attr('aria-hidden', !isDirty);
-          break;
-
-        // The changes to the fields of the entity are being committed.
-        case 'committing':
-          $button
-            .addClass('action-saving icon-throbber icon-end')
-            .text(Drupal.t('Saving'))
-            .attr('disabled', 'disabled');
-          break;
-
-        default:
-          $button.attr('aria-hidden', true);
-          break;
-      }
-
-      return this;
-    },
+        // The save button text and state varies with the state of the entity
+        // model.
+        const $button = this.$el.find('.quickedit-button.action-save');
+        const isDirty = this.model.get('isDirty');
+        // Adjust the save button according to the state of the model.
+        switch (this.model.get('state')) {
+          // Quick editing is active, but no field is being edited.
+          case 'opened':
+            // The saving throbber is not managed by AJAX system. The
+            // EntityToolbarView manages this visual element.
+            $button
+              .removeClass('action-saving icon-throbber icon-end')
+              .text(Drupal.t('Save'))
+              .removeAttr('disabled')
+              .attr('aria-hidden', !isDirty);
+            break;
 
-    /**
-     * @inheritdoc
-     */
-    remove() {
-      // Remove additional DOM elements controlled by this View.
-      this.$fence.remove();
+          // The changes to the fields of the entity are being committed.
+          case 'committing':
+            $button
+              .addClass('action-saving icon-throbber icon-end')
+              .text(Drupal.t('Saving'))
+              .attr('disabled', 'disabled');
+            break;
 
-      // Stop listening to additional events.
-      $(window).off('resize.quickedit scroll.quickedit drupalViewportOffsetChange.quickedit');
-      $(document).off('drupalViewportOffsetChange.quickedit');
+          default:
+            $button.attr('aria-hidden', true);
+            break;
+        }
 
-      Backbone.View.prototype.remove.call(this);
-    },
+        return this;
+      },
 
-    /**
-     * Repositions the entity toolbar on window scroll and resize.
-     *
-     * @param {jQuery.Event} event
-     *   The scroll or resize event.
-     */
-    windowChangeHandler(event) {
-      this.position();
-    },
+      /**
+       * @inheritdoc
+       */
+      remove() {
+        // Remove additional DOM elements controlled by this View.
+        this.$fence.remove();
 
-    /**
-     * Determines the actions to take given a change of state.
-     *
-     * @param {Drupal.quickedit.FieldModel} model
-     *   The `FieldModel` model.
-     * @param {string} state
-     *   The state of the associated field. One of
-     *   {@link Drupal.quickedit.FieldModel.states}.
-     */
-    fieldStateChange(model, state) {
-      switch (state) {
-        case 'active':
-          this.render();
-          break;
-
-        case 'invalid':
-          this.render();
-          break;
-      }
-    },
+        // Stop listening to additional events.
+        $(window).off(
+          'resize.quickedit scroll.quickedit drupalViewportOffsetChange.quickedit',
+        );
+        $(document).off('drupalViewportOffsetChange.quickedit');
 
-    /**
-     * Uses the jQuery.ui.position() method to position the entity toolbar.
-     *
-     * @param {HTMLElement} [element]
-     *   The element against which the entity toolbar is positioned.
-     */
-    position(element) {
-      clearTimeout(this.timer);
-
-      const that = this;
-      // Vary the edge of the positioning according to the direction of language
-      // in the document.
-      const edge = (document.documentElement.dir === 'rtl') ? 'right' : 'left';
-      // A time unit to wait until the entity toolbar is repositioned.
-      let delay = 0;
-      // Determines what check in the series of checks below should be
-      // evaluated.
-      let check = 0;
-      // When positioned against an active field that has padding, we should
-      // ignore that padding when positioning the toolbar, to not unnecessarily
-      // move the toolbar horizontally, which feels annoying.
-      let horizontalPadding = 0;
-      let of;
-      let activeField;
-      let highlightedField;
-      // There are several elements in the page that the entity toolbar might be
-      // positioned against. They are considered below in a priority order.
-      do {
-        switch (check) {
-          case 0:
-            // Position against a specific element.
-            of = element;
-            break;
+        Backbone.View.prototype.remove.call(this);
+      },
 
-          case 1:
-            // Position against a form container.
-            activeField = Drupal.quickedit.app.model.get('activeField');
-            of = activeField && activeField.editorView && activeField.editorView.$formContainer && activeField.editorView.$formContainer.find('.quickedit-form');
-            break;
-
-          case 2:
-            // Position against an active field.
-            of = activeField && activeField.editorView && activeField.editorView.getEditedElement();
-            if (activeField && activeField.editorView && activeField.editorView.getQuickEditUISettings().padding) {
-              horizontalPadding = 5;
-            }
-            break;
+      /**
+       * Repositions the entity toolbar on window scroll and resize.
+       *
+       * @param {jQuery.Event} event
+       *   The scroll or resize event.
+       */
+      windowChangeHandler(event) {
+        this.position();
+      },
 
-          case 3:
-            // Position against a highlighted field.
-            highlightedField = Drupal.quickedit.app.model.get('highlightedField');
-            of = highlightedField && highlightedField.editorView && highlightedField.editorView.getEditedElement();
-            delay = 250;
+      /**
+       * Determines the actions to take given a change of state.
+       *
+       * @param {Drupal.quickedit.FieldModel} model
+       *   The `FieldModel` model.
+       * @param {string} state
+       *   The state of the associated field. One of
+       *   {@link Drupal.quickedit.FieldModel.states}.
+       */
+      fieldStateChange(model, state) {
+        switch (state) {
+          case 'active':
+            this.render();
             break;
 
-          default: {
-            const fieldModels = this.model.get('fields').models;
-            let topMostPosition = 1000000;
-            let topMostField = null;
-            // Position against the topmost field.
-            for (let i = 0; i < fieldModels.length; i++) {
-              const pos = fieldModels[i].get('el').getBoundingClientRect().top;
-              if (pos < topMostPosition) {
-                topMostPosition = pos;
-                topMostField = fieldModels[i];
-              }
-            }
-            of = topMostField.get('el');
-            delay = 50;
+          case 'invalid':
+            this.render();
             break;
-          }
         }
-        // Prepare to check the next possible element to position against.
-        check++;
-      } while (!of);
+      },
 
       /**
-       * Refines the positioning algorithm of jquery.ui.position().
-       *
-       * Invoked as the 'using' callback of jquery.ui.position() in
-       * positionToolbar().
+       * Uses the jQuery.ui.position() method to position the entity toolbar.
        *
-       * @param {*} view
-       *   The view the positions will be calculated from.
-       * @param {object} suggested
-       *   A hash of top and left values for the position that should be set. It
-       *   can be forwarded to .css() or .animate().
-       * @param {object} info
-       *   The position and dimensions of both the 'my' element and the 'of'
-       *   elements, as well as calculations to their relative position. This
-       *   object contains the following properties:
-       * @param {object} info.element
-       *   A hash that contains information about the HTML element that will be
-       *   positioned. Also known as the 'my' element.
-       * @param {object} info.target
-       *   A hash that contains information about the HTML element that the
-       *   'my' element will be positioned against. Also known as the 'of'
-       *   element.
+       * @param {HTMLElement} [element]
+       *   The element against which the entity toolbar is positioned.
        */
-      function refinePosition(view, suggested, info) {
-        // Determine if the pointer should be on the top or bottom.
-        const isBelow = suggested.top > info.target.top;
-        info.element.element.toggleClass('quickedit-toolbar-pointer-top', isBelow);
-        // Don't position the toolbar past the first or last editable field if
-        // the entity is the target.
-        if (view.$entity[0] === info.target.element[0]) {
-          // Get the first or last field according to whether the toolbar is
-          // above or below the entity.
-          const $field = view.$entity.find('.quickedit-editable').eq((isBelow) ? -1 : 0);
-          if ($field.length > 0) {
-            suggested.top = (isBelow) ? ($field.offset().top + $field.outerHeight(true)) : $field.offset().top - info.element.element.outerHeight(true);
+      position(element) {
+        clearTimeout(this.timer);
+
+        const that = this;
+        // Vary the edge of the positioning according to the direction of language
+        // in the document.
+        const edge = document.documentElement.dir === 'rtl' ? 'right' : 'left';
+        // A time unit to wait until the entity toolbar is repositioned.
+        let delay = 0;
+        // Determines what check in the series of checks below should be
+        // evaluated.
+        let check = 0;
+        // When positioned against an active field that has padding, we should
+        // ignore that padding when positioning the toolbar, to not unnecessarily
+        // move the toolbar horizontally, which feels annoying.
+        let horizontalPadding = 0;
+        let of;
+        let activeField;
+        let highlightedField;
+        // There are several elements in the page that the entity toolbar might be
+        // positioned against. They are considered below in a priority order.
+        do {
+          switch (check) {
+            case 0:
+              // Position against a specific element.
+              of = element;
+              break;
+
+            case 1:
+              // Position against a form container.
+              activeField = Drupal.quickedit.app.model.get('activeField');
+              of =
+                activeField &&
+                activeField.editorView &&
+                activeField.editorView.$formContainer &&
+                activeField.editorView.$formContainer.find('.quickedit-form');
+              break;
+
+            case 2:
+              // Position against an active field.
+              of =
+                activeField &&
+                activeField.editorView &&
+                activeField.editorView.getEditedElement();
+              if (
+                activeField &&
+                activeField.editorView &&
+                activeField.editorView.getQuickEditUISettings().padding
+              ) {
+                horizontalPadding = 5;
+              }
+              break;
+
+            case 3:
+              // Position against a highlighted field.
+              highlightedField = Drupal.quickedit.app.model.get(
+                'highlightedField',
+              );
+              of =
+                highlightedField &&
+                highlightedField.editorView &&
+                highlightedField.editorView.getEditedElement();
+              delay = 250;
+              break;
+
+            default: {
+              const fieldModels = this.model.get('fields').models;
+              let topMostPosition = 1000000;
+              let topMostField = null;
+              // Position against the topmost field.
+              for (let i = 0; i < fieldModels.length; i++) {
+                const pos = fieldModels[i].get('el').getBoundingClientRect()
+                  .top;
+                if (pos < topMostPosition) {
+                  topMostPosition = pos;
+                  topMostField = fieldModels[i];
+                }
+              }
+              of = topMostField.get('el');
+              delay = 50;
+              break;
+            }
           }
+          // Prepare to check the next possible element to position against.
+          check++;
+        } while (!of);
+
+        /**
+         * Refines the positioning algorithm of jquery.ui.position().
+         *
+         * Invoked as the 'using' callback of jquery.ui.position() in
+         * positionToolbar().
+         *
+         * @param {*} view
+         *   The view the positions will be calculated from.
+         * @param {object} suggested
+         *   A hash of top and left values for the position that should be set. It
+         *   can be forwarded to .css() or .animate().
+         * @param {object} info
+         *   The position and dimensions of both the 'my' element and the 'of'
+         *   elements, as well as calculations to their relative position. This
+         *   object contains the following properties:
+         * @param {object} info.element
+         *   A hash that contains information about the HTML element that will be
+         *   positioned. Also known as the 'my' element.
+         * @param {object} info.target
+         *   A hash that contains information about the HTML element that the
+         *   'my' element will be positioned against. Also known as the 'of'
+         *   element.
+         */
+        function refinePosition(view, suggested, info) {
+          // Determine if the pointer should be on the top or bottom.
+          const isBelow = suggested.top > info.target.top;
+          info.element.element.toggleClass(
+            'quickedit-toolbar-pointer-top',
+            isBelow,
+          );
+          // Don't position the toolbar past the first or last editable field if
+          // the entity is the target.
+          if (view.$entity[0] === info.target.element[0]) {
+            // Get the first or last field according to whether the toolbar is
+            // above or below the entity.
+            const $field = view.$entity
+              .find('.quickedit-editable')
+              .eq(isBelow ? -1 : 0);
+            if ($field.length > 0) {
+              suggested.top = isBelow
+                ? $field.offset().top + $field.outerHeight(true)
+                : $field.offset().top - info.element.element.outerHeight(true);
+            }
+          }
+          // Don't let the toolbar go outside the fence.
+          const fenceTop = view.$fence.offset().top;
+          const fenceHeight = view.$fence.height();
+          const toolbarHeight = info.element.element.outerHeight(true);
+          if (suggested.top < fenceTop) {
+            suggested.top = fenceTop;
+          } else if (suggested.top + toolbarHeight > fenceTop + fenceHeight) {
+            suggested.top = fenceTop + fenceHeight - toolbarHeight;
+          }
+          // Position the toolbar.
+          info.element.element.css({
+            left: Math.floor(suggested.left),
+            top: Math.floor(suggested.top),
+          });
         }
-        // Don't let the toolbar go outside the fence.
-        const fenceTop = view.$fence.offset().top;
-        const fenceHeight = view.$fence.height();
-        const toolbarHeight = info.element.element.outerHeight(true);
-        if (suggested.top < fenceTop) {
-          suggested.top = fenceTop;
-        }
-        else if ((suggested.top + toolbarHeight) > (fenceTop + fenceHeight)) {
-          suggested.top = (fenceTop + fenceHeight) - toolbarHeight;
+
+        /**
+         * Calls the jquery.ui.position() method on the $el of this view.
+         */
+        function positionToolbar() {
+          that.$el
+            .position({
+              my: `${edge} bottom`,
+              // Move the toolbar 1px towards the start edge of the 'of' element,
+              // plus any horizontal padding that may have been added to the
+              // element that is being added, to prevent unwanted horizontal
+              // movement.
+              at: `${edge}+${1 + horizontalPadding} top`,
+              of,
+              collision: 'flipfit',
+              using: refinePosition.bind(null, that),
+              within: that.$fence,
+            })
+            // Resize the toolbar to match the dimensions of the field, up to a
+            // maximum width that is equal to 90% of the field's width.
+            .css({
+              'max-width':
+                document.documentElement.clientWidth < 450
+                  ? document.documentElement.clientWidth
+                  : 450,
+              // Set a minimum width of 240px for the entity toolbar, or the width
+              // of the client if it is less than 240px, so that the toolbar
+              // never folds up into a squashed and jumbled mess.
+              'min-width':
+                document.documentElement.clientWidth < 240
+                  ? document.documentElement.clientWidth
+                  : 240,
+              width: '100%',
+            });
         }
-        // Position the toolbar.
-        info.element.element.css({
-          left: Math.floor(suggested.left),
-          top: Math.floor(suggested.top),
-        });
-      }
+
+        // Uses the jQuery.ui.position() method. Use a timeout to move the toolbar
+        // only after the user has focused on an editable for 250ms. This prevents
+        // the toolbar from jumping around the screen.
+        this.timer = setTimeout(() => {
+          // Render the position in the next execution cycle, so that animations
+          // on the field have time to process. This is not strictly speaking, a
+          // guarantee that all animations will be finished, but it's a simple
+          // way to get better positioning without too much additional code.
+          _.defer(positionToolbar);
+        }, delay);
+      },
 
       /**
-       * Calls the jquery.ui.position() method on the $el of this view.
+       * Set the model state to 'saving' when the save button is clicked.
+       *
+       * @param {jQuery.Event} event
+       *   The click event.
        */
-      function positionToolbar() {
-        that.$el
-          .position({
-            my: `${edge} bottom`,
-            // Move the toolbar 1px towards the start edge of the 'of' element,
-            // plus any horizontal padding that may have been added to the
-            // element that is being added, to prevent unwanted horizontal
-            // movement.
-            at: `${edge}+${1 + horizontalPadding} top`,
-            of,
-            collision: 'flipfit',
-            using: refinePosition.bind(null, that),
-            within: that.$fence,
-          })
-          // Resize the toolbar to match the dimensions of the field, up to a
-          // maximum width that is equal to 90% of the field's width.
-          .css({
-            'max-width': (document.documentElement.clientWidth < 450) ? document.documentElement.clientWidth : 450,
-            // Set a minimum width of 240px for the entity toolbar, or the width
-            // of the client if it is less than 240px, so that the toolbar
-            // never folds up into a squashed and jumbled mess.
-            'min-width': (document.documentElement.clientWidth < 240) ? document.documentElement.clientWidth : 240,
-            width: '100%',
-          });
-      }
-
-      // Uses the jQuery.ui.position() method. Use a timeout to move the toolbar
-      // only after the user has focused on an editable for 250ms. This prevents
-      // the toolbar from jumping around the screen.
-      this.timer = setTimeout(() => {
-        // Render the position in the next execution cycle, so that animations
-        // on the field have time to process. This is not strictly speaking, a
-        // guarantee that all animations will be finished, but it's a simple
-        // way to get better positioning without too much additional code.
-        _.defer(positionToolbar);
-      }, delay);
-    },
+      onClickSave(event) {
+        event.stopPropagation();
+        event.preventDefault();
+        // Save the model.
+        this.model.set('state', 'committing');
+      },
 
-    /**
-     * Set the model state to 'saving' when the save button is clicked.
-     *
-     * @param {jQuery.Event} event
-     *   The click event.
-     */
-    onClickSave(event) {
-      event.stopPropagation();
-      event.preventDefault();
-      // Save the model.
-      this.model.set('state', 'committing');
-    },
-
-    /**
-     * Sets the model state to candidate when the cancel button is clicked.
-     *
-     * @param {jQuery.Event} event
-     *   The click event.
-     */
-    onClickCancel(event) {
-      event.preventDefault();
-      this.model.set('state', 'deactivating');
-    },
+      /**
+       * Sets the model state to candidate when the cancel button is clicked.
+       *
+       * @param {jQuery.Event} event
+       *   The click event.
+       */
+      onClickCancel(event) {
+        event.preventDefault();
+        this.model.set('state', 'deactivating');
+      },
 
-    /**
-     * Clears the timeout that will eventually reposition the entity toolbar.
-     *
-     * Without this, it may reposition itself, away from the user's cursor!
-     *
-     * @param {jQuery.Event} event
-     *   The mouse event.
-     */
-    onMouseenter(event) {
-      clearTimeout(this.timer);
-    },
+      /**
+       * Clears the timeout that will eventually reposition the entity toolbar.
+       *
+       * Without this, it may reposition itself, away from the user's cursor!
+       *
+       * @param {jQuery.Event} event
+       *   The mouse event.
+       */
+      onMouseenter(event) {
+        clearTimeout(this.timer);
+      },
 
-    /**
-     * Builds the entity toolbar HTML; attaches to DOM; sets starting position.
-     *
-     * @return {jQuery}
-     *   The toolbar element.
-     */
-    buildToolbarEl() {
-      const $toolbar = $(Drupal.theme('quickeditEntityToolbar', {
-        id: 'quickedit-entity-toolbar',
-      }));
-
-      $toolbar
-        .find('.quickedit-toolbar-entity')
-        // Append the "ops" toolgroup into the toolbar.
-        .prepend(Drupal.theme('quickeditToolgroup', {
-          classes: ['ops'],
-          buttons: [
-            {
-              label: Drupal.t('Save'),
-              type: 'submit',
-              classes: 'action-save quickedit-button icon',
-              attributes: {
-                'aria-hidden': true,
-              },
-            },
-            {
-              label: Drupal.t('Close'),
-              classes: 'action-cancel quickedit-button icon icon-close icon-only',
-            },
-          ],
-        }));
-
-      // Give the toolbar a sensible starting position so that it doesn't
-      // animate on to the screen from a far off corner.
-      $toolbar
-        .css({
+      /**
+       * Builds the entity toolbar HTML; attaches to DOM; sets starting position.
+       *
+       * @return {jQuery}
+       *   The toolbar element.
+       */
+      buildToolbarEl() {
+        const $toolbar = $(
+          Drupal.theme('quickeditEntityToolbar', {
+            id: 'quickedit-entity-toolbar',
+          }),
+        );
+
+        $toolbar
+          .find('.quickedit-toolbar-entity')
+          // Append the "ops" toolgroup into the toolbar.
+          .prepend(
+            Drupal.theme('quickeditToolgroup', {
+              classes: ['ops'],
+              buttons: [
+                {
+                  label: Drupal.t('Save'),
+                  type: 'submit',
+                  classes: 'action-save quickedit-button icon',
+                  attributes: {
+                    'aria-hidden': true,
+                  },
+                },
+                {
+                  label: Drupal.t('Close'),
+                  classes:
+                    'action-cancel quickedit-button icon icon-close icon-only',
+                },
+              ],
+            }),
+          );
+
+        // Give the toolbar a sensible starting position so that it doesn't
+        // animate on to the screen from a far off corner.
+        $toolbar.css({
           left: this.$entity.offset().left,
           top: this.$entity.offset().top,
         });
 
-      return $toolbar;
-    },
+        return $toolbar;
+      },
 
-    /**
-     * Returns the DOM element that fields will attach their toolbars to.
-     *
-     * @return {jQuery}
-     *   The DOM element that fields will attach their toolbars to.
-     */
-    getToolbarRoot() {
-      return this._fieldToolbarRoot;
-    },
+      /**
+       * Returns the DOM element that fields will attach their toolbars to.
+       *
+       * @return {jQuery}
+       *   The DOM element that fields will attach their toolbars to.
+       */
+      getToolbarRoot() {
+        return this._fieldToolbarRoot;
+      },
 
-    /**
-     * Generates a state-dependent label for the entity toolbar.
-     */
-    label() {
-      // The entity label.
-      let label = '';
-      const entityLabel = this.model.get('label');
-
-      // Label of an active field, if it exists.
-      const activeField = Drupal.quickedit.app.model.get('activeField');
-      const activeFieldLabel = activeField && activeField.get('metadata').label;
-      // Label of a highlighted field, if it exists.
-      const highlightedField = Drupal.quickedit.app.model.get('highlightedField');
-      const highlightedFieldLabel = highlightedField && highlightedField.get('metadata').label;
-      // The label is constructed in a priority order.
-      if (activeFieldLabel) {
-        label = Drupal.theme('quickeditEntityToolbarLabel', {
-          entityLabel,
-          fieldLabel: activeFieldLabel,
-        });
-      }
-      else if (highlightedFieldLabel) {
-        label = Drupal.theme('quickeditEntityToolbarLabel', {
-          entityLabel,
-          fieldLabel: highlightedFieldLabel,
-        });
-      }
-      else {
-        // @todo Add XSS regression test coverage in https://www.drupal.org/node/2547437
-        label = Drupal.checkPlain(entityLabel);
-      }
-
-      this.$el
-        .find('.quickedit-toolbar-label')
-        .html(label);
-    },
+      /**
+       * Generates a state-dependent label for the entity toolbar.
+       */
+      label() {
+        // The entity label.
+        let label = '';
+        const entityLabel = this.model.get('label');
+
+        // Label of an active field, if it exists.
+        const activeField = Drupal.quickedit.app.model.get('activeField');
+        const activeFieldLabel =
+          activeField && activeField.get('metadata').label;
+        // Label of a highlighted field, if it exists.
+        const highlightedField = Drupal.quickedit.app.model.get(
+          'highlightedField',
+        );
+        const highlightedFieldLabel =
+          highlightedField && highlightedField.get('metadata').label;
+        // The label is constructed in a priority order.
+        if (activeFieldLabel) {
+          label = Drupal.theme('quickeditEntityToolbarLabel', {
+            entityLabel,
+            fieldLabel: activeFieldLabel,
+          });
+        } else if (highlightedFieldLabel) {
+          label = Drupal.theme('quickeditEntityToolbarLabel', {
+            entityLabel,
+            fieldLabel: highlightedFieldLabel,
+          });
+        } else {
+          // @todo Add XSS regression test coverage in https://www.drupal.org/node/2547437
+          label = Drupal.checkPlain(entityLabel);
+        }
 
-    /**
-     * Adds classes to a toolgroup.
-     *
-     * @param {string} toolgroup
-     *   A toolgroup name.
-     * @param {string} classes
-     *   A string of space-delimited class names that will be applied to the
-     *   wrapping element of the toolbar group.
-     */
-    addClass(toolgroup, classes) {
-      this._find(toolgroup).addClass(classes);
-    },
+        this.$el.find('.quickedit-toolbar-label').html(label);
+      },
 
-    /**
-     * Removes classes from a toolgroup.
-     *
-     * @param {string} toolgroup
-     *   A toolgroup name.
-     * @param {string} classes
-     *   A string of space-delimited class names that will be removed from the
-     *   wrapping element of the toolbar group.
-     */
-    removeClass(toolgroup, classes) {
-      this._find(toolgroup).removeClass(classes);
-    },
+      /**
+       * Adds classes to a toolgroup.
+       *
+       * @param {string} toolgroup
+       *   A toolgroup name.
+       * @param {string} classes
+       *   A string of space-delimited class names that will be applied to the
+       *   wrapping element of the toolbar group.
+       */
+      addClass(toolgroup, classes) {
+        this._find(toolgroup).addClass(classes);
+      },
 
-    /**
-     * Finds a toolgroup.
-     *
-     * @param {string} toolgroup
-     *   A toolgroup name.
-     *
-     * @return {jQuery}
-     *   The toolgroup DOM element.
-     */
-    _find(toolgroup) {
-      return this.$el.find(`.quickedit-toolbar .quickedit-toolgroup.${toolgroup}`);
-    },
+      /**
+       * Removes classes from a toolgroup.
+       *
+       * @param {string} toolgroup
+       *   A toolgroup name.
+       * @param {string} classes
+       *   A string of space-delimited class names that will be removed from the
+       *   wrapping element of the toolbar group.
+       */
+      removeClass(toolgroup, classes) {
+        this._find(toolgroup).removeClass(classes);
+      },
 
-    /**
-     * Shows a toolgroup.
-     *
-     * @param {string} toolgroup
-     *   A toolgroup name.
-     */
-    show(toolgroup) {
-      this.$el.removeClass('quickedit-animate-invisible');
-    },
+      /**
+       * Finds a toolgroup.
+       *
+       * @param {string} toolgroup
+       *   A toolgroup name.
+       *
+       * @return {jQuery}
+       *   The toolgroup DOM element.
+       */
+      _find(toolgroup) {
+        return this.$el.find(
+          `.quickedit-toolbar .quickedit-toolgroup.${toolgroup}`,
+        );
+      },
 
-  });
-}(jQuery, _, Backbone, Drupal, Drupal.debounce));
+      /**
+       * Shows a toolgroup.
+       *
+       * @param {string} toolgroup
+       *   A toolgroup name.
+       */
+      show(toolgroup) {
+        this.$el.removeClass('quickedit-animate-invisible');
+      },
+    },
+  );
+})(jQuery, _, Backbone, Drupal, Drupal.debounce);