lenguajes de programación

Separar un texto en divs dinámicamente

Revisando mi código viejo, hice hace tiempo un editor de texto en HTML, pensando en que fuera un Editor en línea tipo Word HTML5, con puro CSS, JavaScript y jQuery, pues en ese entonces no había Office 365. Mi problema es que aunque se pinta una página, esta página se agranda infinitamente. Eso se debe a que me faltó separar un texto en divs dinámicamente, el texto del usuario al ser editable puede ser cualquier cantidad de texto, a veces son 200 líneas de texto, otras veces apenas 2 elementos, lo cual nos presenta un problema un poco fuera de lo común, pues cada página es un div, que debe de tener una altura igual, y una separación constante entre cada hoja.

La solución debe:

  • Mantener todo dentro del <div> contenedor.
  • Funcionar con contenido dinámico.
  • Evitar cambiar la estructura a <table> u otros elementos.

Paso 1: Bloques de tamaño fijo con CSS

Primero, definimos columnas de cierta altura, por ejemplo 200 píxeles. Para mantener el contenido dentro de esos límites sin que se vea el excedente, usamos overflow: hidden y un borde inferior como separador.

.column {
  height: 200px;
  overflow: hidden;
  border-bottom: 1px dotted gray; /* Línea separadora */  margin-bottom: 10px;
  padding: 10px;
}

Paso 2: Distribuir el contenido dinámicamente con JavaScript

El siguiente reto es evitar que el contenido se corte de manera brusca. Para eso, usamos una función que reparte el texto en cada bloque y mueve el sobrante al siguiente.

Estructura HTML

El HTML inicial es sencillo:

<div id="container">
  <div class="column"></div>
</div>

Simplemente tenemos nuestro contenedor que es el área gris, y cada column es una página.

Aunque tengamos una sola página que es un div, con JavaScript agregaremos más páginas y nos encargaremos de separar un texto en divs, ¿Qué texto? El texto que el usuario escriba.

La función distributeText

function distributeText(fullText, containers) {
  let remainingText = fullText;
  ...
}

👉 Esta función recibe:

  • fullText: es todo el texto que queremos mostrar.
  • containers: un arreglo de elementos HTML (nuestros divs, que son filas).

La idea es llenar cada div con la mayor cantidad de texto posible, y si sobra texto, pasarlo al siguiente bloque, para eso guardamos el texto que no quepa en remainingText.

Recorremos cada bloque

con el ciclo de nuestra preferencia iteramos cada elemento que queremos que contenga texto, es decir, cada página que tenga, y al inicio solamente va a tener una.

for (let i = 0; i < containers.length; i++) {
  const container = containers[i];
  container.innerHTML = remainingText;

Aquí tomamos cada bloque .column y le metemos el texto que queda (remainingText).

Detectamos si el texto se desborda

Para obtener las medidas de cada div usaremos dos propiedades de solo lectura que pertenecen a la API HTMLElement, en concreto scrollHeight y clientHeight.

if (container.scrollHeight > container.clientHeight) {
  • scrollHeight: cuánto mide el contenido real.
  • clientHeight: cuánto espacio tiene disponible el contenedor (200px).

👉 Si el contenido mide más que el contenedor, significa que se desbordó.

Ajustamos hasta que encaje

Para saber que texto es visible en un div usamos la propiedad innerText del api HTMLElement.

let textContent = container.innerText;
let lastValidIndex = textContent.length;

while (container.scrollHeight > container.clientHeight && lastValidIndex > 0) {
  lastValidIndex--;
  container.innerText = textContent.substring(0, lastValidIndex);
}

Aquí lo que hacemos es recortar el texto poco a poco hasta que encaje dentro de los 200px.

  • substring(0, lastValidIndex) → va eliminando las últimas letras una por una.
  • Cuando finalmente el texto cabe, paramos.

Guardamos lo que sobró

remainingText = textContent.substring(lastValidIndex);

Todo el texto que ya no cabía se guarda en remainingText. Ese será el texto que pasaremos al siguiente bloque .column.

Salimos si ya no queda texto

if (remainingText === "") break;

Esto evita revisar los bloques restantes si ya acabamos.

Creamos más bloques si hace falta

Aquí para resolverlo había dos opciones, con recursividad o de forma iterativa. como estamos modificando el dom directamente sinceramente el desempeño sería pésimo con ambas opciones, así que fui por la más entendible, con un while.

let pendientes = distributeText(fullContent, containers);
while (pendientes > 0) {
  const container = document.getElementById('container');
  const div = document.createElement("div");
  div.setAttribute("class", "column");
  container.append(div);

  pendientes = distributeText(fullContent, Array.from(document.querySelectorAll('.column')));
}
  • pendientes guarda el número de caracteres que aún no se han colocado en ningún bloque.
  • Mientras quede texto pendiente, creamos un nuevo bloque .column y volvemos a ejecutar la función haciendo todo desde el inicio.
  • Así, el script seguirá generando columnas automáticamente hasta mostrar todo el contenido.
javatlacati

Compartir
Publicado por
javatlacati
Etiquetas: HTML5javascript

Entradas recientes

Cursos de LinkedIn Learning

Te comparto aquí mis recomendaciones de cursos de Linkedin Learning. LinkedIn Learning es una plataforma…

1 mes hace

Mockito: Snippets de código

Estos snippets de código para entrevista acerca de mockito espero te sean de mucha utilidad.…

2 meses hace

Expresiones regulares en Java: analizar un String

En este tutorial aprenderá a usar expresiones regulares en Java de manera práctica para contar…

2 meses hace

Preguntas para entrevista de programación Java full-stack

¿Entrevista de programación Java fullstack? No te preocupes, te tengo un compendio de preguntas de…

3 meses hace

SoftSkills: cursos de Udemy

Te recomiendo algunos cursos de Udemy para mejorar tus softskills y así mejorar en tu…

3 meses hace

Cursos de Código Facilito

Te comparto aquí mis recomendaciones de cursos de Código Facilito. Codigofacilito.com es una plataforma virtual…

3 meses hace