Skip to content

Latest commit

 

History

History
131 lines (107 loc) · 3.03 KB

ckeditor.md

File metadata and controls

131 lines (107 loc) · 3.03 KB

CKEditor

If you use CKEditor for the WYSIWYG fields of your blocks, you will need to implement a decidated Stimulus controller to manage CKEditor instances as you add or re-render blocks by dragging them.

Here is an example of how you might do that:

import { Controller } from '@hotwired/stimulus';
import { useIntersection } from 'stimulus-use';

/* stimulusFetch: 'lazy' */
export default class extends Controller {
  static values = {
    formJs: String,
    ckeditorConfig: String,
  };

  isDragging = false;
  isDraggable = false;
  ckConf;

  connect() {
    useIntersection(this);

    this._loadConf();
  }

  appear() {
    this._instanciate();
  }

  destroy() {
    this.isDraggable = true;
    this.isDragging = true;

    if ('undefined' !== typeof CKEDITOR) {
      if (CKEDITOR.instances[this.element.id]) {
        CKEDITOR.instances[this.element.id].destroy();
      }
    }
  }

  restore() {
    this.isDragging = false;

    if ('undefined' !== typeof CKEDITOR && this.ckeditorConfigValue) {
      this._replaceEditor();
    }
  }

  _instanciate() {
    // Si CkEditor chargé
    if (window.CKEDITOR) {
      this._initCK();
    } else {
      // sinon on charge tous les scripts
      this._initScript();
    }
  }

  _initScript() {
    const script = document.createElement('script');
    script.src = this.formJsValue;
    document.head.appendChild(script);

    this._whenDefined(window, 'CKEDITOR', () => {
      this._initCK(window.CKEDITOR);
    });
  }

  _whenDefined(context, variableName, ck) {
    // eslint-disable-next-line prefer-rest-params
    const interval = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 150;
    const checkVariable = () => {
      if (context[variableName]) {
        ck();
      } else {
        setTimeout(checkVariable, interval);
      }
    };

    setTimeout(checkVariable, 0);
  }

  _initCK() {
    if ((this.isDraggable && !this.isDragging && !(CKEDITOR.instances[this.element.id]))
      || (!this.isDraggable)) {
      this._replaceEditor();
    }
  }

  _loadConf() {
    try {
      this.ckConf = JSON.parse(this.ckeditorConfigValue);

      if (!this.ckConf?.on?.change) {
        this.ckConf = {
          ...this.ckConf,
          on: {
            // eslint-disable-next-line object-shorthand
            change: function () {
              this.updateElement();
            },
          },
        };
      }
    } catch (err) {
      console.error(`CKEditor configuration could not be parsed: ${err}`);
    }
  }

  _replaceEditor() {
    CKEDITOR.replace(this.element.id, this.ckConf);
  }
}

You also need to bind this controller to the CKEditor Twig widget.

{% block ckeditor_widget %}
  <textarea {{ block('widget_attributes') }} {{ stimulus_controller('ckeditor', {
    formJs: ckeditor_js_path(js_path),
    ckeditorConfig: '',
  }) }} data-action="start@window->ckeditor#destroy end@window->ckeditor#restore"
  >{{ value }}</textarea>
{% endblock %}

To load your configuration, you can use the CKEditorConfiguration->getConfig() method and json_encode the result.