TinyMCE – zarządzanie stanami przycisków

W poprzednich wpisach pokazałem jak dodawać własne przyciski do edytora TinyMCE oraz wstawić własny kod do edytora. Pora na zagadnienie bardziej złożone – dodawanie własnego formatowania i sprawienie by zachowywało się ono tak jak podstawowe przyciski formatowania dostępne w TinyMCE.

Pełny kod wtyczki opisywanej w poniższym wpisie znajduje się na Githubie.

Standardowe przyciski formatowania działają tak, że gdy kursor wprowadzania tekstu znajduje się w sformatowanym ciągu znaków są one aktywne. Dodanie takiego zachowania jest dostępne również dla naszych własnych przycisków.

Zacznijmy od podstaw skryptu dodającego przycisk – stworzymy przycisk, który tworzy duży tekst:

(function() {
    tinymce.PluginManager.add('dziudek_bigtext_button', function( editor, url ) {
       editor.addButton("dziudek_bigtext_button", {
            title: 'Big text',
            tooltip: "Toggle big text",
            icon: 'icon dashicons-arrow-up-alt2'
        })
    });
})();

Aby stworzyć formatowanie tekstu dla którego można zarządzać stanami przycisków musimy skorzystać z obiektu odpowiadającego za formatowanie tekstu i stworzyć funkcję, która odpowiednio go skonfiguruje:

var editorFormatterSetup = function(self) {
    editor.formatter.register('bigtext', {
        inline: 'strong',
        styles: {fontSize : '32px'}
    });

    editor.formatter.formatChanged('bigtext', function(state) {
        self.active(state);
    });
};

Powyższa funkcja tworzy nowy styl formatowania – bigtext, który korzysta ze znacznika strong oraz nadaje mu atrybut style z rozmiarem tekstu ustawionym na 32 piksele. Funkcja ta jako argument przyjmuje uchwyt do przycisku, który obsługuje dane formatowanie.

Kolejnym krokiem jest obsłużenie akcji zmiany stylu formatowania – służy do tego zdarzenie formatChanged, które jako pierwszy argument przyjmuje nazwę sposobu formatowania tekstu dla którego jest wywoływana funkcja podana jako drugi argument – w naszym wypadku będzie ona zmieniać stan przycisku pomiędzy stanami: aktywny i nieaktywny. Nie musimy tych stanów dodatkowo stylować, gdyż są one domyślnie ostylowane w edytorze.

Pora wykorzystać naszą funkcję – umieszczamy ją wewnątrz funkcji wywoływanej przy dodawaniu przycisku a dodatkowo definiujemy dwie akcje: onclick oraz onpostrender:

(function() {
    tinymce.PluginManager.add('dziudek_bigtext_button', function( editor, url ) {
        var editorFormatterSetup = function(self) {
            editor.formatter.register('bigtext', {
                inline: 'strong',
                styles: {fontSize : '32px'}
            });

            editor.formatter.formatChanged('bigtext', function(state) {
                self.active(state);
            });
       };

       editor.addButton("dziudek_bigtext_button", {
            title: 'Big text',
            tooltip: "Toggle big text",
            icon: 'icon dashicons-arrow-up-alt2',
            onclick: function() {
                editor.formatter.toggle('bigtext');
            },
            onpostrender: function() {
                var self = this;

                if(editor.formatter) {
                    editorFormatterSetup(self);
                } else {
                    editor.on('init', function() {
                        editorFormatterSetup(self);
                    });
                }
            }
        });
    });
})();

Akcja onclick jest już nam znana – w tym wypadku po prostu wywołujemy zmianę formatowania dla zaznaczonego tekstu z użyciem funkcji, która automatycznie włącza lub wyłącza formatowanie w zależności od tego czy było ono uprzednio zaaplikowane dla danego tekstu czy też nie. Jak widać dzięki funkcji toggle obiektu formatującego tekst w TinyMCE nie musimy się w ogóle martwić o wyodrębnienie zaznaczonego tekstu i sprawdzenie czy ma on zaaplikowane konkretne stylowanie czy też nie – a wszystko to dzięki temu, że skorzystaliśmy uprzednio ze stworzenia własnego stylu formatowania tekstu.

W akcji onpostrender definujemy kod, który wykona się przy renderowaniu posta w edytorze. W naszym wypadku tworzymy uchwyt do przycisku w postaci zmiennej self. Następnie w zależności od tego czy obiekt formatujący tekst w edytorze już istnieje czy też nie wywołujemy naszą funkcję konfigurującą nasz styl formatowania. W wypadku gdy obiekt ten nie jest zdefiniowany w momencie tworzenia naszego przycisku, nasza funkcja zostanie wywołana podczas inicjalizacji edytora.

W tym momencie mamy już działające zarządzanie stanami naszego przycisku:

btn_state_1

Pozwolę sobie opisać jeszcze jedno udogodnienie, które wymaga dodanie dodatkowego kodu przy zmianie stanu przycisku:

(function() {
    tinymce.PluginManager.add('dziudek_bigtext_button', function( editor, url ) {
        var editorFormatterSetup = function(self) {
            editor.formatter.register('bigtext', {
                inline: 'strong',
                styles: {fontSize : '32px'}
            });

            editor.formatter.formatChanged('bigtext', function(state) {
                self.active(state);

                if(state) {
                    document.querySelector('#' + self._id + ' i').setAttribute('class', 'mce-ico mce-i-icon dashicons-arrow-down-alt2');
                } else {
                    document.querySelector('#' + self._id + ' i').setAttribute('class', 'mce-ico mce-i-icon dashicons-arrow-up-alt2');
                }
            });
        };

        editor.addButton("dziudek_bigtext_button", {
            title: 'Big text',
            tooltip: "Toggle big text",
            icon: 'icon dashicons-arrow-up-alt2',
            onclick: function() {
                editor.formatter.toggle('bigtext');
            },
            onpostrender: function() {
                var self = this;

                if(editor.formatter) {
                    editorFormatterSetup(self);
                } else {
                    editor.on('init', function() {
                        editorFormatterSetup(self);
                    });
                }
            }
        });
    });
})();

W tym momencie poza stanem przycisku zmienią się też klasy CSS przypisane do naszego przycisku a jego wygląd będzie zależny od jego stanu:

btn_state_2

btn_state_3

Na koniec mała wskazówka dla tych, którzy niekoniecznie chcą korzystać z atrybutów <strong>style</strong> do stylowania tekstu – oczywiście można też użyć klas CSS:

editor.formatter.register('bigtext', {
    inline: 'strong',
    classes: 'big-text'
});

Powyższy kod doda klasę big-text do elementu strong – oczywiście warto pamiętać by plik editor.css w wykorzystywanym motywie zawierał odpowiedni kod stylujący tą klasę CSS.

Więcej o atrybutach obiektów konfigurujących sposoby formatowania tekstu można przeczytać w tym artykule.