editor_advanced_image-8.x-2.x-dev/js/ckeditor5_plugins/editorAdvancedImage/src/EditorAdvancedImageUI.js

js/ckeditor5_plugins/editorAdvancedImage/src/EditorAdvancedImageUI.js
/**
 * @module editor_advanced_image/editorAdvancedImage/EditorAdvancedImageUI
 */

import { Plugin } from "ckeditor5/src/core";
import {
  ButtonView,
  ContextualBalloon,
  clickOutsideHandler,
} from "ckeditor5/src/ui";

import { getBalloonPositionData } from "@ckeditor/ckeditor5-image/src/image/ui/utils";

import EditorAdvancedImageFormView from "./ui/EditorAdvancedImageFormView";

import { IconThreeVerticalDots } from "ckeditor5/src/icons";

/**
 * The Editor Advanced Image UI plugin.
 *
 * The plugin uses the contextual balloon.
 *
 * @see module:ui/panel/balloon/contextualballoon~ContextualBalloon
 *
 * @extends module:core/plugin~Plugin
 *
 * @internal
 */
export default class EditorAdvancedImageUI extends Plugin {
  /**
   * @inheritdoc
   */
  static get requires() {
    return [ContextualBalloon];
  }

  /**
   * @inheritdoc
   */
  init() {
    const options = this.editor.config.get("editorAdvancedImageOptions");

    // Prevent creation of Editor Advanced Button & Form when the option "Disable Balloon" is enabled.
    if (
      options !== undefined &&
      options.disable_balloon !== undefined &&
      options.disable_balloon
    ) {
      return;
    }

    this._createButton();
    this._createForm();
  }

  /**
   * @inheritdoc
   */
  destroy() {
    super.destroy();

    // Destroy created UI components as they are not automatically destroyed
    // @see https://github.com/ckeditor/ckeditor5/issues/1341
    this._form.destroy();
  }

  /**
   * Creates a button showing the balloon panel for changing the image advanced
   * attributes alternative and registers it in the editor component factory.
   *
   * @see module:ui/componentfactory~ComponentFactory
   *
   * @private
   */
  _createButton() {
    const editor = this.editor;

    // The name on the component factory must be the same as in editor_advanced_image.ckeditor5.yml.
    editor.ui.componentFactory.add("editorAdvancedImageButton", (locale) => {
      const command = editor.commands.get("EditorAdvancedImageCmd");
      const view = new ButtonView(locale);

      view.set({
        label: Drupal.t("Editor Advanced Image"),
        icon: IconThreeVerticalDots,
        tooltip: true,
      });

      // Enable the UI if and only if the command is enabled.
      view.bind("isVisible").to(command, "isEnabled");

      this.listenTo(view, "execute", () => {
        this._showForm();
      });

      return view;
    });
  }

  /**
   * Creates the {@link module:editor_advanced_image/editorAdvancedImage/ui/EditorAdvancedImageFormView~EditorAdvancedImageFormView}
   * form.
   *
   * @private
   */
  _createForm() {
    const editor = this.editor;

    // Get the Drupal Configurations.
    // @see \Drupal\editor_advanced_image\Plugin\CKEditor5Plugin\EditorAdvancedImage::getDynamicPluginConfig
    const options = editor.config.get(`editorAdvancedImageOptions`);

    /**
     * The contextual balloon plugin instance.
     */
    this._balloon = this.editor.plugins.get("ContextualBalloon");

    /**
     * A form containing class, title & id inputs, used to change data-attributes values.
     */
    this._form = new EditorAdvancedImageFormView(editor.locale, options);

    // Render the form so its #element is available for clickOutsideHandler.
    this._form.render();

    // When the form is submitted, close the form instead of POST the whole page.
    this.listenTo(this._form, "save", () => {
      // Execute the Command.
      editor.execute("EditorAdvancedImageCmd", {
        title: options.allowedAttributes.includes("title")
          ? this._form.titleAttrInput.fieldView.element.value
          : false,
        class: options.allowedAttributes.includes("class")
          ? this._form.classAttrInput.fieldView.element.value
          : false,
        id: options.allowedAttributes.includes("id")
          ? this._form.idAttrInput.fieldView.element.value
          : false,
      });

      this._hideForm(true);
    });

    // Close the form when clicking on the cancel button.
    this.listenTo(this._form, "cancel", () => {
      this._hideForm(true);
    });

    // Close the form on Esc key press.
    this._form.keystrokes.set("Esc", (data, cancel) => {
      this._hideForm(true);
      cancel();
    });

    // Close on click outside of balloon panel element.
    clickOutsideHandler({
      emitter: this._form,
      activator: () => this._isVisible,
      contextElements: [this._balloon.view.element],
      callback: () => this._hideForm(),
    });
  }

  /**
   * Shows the form in a balloon.
   */
  _showForm() {
    if (this._isVisible) {
      return;
    }

    const editor = this.editor;
    const command = editor.commands.get("EditorAdvancedImageCmd");

    // Get the Drupal Configurations.
    // @see \Drupal\editor_advanced_image\Plugin\CKEditor5Plugin\EditorAdvancedImage::getDynamicPluginConfig
    const options = editor.config.get(`editorAdvancedImageOptions`);

    if (!this._isInBalloon) {
      // Place the form into the Balloon.
      this._balloon.add({
        view: this._form,
        // Be sure to keep the Balloon at the same centered position.
        position: getBalloonPositionData(editor),
      });
    }

    // Make sure that each time the panel shows up, the field remains in sync with the value of
    // the command. If the user typed in the input, then canceled the balloon (`labeledInput#value`
    // stays unaltered) and re-opened it without changing the value of the command, they would see the
    // old value instead of the actual value of the command.
    // https://github.com/ckeditor/ckeditor5-image/issues/114
    if (options.allowedAttributes.includes("title")) {
      this._form.titleAttrInput.fieldView.element.value =
        command.attributes.title || "";
      this._form.titleAttrInput.fieldView.value =
        this._form.titleAttrInput.fieldView.element.value;
    }

    if (options.allowedAttributes.includes("class")) {
      this._form.classAttrInput.fieldView.element.value =
        command.attributes.class || "";
      this._form.classAttrInput.fieldView.value =
        this._form.classAttrInput.fieldView.element.value;
    }

    if (options.allowedAttributes.includes("id")) {
      this._form.idAttrInput.fieldView.element.value =
        command.attributes.id || "";
      this._form.idAttrInput.fieldView.value =
        this._form.idAttrInput.fieldView.element.value;
    }
  }

  /**
   * Removes the {@link #_form} from the {@link #_balloon}.
   *
   * @param {Boolean} [focusEditable=false] Controls whether the editing view is focused afterwards.
   * @private
   */
  _hideForm(focusEditable) {
    if (!this._isInBalloon) {
      return;
    }

    this._balloon.remove(this._form);

    if (focusEditable) {
      this.editor.editing.view.focus();
    }
  }

  /**
   * Returns `true` when the form is the visible view in the balloon.
   *
   * @type {Boolean}
   */
  get _isVisible() {
    return this._balloon.visibleView === this._form;
  }

  /**
   * Returns `true` when the form is in the balloon.
   *
   * @type {Boolean}
   */
  get _isInBalloon() {
    return this._balloon.hasView(this._form);
  }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc