在古登堡块的组件中集成内联时态编辑器

时间:2018-07-02 作者:jhotadhari

我不熟悉stack exchange。我希望我的问题不要太长。

我想在组件中集成内联tinymce编辑器,并在gutenberg块中使用它。但我的编辑器ui与gutenberg冲突。(第一个屏幕截图)

编辑器元素位于主干视图内。我不能在我的案例中使用RichText编辑器组件。

背景:

我正在开发一个插件,可以在帖子中插入传单地图https://github.com/jhotadhari/geo-masala

该插件有一个古腾堡块,用于插入和控制地图及其外观/弹出窗口/控件/标记。

地图要素(标记/线/多边形)另存为自定义贴子类型:geom\\u要素。每个geom\\u功能都有geoJSON的meta、外观。。。自定义帖子类型在没有ui的情况下注册。geom\\u特征的所有crud操作都在gutenberg块内完成(例如,绘制标记创建新的geom\\u特征)

在块内部,一个组件将传单贴图渲染为ref元素。该组件使用主干来获取geom\\u要素作为集合。单击地图功能(传单图层)时,将打开一个带有不同编辑选项的工具栏。可以在弹出窗口中编辑弹出窗口内容(使用带有自定义wysiwyg字段的反向表单)。弹出内容是geom\\u功能的帖子内容。

自定义所见即所得字段使用tinymce内联编辑器。所有这些(如将新内容更新到数据库)都可以正常工作,但编辑器的ui会中断。编辑器工具栏和小部件未就位。

我可以使用fixed\\u toolbar\\u容器初始化编辑器。像这样:

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;
},
这可以工作,但工具栏的外观与预期不同。mce面板和工具提示显示在文档末尾。请参见第一个屏幕截图。

enter image description here

我可以应用一些样式来修复此问题:

.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;
}
编辑器如下所示:

enter image description here

这根本不是一个好的解决方案。它会在某个地方发生冲突。

回到问题上来,是否有人知道一种方法,可以包含一个与gutenberg不冲突的内联tinymce编辑器?

我是否必须为tinymce编辑器加载一些gutenberg没有加载的默认样式?以及如何将它们的范围限制在我的组件上,或者可以给我提供建议。

我不会搜索使用gutenbergs RichText组件的解决方案。

非常感谢。

1 个回复
SO网友:jhotadhari

Gutenbergs FreeformEdit Component (用于经典编辑器块)演示如何集成tinyMce编辑器。

重新编码我的自定义表单WysiwygControl 并采用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;

New Plugin Version 0.0.7

... 最好的办法是把一切都建立在React中。但那是另一个故事

Update 10 July 2018: 更新了0.0.6版的插件链接(与gb 3.2.0和wp 4.9.7兼容)Update 12 July 2018: 更新了0.0.7版本的插件链接(与gb 3.2.0和wp 4.9.7兼容)

结束

相关推荐

如何在TinyMCE中使用自定义文本样式编辑实际的段落下拉菜单

我想给后端用户只有4种文本样式可供选择。标题、副标题、段落和我们称之为.statement.搜索诸如“TinyMCE中的自定义样式”之类的术语总是以wordpress本身的这篇文章结尾。https://codex.wordpress.org/TinyMCE_Custom_Styles不幸的是,我不想访问其他下拉列表。我需要去掉当前下拉列表中的内容,并用我自己的样式填充它。在第一步中,我实际上并不关心它们在下拉菜单和可视化编辑器中的外观。这里的关键是去掉不必要的造型选项;选项设计(&P);前端将不支持。(尽