Hay dos editores de texto WYSIWYG muy buenos realizados con HTML y JavaScript, el CKEditor y el tinyMCE. Además, si necesitamos algo mucho más ligero, también tenemos a nuestra disposición el bootstrap-wysiwyg y otros similares; pero en este post vamos a ver cómo podemos programar uno desde cero de forma muy sencilla y divertida gracias al atributo contenteditable de HTML y el método execCommand() del objeto document de javaScript. El atributo contenteditable puede tomar dos valores, true o false, y si está en true hace que el contenido de ese tag se pueda editar, es decir, que al ser pulsado, el usuario pueda modificar su contenido mediante el teclado y el ratón.
Lo que hay dentro de este div se puede editar.
</div>
$(".js-boton").mousedown(function(event) {
document.execCommand('bold', false, null);
});
})
<button class="js-boton" data-type="bold"><span class="glyphicon glyphicon-bold"></span></button>
<button class="js-boton" data-type="italic"><span class="glyphicon glyphicon-italic"></span></button>
<button class="js-boton" data-type="justifyLeft"><span class="glyphicon glyphicon-align-left"></span></button>
<button class="js-boton" data-type="justifyCenter"><span class="glyphicon glyphicon-align-center"></span></button>
<button class="js-boton" data-type="justifyRight"><span class="glyphicon glyphicon-align-right"></span></button>
<div id="editorWYS" contenteditable="true"> Lo que hay dentro de este div se puede editar. </div>
y algo así en el js.
$(document).ready(function() {
$(".js-boton").mousedown(function(event) {
event.preventDefault(); // Esto no es necesario, es por vicio xD
var comando = $(this).attr('data-type');
document.execCommand(comando, false, null);
});
});
Bueno, espero que hasta aquí todo esté claro, veamos ahora qué ocurre cuando perdemos el foco del nodo en el que hemos seleccionado algo.
Botones sin foco (dialogs)
En el caso anterior he utilizado el evento mousedown() en vez de un click() para que no se pierda el foco y con este, la selección del texto. Es un truco sencillo, pero se queda corto cuando no nos queda más remedio que perder el foco, como ocurre cuando necesitamos abrir un dialog o similar para que el usuario introduzca datos. En estas situaciones, el truco es primero guardar la selección y, después de que se hayan trabajado los datos pertinentes, restaurarla antes de ejecutar el execCommand. Un caso típico es un botón para insertar un enlace, donde no nos queda más remedio que incorporar un input para que se ponga la url. Vamos a ver cómo hacerlo :P. Primero añadimos un div a nuestro editor que nos servirá de dialog y un botón que lo abre:
<div id="js-dialog" style="display:none;"></div>
<button class="js-boton" data-type="bold">
<span class="glyphicon glyphicon-bold"></span></button> ...
<button id="js-enlaces"><span class="glyphicon glyphicon-paperclip"></span></button>
<div id="editorWYS" contenteditable="true"> </div>
Luego, en el js incorporamos tres funciones como las que tiene el bootstrap-wysiwyg, que están muy bien pensadas. Sin entrar en detalles, basta con decir que se basan en el método getSelection(), que recoge lo que está seleccionado:
var selectedRange;
function getCurrentRange() {
var sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
return sel.getRangeAt(0);
}
}
function saveSelection() {
selectedRange = getCurrentRange();
}
function restoreSelection() {
var selection = window.getSelection();
if (selectedRange) {
try {
selection.removeAllRanges();
} catch (ex) {
document.body.createTextRange().select();
document.selection.empty();
}
selection.addRange(selectedRange);
}
}
Y ahora solo necesitamos incorporar la funcionalidad del botón enlace:
$('#js-enlaces').mousedown(function(event) {
var cadena;
saveSelection();
cadena = "<div id='js-bodyDialog'>";
cadena += "<input type='text' id='js-inputURL' /><br />";
cadena += "<button id='js-aceptar'>Aceptar</button>";
cadena += "<button id='js-cancelar'>Cancelar</button>";
cadena += "</div>";
$('#js-dialog').html(cadena).show();
$('#js-cancelar').click(function() {
$('#js-bodyDialog').remove();
$('#js-dialog').hide();
});
$('#js-aceptar').click(function(event) {
event.preventDefault();
var href = $('#js-inputURL').val().trim().toLowerCase();
restoreSelection();
document.execCommand("createLink", false, href);
$('#js-bodyDialog').remove();
$('#js-dialog').hide();
});
});
Bueno, pues con esto y los métodos habituales de jQuery para trabajar el DOM, más o menos tenemos todo lo necesario para hacer un editor de texto con javaScript. Otro día vemos cómo incorporar otras funcionalidades, como un corrector de texto o un modo de visualización de código, y cómo enviar el texto editado por ajax a algún lado, pero por hoy lo dejo aquí :P.
Adenda
Otro día explico esto mejor. El método anterior tiene el inconveniente de que el texto que se devuelve es plano, sin código html; por lo que puede ser mejor hacer algo así en algunos casos:
$("#js-botonVersalitas").mousedown(function(event) {
var selObj = window.getSelection();
var selRange = selObj.getRangeAt(0);
var newNode = document.createElement("span");
newNode.style.cssText = 'font-variant:small-caps;';
selRange.surroundContents(newNode);
});
El problema ea que execcommand no genera marcado correcto (una lastima)
a qué te refieres exactamente Jorge?
muchas, gracias me sirvio de mucha utilidad, me gustaria que hicieras otro post, ampliando este tema, agregando nuevas funciones.
gracias, aquí encontrarás más funciones jquery plugin – editor wyswyg