web-dev-qa-db-fra.com

Intégration de l'éditeur de tinymce en ligne dans un composant pour un bloc gutenberg

Je suis nouveau pour empiler l'échange. J'espère que ma question n'est pas trop longue.

Je souhaite intégrer un éditeur de tinymce en ligne dans un composant et l'utiliser dans un bloc gutenberg. Mais mes éditeurs entrent en conflit avec Gutenberg. (première capture d'écran)

L'élément editor se trouve dans une vue de réseau principal. Je ne peux pas utiliser le composant d’éditeur RichText dans mon cas.

Contexte:

Je développe un plug-in pour insérer des cartes de dépliants dans un message https://github.com/jhotadhari/geo-masala

Le plugin a un bloc Gutenberg pour insérer et contrôler une carte et son apparence/popups/contrôles/marqueurs….

Les entités cartographiques (marqueurs/lignes/polygones) sont enregistrées sous un type personnalisé: geom_feature. Chaque geom_feature a une méta pour geoJSON, l'apparence ... Le type personnalisé est enregistré sans interface utilisateur. Toutes les actions crud pour geom_feature (s) sont effectuées dans un bloc gutenberg (par exemple, dessiner un marqueur crée un nouveau geom_feature)

À l'intérieur du bloc, un composant convertit une carte de dépliants en un élément ref. Le composant utilise backbone pour extraire la ou les geom_feature (s) en tant que collection. Lorsque l'utilisateur clique sur un objet carte (Leaflet.layer), une barre d'outils s'ouvre avec différentes options d'édition. Le contenu de la popup peut être édité dans une popup (en utilisant un formulaire avec un champ wysiwyg personnalisé). Le contenu popup est le post-contenu de geom_feature.

Le champ wysiwyg personnalisé utilise un éditeur intégré tinymce. Tout (par exemple, mettre à jour le nouveau contenu dans la base de données) fonctionne bien, mais l'interface utilisateur de cet éditeur est défectueuse. La barre d'outils de l'éditeur et les widgets ne sont pas en place.

Je peux initier l'éditeur avec un fixed_toolbar_container. Comme ça:

initMceEditor: function(){
    let self = this;

    if ( this.mceEditor )
        return this;

    // setup editor element
    this.getMceElement().attr( 'id', this.cid );
    // setup toolbar element
    this.setupToolbar();

    let settings = _.extend( {}, wp.editor.getDefaultSettings().tinymce, {
        selector: this.cid,
        inline: true,
        toolbar1: [
            'formatselect fontsizeselect bold italic underline',
            'bullist numlist',
            'alignleft aligncenter alignright',
            'link pastetext',
        ].join(' | '),
        toolbar: true,
        fixed_toolbar_container: '#geom-inline-editor-toolbar-' + this.cid,
        content_css: geomData.pluginDirUrl + '/css/tinymce_content.min.css',
        setup: function (editor) {
            // editor events
            // ... some lines skipped
        },
    });

    // init mceEditor
    this.mceEditor = tinymce.createEditor( this.cid, settings );

    // render mceEditor
    this.mceEditor.render();

    return this;
},

Cela fonctionne mais l’apparence de la barre d’outils n’est pas celle attendue. Et les panneaux et info-bulles de mce sont affichés à la fin du document. Voir la première capture d'écran.

enter image description here

Je peux appliquer un style pour résoudre ce problème:

.geom-toolbar {
    display: table;
    width: 100%;
    position: relative;
    .geom-inline-editor-toolbar {
        width: 100%;
        .mce-flow-layout-item {
            float: left;
        }
        .mce-widget.mce-btn {
            float: left;
            button {
                padding: 0;
            }
        }
    }
}

// stupid fix, dont do that!
.mce-widget.mce-tooltip[role="presentation"] {
    position: absolute;
    background-color: #111;
    padding: 0.5em;
}
.mce-container.mce-panel.mce-floatpanel {
    position: absolute;
    max-width: 200px;
    width: 200px !important;
}

L'éditeur ressemble à ceci alors:

enter image description here

Ce n’est pas une bonne solution du tout. Et ce sera en conflit quelque part.

Retour à la question

Est-ce que quelqu'un connaît un moyen d'inclure un éditeur de tinymce en ligne qui ne soit pas en conflit avec gutenberg?

Dois-je charger des styles par défaut pour mon éditeur tinymce qui ne sont pas chargés par gutenberg? Et comment limiter leur portée à mes composants ou peut me conseiller de façon.

Je ne cherche pas de solution utilisant le composant RichText de gutenberg.

Je vous remercie

3
jhotadhari

Le composant FreeformEdit de Gutenbergs (utilisé pour le bloc de l'éditeur classique) montre comment intégrer un éditeur tinyMce.

Recodé mon Backform personnalisé WysiwygControl et a adopté l'intégration tinyMce.

/**
 * External dependencies
 */
import Backform from 'Backform';

/**
 * WordPress dependencies
 */
const { __ } = wp.i18n;
const { F10, ESCAPE, ALT } = wp.utils.keycodes;

/**
 * Wysiwyg Control
 *
 * The tinyMce integration is mostly copied from the gutenberg/core-blocks/freeform component (classic editor)
 *
 */
const WysiwygControl = Backform.Control.extend({

    defaults: {
        label: '',
        helpMessage: null
    },

    // ./form.js inits the controls with options for layer and model
    initialize( options ) {
        Backform.Control.prototype.initialize.apply(this, arguments);
        this.layer = options.layer;
    },

    template: _.template([
        '<label class="<%=Backform.controlLabelClassName%>"><%=label%></label>',
        '<div class="<%=Backform.controlsClassName%>">',
        '  <div class="geom-inline-editor" <%=disabled ? "disabled" : ""%> <%=required ? "required" : ""%> >',
        '    <%= value %>',
        '  </div>',
        '  <% if (helpMessage && helpMessage.length) { %>',
        '    <span class="<%=Backform.helpMessageClassName%>"><%=helpMessage%></span>',
        '  <% } %>',
        '</div>'
    ].join('\n')),

    events: _.extend({}, Backform.Control.prototype.events, {
        'click': 'onClick',
        'dblclick': 'onClick',
    }),

    onClick(e){
        if ( e ) e.preventDefault();
        const { baseURL, suffix } = window.wpEditorL10n.tinymce;

        if ( this.editor ) return this;

        window.tinymce.EditorManager.overrideDefaults( {
            base_url: baseURL,
            suffix,
        } );

        if ( document.readyState === 'complete' ) {
            this.initEditor();
        } else {
            window.addEventListener( 'DOMContentLoaded', this.initEditor );
        }
    },

    setupToolbar(){
        if ( ! this.$toolbar ){
            // create toolbar element
            this.$toolbar = $('<div>', {
                id: 'geom-inline-editor-toolbar-' + this.cid,
                class: 'geom-inline-editor-toolbar freeform-toolbar',
                ['data-placeholder']: __( 'Classic' ),
            } );
            // append toolbar to container
            this.$el.closest('div[data-type="geom/map"]').find('.geom-toolbar').append(this.$toolbar);
            // animate toolbar
            let autoHeight = this.$toolbar.css('height', 'auto').height();
            this.$toolbar.height(0).animate({height: autoHeight}, 500, () => this.$toolbar.css('height', 'auto') );
            // toolbar events
            this.$toolbar.on('keydown', this.onToolbarKeyDown.bind(this) );
        }
    },

    getEditorElement(){
        return this.$el.find('.geom-inline-editor');
    },

    initEditor() {
        const { settings } = window.wpEditorL10n.tinymce;
        if ( this.editor ) return;
        // setup editor element
        this.getEditorElement().attr( 'id', 'editor-' + this.cid );
        // setup toolbar element
        this.setupToolbar();
        // initialize
        wp.oldEditor.initialize( 'editor-' + this.cid, {
            tinymce: {
            ...settings,
            inline: true,
            content_css: geomData.pluginDirUrl + '/css/geom_block_map_editor_tinymce_content.min.css',
            fixed_toolbar_container: '#geom-inline-editor-toolbar-' + this.cid,
            setup: this.onSetup.bind(this),
        },
        } );
    },

    onSetup( editor ) {
        const self = this;
        const content  = this.getEditorElement().html();
        this.editor = editor;

        editor.addButton( 'kitchensink', {
            tooltip: __( 'More' ),
            icon: 'dashicon dashicons-editor-kitchensink',
            onClick: function() {
                const button = this;
                const active = ! button.active();
                button.active( active );
                editor.dom.toggleClass( self.$toolbar, 'has-advanced-toolbar', active );
            },
        } );

        if ( content ) {
            editor.on( 'loadContent', () => editor.setContent( content ) );
        }

        editor.on( 'init', () => {
            // Create the toolbar by refocussing the editor.
            editor.getBody().blur();
            editor.focus();
        } );

        // // ??? well that doesn't work... will fix that in future
        // editor.on('keydown', ( event ) => {
        //  const { altKey } = event;
        //  // Prevent Mousetrap from kicking in: TinyMCE already uses its own 'alt+f10' shortcut to focus its toolbar.
        //  // if ( altKey && event.keyCode === F10 ) {
        //  if ( event.keyCode === F10 ) {
        //      event.stopPropagation();
        //  }
        // });

        editor.on( 'blur', (event) => {
            this.setModelVal(event);
            return false;
        } );

        editor.on('KeyUp Change Paste input touchend', ( event ) => {
            // close editor if esc pressed
            if ( event.keyCode === ESCAPE ) {
                this.close(event);
            }
        });

        editor.on('focusout', ( event ) => {
            if ( undefined !== $( event.explicitOriginalTarget ) ){

                if ( $( event.explicitOriginalTarget ).attr('id') ){
                    if ( $( event.explicitOriginalTarget ).attr('id').startsWith('mce') ){
                        return;
                    }
                }

                if ( event.explicitOriginalTarget.tagName === 'BUTTON' ){
                    this.setModelVal(event);
                    this.close(event);
                    $( event.explicitOriginalTarget ).trigger('click');
                    return;
                }
            }
            this.setModelVal(event);
            this.close(event);
        });
    },

    focus() {
        if ( this.editor ) {
            this.editor.focus();
        }
    },

    onToolbarKeyDown( event ) {
        // Prevent WritingFlow from kicking in and allow arrows navigation on the toolbar.
        event.stopPropagation();
        // Prevent Mousetrap from moving focus to the top toolbar when pressing 'alt+f10' on this block toolbar.
        event.nativeEvent.stopImmediatePropagation();
    },

    close(e){
        if ( e ) e.preventDefault();
        this.removeEditor();
    },

    setModelVal(e){
        if ( e ) e.preventDefault();
        const model = this.model;
        const val = this.editor.getContent();
        const oldVal = model.get( this.field.get( 'name' ) ) || model.get( this.field.get( 'name' ) ).rendered;
        const newVal = this.formatter.toRaw( val ) || this.formatter.toRaw( val ).rendered;
        if ( ! _.isUndefined( newVal ) ) this.model.set( 'content', newVal );
    },

    getValueFromDOM() {
        return this.formatter.toRaw( this.getEditorElement().html(), this.model );
    },

    removeEditor() {
        if ( this.editor ){
            window.addEventListener( 'DOMContentLoaded', this.initEditor );
            wp.oldEditor.remove( 'editor-' + this.cid );
            this.removeToolbar();
            delete this.editor;
            this.getEditorElement().attr( 'id', null);
        }
    },

    removeToolbar(){
        if ( this.$toolbar ){
            this.$toolbar.animate({height: 0}, 500, () => {
                this.$toolbar.remove();
                delete this.$toolbar;
            });
        }
    },

});

export default WysiwygControl;

Nouvelle version du plugin 0.0.7

... eh bien, le meilleur moyen serait de tout construire dans React. Mais c'est une autre histoire

Mise à jour 10 juillet 2018: Mise à jour des liens du plug-in vers la version 0.0.6 (compatible avec gb 3.2.0 et wp 4.9.7) Mise à jour du 12 juillet 2018: Mise à jour des liens du plugin vers la version 0.0.7 (compatible avec gb 3.2.0 et wp 4.9.7)

1
jhotadhari