A ideia é configurar um botão para alternar entre adicionar e remover um span com um estilo css ao texto selecionado.
Demo e Download
O conteúdo abordado neste artigo pode ser testado online em nosso demo e também pode ser baixado para uso local.
Configuração básica
Crie o <textarea> e carregue o TinyMCE:
HTML
<textarea id='default'></textarea> <script src='tinymce.5.10.9/js/tinymce/tinymce.min.js'></script>
Altere o caminho para o arquivo tinymce.min.js conforme a sua necessidade.
Inicializando
Iniciaremos com um editor básico usando o elemento textarea com o id='default' criado acima. A altura será definida como 500px e o plugin code será carregado para disponibilizar a visualização do código fonte em HTML. A barra de ferramentas será customizada contendo os botões negrito, itálico e code.
JavaScript
tinymce.init({ selector: 'textarea#default', height: 500, plugins: 'code', toolbar: 'bold italic code', content_css: 'css/style.css?1', formats: { bold: { inline: 'span', attributes: { class: 'text-bold' }, }, }, });
A opção content_css define o caminho para o arquivo css contendo as regras de estilo que serão utilizadas dentro do editor, para por exemplo personalizar fontes, parágrafos e cabeçalhos. Os caracteres ?1 em frente ao nome do arquivo css são usados para limpar o cache depois de alterações, mudar o número em frente do ponto de interrogação força o recarregamento do arquivo, isto ocorre pois entende-se que o nome é diferente porém o arquivo sendo carregado é o mesmo.
Por fim, alteramos o comportamento padrão do negrito que é envolver o texto selecionado em um elemento <b>. Com a configuração acima, ao aplicar o negrito o texto selecionado será envolvido por um elemento <span class='text-bold'>. Neste caso é necessário fazer a estilização no arquivo css para que o negrito seja aplicado.
CSS
.text-bold {
font-weight: bold;
}
Teste o botão negrito inspecionando o código html do editor usando o botão < >.
Configurando os botões
Começando pelo css, prepare as classes que serão usadas no editor.
CSS
.text-bold { font-weight: bold; } .text-red { color: red; } .text-blue { color: blue; }
Abaixo o código completo com dois botões adicionais, Red e Blue, que envolvem o texto selecionado em um span contendo suas respectivas classes css.
JavaScript
// Função para converter caracteres html em suas entidades function encodeHTML(s) { return s.replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"'); } tinymce.init({ selector: 'textarea#default', height: 500, plugins: 'code', // Adiciona os botões Red e Blue na barra de ferramentas toolbar: 'bold italic code | textred textblue', content_css: 'css/style.css?1', formats: { bold: { inline: 'span', attributes: { class: 'text-bold' }, }, // Cria o formato para os botões
'textred': { inline: 'span', classes: 'text-red', wrapper: true }, 'textblue': { inline: 'span', classes: 'text-blue', wrapper: true }, }, setup: function(editor) { // Função para envolver o texto selecionado com o span // Recebe como parâmetro a classe a ser utilizada no span
function wrapText(cls) { const node = editor.selection.getNode(); const selectedText = encodeHTML(editor.selection.getContent({ format: 'text' })); if (node.nodeName == 'SPAN') { const l = node.classList.length; if (l == 0) { node.classList.add(cls); } else if (l == 1) { if (node.classList.contains(cls)) { editor.execCommand('mceReplaceContent', false, selectedText); } else { node.classList.add(cls); } } else { node.classList.remove(cls); } } else { editor.execCommand( 'mceReplaceContent', false, '<span class="' + cls + '">' + selectedText + '</span>'
); } } // Configura os botões editor.ui.registry.addButton('textred', { text: 'Red', tooltip: 'Span Vermelho', onAction: function() { wrapText('text-red'); } }); editor.ui.registry.addButton('textblue', { text: 'Blue', onAction: function() { wrapText('text-blue'); } }); } });
Neste exemplo são configurados dois botões adicionais para estilizar o texto no editor usando um elemento span contendo uma classe css. Selecione o texto e clique nos novos botões para adicionar e remover a customização.
Para remover a customização a seleção deve conter exatamente o mesmo texto da seleção original, incluindo espaços em branco. Para alternar a customização é necessário mudar o cursor de posição no editor antes de selecionar novamente o texto, veja mais informações na seção bugs adiante.
Considerações finais
A função wrapText() envolve o texto selecionado em um span se já não estiver em um. Caso o texto já esteja envolvido por um span e este não possuir a classe vinculada ao botão, a classe será adicionada ao span ao em vez de adicionar um novo span.
Ao clicar no botão, se o span envolvendo o texto possuir mais de uma classe, uma delas sendo a classe vinculada ao botão, esta será removida e o span preservado com o restante de suas classes.
O span não será adicionado se o cursor estiver posicionado na palavra e o texto não estiver selecionado.
Este artigo serve de inspiração para outras situações, você pode envolver o texto em uma div, criar botões para adicionar templates, use a criatividade.
Bugs
Um bug que parece estar relacionado ao editor ocorre da seguinte maneira: Ao selecionar um texto e clicar no botão negrito o padrão é aplicado, se clicar imediatamente após no botão Red o texto ficará vermelho e perderá o negrito. Para funcionar como deveria, após clicar no botão negrito, mude o cursor de posição, refaça a seleção do texto e somente depois clique no botão Red, assim o texto ficará em vermelho negrito.
Esse mesmo erro ocorre com o uso somente dos novos botões, se algo não funcionar tente mudar o cursor de posição e selecionar o texto novamente. Se for só uma palavra o clique duplo funciona. Mover o cursor do teclado de um lado e para outro e selecionar novamente também funciona.
Referências
O conteúdo deste artigo foi escrito através de consultas a documentação no site do TinyMCE, a tópicos no site stackoverflow, e a perguntas feitas ao ChatGPT.