Gutenberg の Format type に複数クラスを指定

WordPress

インラインで文字を修飾するために registerFormatTypeを使用してツールバーにボタンを追加することができます。

@wordpress/rich-text
This module contains helper functions to convert HTML or a DOM tree into a rich text value and back, and to modify the value with functions that are similar to ...

ただ registerFormatType で指定できるクラス名はスペース等で複数指定することはできません。

実際のソースを見るとわかりますが、英数字とハイフン、アンダーバー以外が入っているとはじかれてしまうためです。

WordPress/gutenberg
The Block Editor project for WordPress and beyond. Plugin is available from the official repository. - WordPress/gutenberg

ただ実際はGutenbergの内部でクラス名をスペースで区切って処理したりはしていないため、スペースが入っていても問題なく動く場合があります。

ここでは WordPress v5.1 で問題なく複数のクラスの付け外しを行うことのできるボタンをRichTextのツールバーに追加する非公式な方法を紹介します。

フォーマットの追加

registerFormatType のほとんどは引数のチェックや既に登録されているフォーマットかどうかのチェックであり、実際の登録自体は addFormatTypes の一行だけです。

WordPress/gutenberg
The Block Editor project for WordPress and beyond. Plugin is available from the official repository. - WordPress/gutenberg

したがって直接これを呼び出せば現状のクラス名チェックを飛ばして登録することが可能です。

同じクラスの判定による制限

同じクラス名かどうかの判定は getFormatTypeForClassName で行われます。

WordPress/gutenberg
The Block Editor project for WordPress and beyond. Plugin is available from the official repository. - WordPress/gutenberg

登録しようとしているクラス名の一部又は全部から構成されるクラス名を持つフォーマットが登録されている場合に、この検索で引っかかります。

したがって以下のような二つのフォーマットを登録する場合は 2. のほうを先に登録する必要があります。

  1. className: class1
  2. className: class1 class2

Gutenbergの内部の処理でも getFormatTypeForClassName が使用されているため、この制限を無視して登録した場合はボタンのアクティブ判定などに影響が出てしまいます。

その他のチェック

細かく影響を確認していないため、その他の部分は元のチェックを行うようにします。

最終的なコード例

const {dispatch, select} = wp.data;

function _registerFormatType( name, settings ) {
    settings.name = name;

    if ( typeof settings.name !== 'string' ) {
        window.console.error(
            'Format names must be strings.'
        );
        return;
    }

    if ( ! /^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/.test( settings.name ) ) {
        window.console.error(
            'Format names must contain a namespace prefix, include only lowercase alphanumeric characters or dashes, and start with a letter. Example: my-plugin/my-custom-format'
        );
        return;
    }

    if ( select( 'core/rich-text' ).getFormatType( settings.name ) ) {
        window.console.error(
            'Format "' + settings.name + '" is already registered.'
        );
        return;
    }

    if (
        typeof settings.tagName !== 'string' ||
        settings.tagName === ''
    ) {
        window.console.error(
            'Format tag names must be a string.'
        );
        return;
    }

    if (
        ( typeof settings.className !== 'string' || settings.className === '' ) &&
        settings.className !== null
    ) {
        window.console.error(
            'Format class names must be a string, or null to handle bare elements.'
        );
        return;
    }

    if ( ! /^([_a-zA-Z]+[a-zA-Z0-9-]*)(\s+[_a-zA-Z]+[a-zA-Z0-9-]*)*$/.test( settings.className ) ) {
        window.console.error(
            'A class name must begin with a letter, followed by any number of hyphens, letters, or numbers.'
        );
        return;
    }

    if ( settings.className === null ) {
        const formatTypeForBareElement = select( 'core/rich-text' )
            .getFormatTypeForBareElement( settings.tagName );

        if ( formatTypeForBareElement ) {
            window.console.error(
                `Format "${ formatTypeForBareElement.name }" is already registered to handle bare tag name "${ settings.tagName }".`
            );
            return;
        }
    } else {
        const formatTypeForClassName = select( 'core/rich-text' )
            .getFormatTypeForClassName( settings.className );

        if ( formatTypeForClassName ) {
            window.console.error(
                `Format "${ formatTypeForClassName.name }" is already registered to handle class name "${ settings.className }".`
            );
            return;
        }
    }

    if ( ! ( 'title' in settings ) || settings.title === '' ) {
        window.console.error(
            'The format "' + settings.name + '" must have a title.'
        );
        return;
    }

    if ( 'keywords' in settings && settings.keywords.length > 3 ) {
        window.console.error(
            'The format "' + settings.name + '" can have a maximum of 3 keywords.'
        );
        return;
    }

    if ( typeof settings.title !== 'string' ) {
        window.console.error(
            'Format titles must be strings.'
        );
        return;
    }

    dispatch( 'core/rich-text' ).addFormatTypes( settings );

    return settings;
}

主な違いはクラス名の判定箇所です。

if ( ! /^[_a-zA-Z]+[a-zA-Z0-9-]*$/.test( settings.className ) ) {

if ( ! /^([_a-zA-Z]+[a-zA-Z0-9-]*)(\s+[_a-zA-Z]+[a-zA-Z0-9-]*)*$/.test( settings.className ) ) {

スペース区切りで複数の指定を許可しています。

動作確認

まとめ

複数クラスを付けられると使用しているテーマに組み込まれたデザインの利用がさらにしやすくなって便利になりそうです。

コメント