insert-8.x-2.x-dev/js/FocusManager.js

js/FocusManager.js
(function(Drupal) {
  'use strict';

  /**
   * The Focus Manager keeps track of the CKEditor instances and text areas on
   * the page, including which of the elements is currently focused and was
   * previously focused to determine the target for an insertion operation.
   */
  class FocusManager {

    /**
     * Finds descending elements of a CKEditor model element according to a
     * predicate function looping through the provided element's descendants.
     * @param {ckeditor.Element} element
     * @param {(child: ckeditor.Element) => boolean} predicate
     * @returns {ckeditor.Element[]}
     */
    static findDescendants(element, predicate) {
      let elements = [];

      if (predicate(element)) {
        elements = [...elements, element];
      } else if (element.getChildren) {
        for (const child of element.getChildren()) {
          const childElements = this.findDescendants(child, predicate);
          if (childElements) {
            elements = [...elements, ...childElements];
          }
        }
      }

      return elements;
    }

    /**
     * Registry of the CKEditor instances tracked by the FocusManager
     * @type {ckeditor.Editor[]}
     */
    #editors;

    /**
     * Registry of the textareas tracked by the FocusManager
     * @type {HTMLTextAreaElement[]}
     */
    #textareas;

    /**
     * The current target for inserting.
     * @type {ckeditor.Editor|HTMLTextAreaElement|undefined}
     */
    #focusTarget;

    /**
     * The previous target used as a fallback when inserting while there is no
     * current target.
     * @type {ckeditor.Editor|HTMLTextAreaElement|undefined}
     */
    #previousFocusTarget;

    /**
     * The default target used when there has been no interaction with any
     * editor or textarea yet.
     * @type {ckeditor.Editor|HTMLTextAreaElement|undefined}
     */
    defaultTarget;

    constructor() {
      this.#editors = [];
      this.#textareas = [];

      this.init();
    }

    init() {
      const firstEditorElement= document.querySelector('.ck-editor__editable');

      this.defaultTarget = firstEditorElement
        ? firstEditorElement.ckeditorInstance
        : document.querySelector('textarea') || undefined;
    }

    /**
     * @returns {ckeditor.Editor[]}
     */
    get editors() {
      return this.#editors;
    }

    /**
     * @returns {HTMLTextAreaElement[]}
     */
    get textareas() {
      return this.#textareas;
    }

    /**
     * @param {ckeditor.Editor} editor
     */
    addEditor(editor) {
      if (!this.#editors.map(editor => editor.id).includes(editor.id)) {
        this.#attachEditorEvents(editor);
        this.#editors.push(editor);
      }
    }

    /**
     * @param {ckeditor.Editor} editor
     */
    #attachEditorEvents(editor) {
      editor.editing.view.document.on('change:isFocused', (event, data, isFocused) => {
        if (isFocused) {
          this.#focusTarget = editor;
        } else {
          this.#previousFocusTarget = editor;

          if (this.#focusTarget && this.#focusTarget.id === editor.id) {
            this.#focusTarget = undefined;
          }
        }
      });
    }

    /**
     * @param {HTMLTextAreaElement} textarea
     */
    addTextarea(textarea) {
      if (!this.#textareas.includes(textarea)) {
        this.#attachTextareaEvents(textarea);
        this.#textareas.push(textarea);
      }
    }

    /**
     * @param {HTMLTextAreaElement} textarea
     */
    #attachTextareaEvents(textarea) {
      textarea.addEventListener('focus', event => {
        this.#focusTarget = event.target;
      });

      textarea.addEventListener('blur', () => {
        this.#previousFocusTarget = textarea;

        if (this.#focusTarget && this.#focusTarget === textarea) {
          this.#focusTarget = undefined;
        }
      });
    }

    /**
     * Returns the best guessed target to insert content into.
     * @returns {ckeditor.Editor|HTMLTextAreaElement|undefined}
     */
    getTarget() {
      if (this.#focusTarget) {
        return this.#focusTarget;
      }

      if (this.#previousFocusTarget) {
        return this.#previousFocusTarget;
      }

      // Only return the default target if it is tracked by the focus manager
      if (this.defaultTarget) {
        if (
          typeof CKEditor5 !== 'undefined'
          && this.defaultTarget instanceof CKEditor5.core.Editor
          && this.#editors.find(
            editor => editor.id === this.defaultTarget.id
          )
        ) {
          return this.defaultTarget;
        }

        if (
          this.#textareas.find(
            textarea => textarea === this.defaultTarget
          )
        ) {
            return this.defaultTarget;
        }
      }

      if (this.#editors.length) {
        return this.#editors[0];
      }

      if (this.#textareas.length) {
        return this.#textareas[0];
      }

      console.warn('Insert: Unable to determine the insertion target');
    }
  }

  Drupal.insert.Manager = FocusManager;

})(Drupal);

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

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