javascript - parte - truncar texto con puntos suspensivos
Puntos suspensivos en medio de un texto(estilo Mac) (12)
Acabo de crear una función que puede recortar en el medio, cerca del final y el final, pero todavía no se han probado porque finalmente lo necesitaba en el lado del servidor
//position acceptable values : middle, end, closeEnd
function AddElipsis(input, maxChars, position) {
if (typeof input === ''undefined'') {
return "";
}
else if (input.length <= maxChars) {
return input;
}
else {
if (position == ''middle'') {
var midPos = Math.floor(maxChars / 2) - 2;
return input.substr(0, midPos) + ''...'' + input.substr(input.length - midPos, input.length);
}
else if (position == ''closeEnd'') {
var firstPart = Math.floor(maxChars * 0.80) - 2;
var endPart = Math.floor(maxChars * 0.20) - 2;
return input.substr(0, firstPart) + ''...'' + input.substr(input.length - endPart, input.length);
}
else {
return input.substr(0, maxChars - 3) + ''...'';
}
}
}
Necesito implementar ellipsis ( "..."
) en el medio de un texto dentro de un elemento redimensionable. Esto es lo que podría parecer. Asi que,
"Lorem ipsum dolor sit amet. Ut ornare dignissim ligula sed commodo."
se convierte
"Lorem ipsum dolor sit amet ... commodo."
Cuando el elemento se estira al ancho del texto, quiero que desaparezcan las elipsis. ¿Cómo puede hacerse esto?
Aquí está el bit más corto que pude encontrar que reemplaza 3 caracteres en el medio con ....
function shorten(s, max) {
return s.length > max ? s.substring(0, (max / 2) - 1) + ''...'' + s.substring(s.length - (max / 2) + 2, s.length) : s
}
Después de investigar un poco sobre las cajas flexibles, encontré esta solución pura de CSS, que creo que es muy buena.
<div style="width:100%;border:1px solid green;display:inline-flex;flex-wrap:nowrap;">
<div style="flex: 0 1 content;text-overflow: ellipsis;overflow:hidden;white-space:nowrap;"> Her comes very very very very very very very very very very very very very very very very very very very long </div>
<div style="flex: 1 0 content;white-space:nowrap;"> but flexible line</div>
</div>
En el HTML, coloque el valor completo en un atributo personalizado data- * como
<span data-original="your string here"></span>
A continuación, asigne load
y resize
detectores de eventos a una función de JavaScript que leerá el atributo de datos original y lo colocará en el HTML innerHTML
de su etiqueta span. Aquí hay un ejemplo de la función de puntos suspensivos:
function start_and_end(str) {
if (str.length > 35) {
return str.substr(0, 20) + ''...'' + str.substr(str.length-10, str.length);
}
return str;
}
Ajuste los valores o, si es posible, haga que sean dinámicos, si es necesario para diferentes objetos. Si tiene usuarios de diferentes navegadores, puede robar un ancho de referencia de un texto con la misma fuente y tamaño en cualquier otro lugar de su dominio. Luego, interpola a una cantidad apropiada de caracteres para usar.
Un consejo es también tener una etiqueta abreviada en el ... o quién mensaje para que el usuario pueda obtener una información sobre herramientas con la cadena completa.
<abbr title="simple tool tip">something</abbr>
Entonces, mi colega propuso una solución que no usa elementos adicionales de dom. Verificamos si el div se desborda y agregamos un atributo de datos de los últimos n caracteres. El resto se hace en css.
Aquí hay algo de HTML:
<div class="box">
<div class="ellipsis" data-tail="some">This is my text it is awesome</div>
</div>
<div class="box">
<div class="ellipsis">This is my text</div>
</div>
Y el CSS:
.box {
width: 200px;
}
.ellipsis:before {
float: right;
content: attr(data-tail);
}
.ellipsis {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
Aquí está el jsfiddle obligatorio para esto: http://jsfiddle.net/r96vB/1/
Esto le dará un poco más de control sobre la posición de la elipsis y el texto del marcador de posición:
function ellipsis(str, maxLength, ellipsisLocationPercentage,placeholder) {
/*
ARGUMENTS:
str - the string you want to maninpulate
maxLength - max number of characters allowed in return string
ellipsisLocationPercentage (optional) - How far (percentage wise) into the return string you want the ellipses to be placed
Examples:
.85 : This is a very long string. This is a very long string. This is a very long string. This is a ver[...]very long string.
.25 : This is a very long string. [...]g. This is a very long string. This is a very long string. This is a very long string.
placeholder (optional) - this will be used to replace the removed substring. Suggestions : ''...'', ''[..]'', ''[ ... ]'', etc....
*/
if(ellipsisLocationPercentage == null || isNaN(ellipsisLocationPercentage) || ellipsisLocationPercentage >= 1 || ellipsisLocationPercentage <= 0){
//we''ve got null or bad data.. default to something fun, like 85% (that''s fun, right??)
ellipsisLocationPercentage = .85;
}
if(placeholder == null || placeholder ==""){
placeholder = "[...]";
}
if (str.length > (maxLength-placeholder.length)) {
//get the end of the string
var beginning = str.substr(0, (maxLength - placeholder.length)*ellipsisLocationPercentage );
var end = str.substr(str.length-(maxLength - placeholder.length) * (1-ellipsisLocationPercentage));
return beginning + placeholder + end;
}
return str;
}
Puede llamar a esta función llamando al:
ellipsis("This is a very long string. Be Scared!!!!", 8);//uses default values
ellipsis("This is a very long string. Be Scared!!!!", 8,.5);//puts ellipsis at half way point
ellipsis("This is a very long string. Be Scared!!!!", 8,.75,''<..>'');//puts ellipsis at 75% of the way into the string and uses ''<..>'' as the placeholder
Esto puede ser un poco tarde en el juego, pero estaba buscando una solución para esto, y un colega me sugirió uno muy elegante, que compartiré. Requiere algunos JS, pero no mucho.
Imagina que tienes un div
de un tamaño que necesitas para poner tu etiqueta en:
<div style="width: 200px; overflow: hidden"></div>
Ahora, tienes una función que tomará dos params: una cadena con la etiqueta, y un elemento DOM (este div
) para que quepa en:
function setEllipsisLabel(div, label)
Lo primero que debe hacer es crear un span
con esta etiqueta y colocarlo en el div
:
var span = document.createElement(''span'');
span.appendChild(document.createTextNode(label));
span.style.textOverflow = ''ellipsis'';
span.style.display = ''inline-block'';
div.appendChild(span);
Configuramos la propiedad de text-overflow
en "puntos suspensivos" para que, cuando el texto sea cortado, se agregue un "..." al final para ilustrar esto. También establecemos que la display
sea "en línea" para que estos elementos tengan dimensiones reales en píxeles que podemos manipular más adelante. Hasta ahora, nada que no pudiéramos haber hecho con CSS puro.
Pero queremos las elipsis en el medio. En primer lugar, deberíamos averiguar si lo necesitamos en absoluto ... Esto se puede hacer comparando div.clientWidth
con span.clientWidth
; solo se necesita puntos suspensivos si el span
es más ancho que el div
.
Si necesitamos una elipsis, comencemos diciendo que queremos que se muestre un número fijo de caracteres al final de la palabra, por ejemplo, 10. Creemos un tramo que contenga solo los últimos 10 caracteres de la etiqueta y pégalo en el div:
var endSpan = document.createElement(''span'');
endSpan.style.display = ''inline-block'';
endspan.appendChild(document.createTextNode(label.substring(label.length - 10)));
div.appendChild(endSpan);
Ahora, anulemos el ancho del span
original para acomodar el nuevo:
span.style.width = (div.clientWidth - endSpan.clientWidth) + ''px'';
Como resultado de esto, ahora tenemos una estructura DOM que se ve más o menos así:
<div style="width: 200px; overflow: hidden">
<span style="display: inline-block; text-overflow: ellipsis; width: 100px">
A really long label is shown in this span
</span>
<span style="display: inline-block"> this span</span>
</div>
Debido a que el primer span
tiene text-overflow
establecido en "puntos suspensivos", mostrará "..." al final, seguido de los 10 caracteres del segundo tramo, lo que dará como resultado puntos suspensivos que se muestran aproximadamente en el medio del div
.
No es necesario codificar también la longitud de 10 caracteres para endSpan: esto se puede calcular calculando la relación entre el ancho inicial del span
y el del div
, restando la proporción apropiada de la longitud de la etiqueta y dividiendo por dos .
La siguiente función de Javascript hará un truncamiento intermedio, como OS X:
function smartTrim(string, maxLength) {
if (!string) return string;
if (maxLength < 1) return string;
if (string.length <= maxLength) return string;
if (maxLength == 1) return string.substring(0,1) + ''...'';
var midpoint = Math.ceil(string.length / 2);
var toremove = string.length - maxLength;
var lstrip = Math.ceil(toremove/2);
var rstrip = toremove - lstrip;
return string.substring(0, midpoint-lstrip) + ''...''
+ string.substring(midpoint+rstrip);
}
Reemplazará a los personajes en el medio con puntos suspensivos. Mis pruebas unitarias muestran:
var s = ''1234567890'';
assertEquals(smartTrim(s, -1), ''1234567890'');
assertEquals(smartTrim(s, 0), ''1234567890'');
assertEquals(smartTrim(s, 1), ''1...'');
assertEquals(smartTrim(s, 2), ''1...0'');
assertEquals(smartTrim(s, 3), ''1...90'');
assertEquals(smartTrim(s, 4), ''12...90'');
assertEquals(smartTrim(s, 5), ''12...890'');
assertEquals(smartTrim(s, 6), ''123...890'');
assertEquals(smartTrim(s, 7), ''123...7890'');
assertEquals(smartTrim(s, 8), ''1234...7890'');
assertEquals(smartTrim(s, 9), ''1234...67890'');
assertEquals(smartTrim(s, 10), ''1234567890'');
assertEquals(smartTrim(s, 11), ''1234567890'');
Me gustaría proponer el ejemplo de cómo resolver este problema.
La idea principal es dividir el texto en dos partes pares (o la primera es más grande, si la longitud es impar) una de las cuales tiene puntos suspensivos al final y otra alineada a la derecha con text-overflow: clip
.
Entonces, todo lo que necesitas hacer con js, si quieres que sea automático / universal, es dividir la cadena y establecer los atributos.
Sin embargo, tiene algunas desventajas.
- No es agradable envolver con palabras, o incluso letras (
text-overflow: ''''
no funciona, al menos, en cromo) - Si la división ocurre entre palabras, el espacio debe estar en la primera parte. De lo contrario, se colapsará.
- El final de la cadena no debe tener signos de exclamación, debido a la
direction: rtl
a la izquierda de la cadena. Creo que es posible solucionar esto poniendo una parte correcta de la palabra en la etiqueta y el signo de exclamación en el pseudo-elemento::after
. Pero todavía no lo he hecho funcionar correctamente.
Pero, con todo esto, me parece realmente genial, especialmente cuando arrastra el borde del navegador, lo cual puede hacer fácilmente en la página jsfiddle: https://jsfiddle.net/extempl/93ymy3oL/ . O simplemente ejecute el fragmento con ancho máximo fijo a continuación.
Gif bajo el alerón:
body {
max-width: 400px;
}
span::before, span::after {
display: inline-block;
max-width: 50%;
overflow: hidden;
white-space: pre;
}
span::before {
content: attr(data-content-start);
text-overflow: ellipsis;
}
span::after {
content: attr(data-content-end);
text-overflow: clip;
direction: rtl;
}
<span data-content-start="Look deep into nature, and then you "
data-content-end= "will understand everything better"></span>
<br>
<span data-content-start="https://www.google.com.ua/images/branding/g"
data-content-end= "ooglelogo/2x/googlelogo_color_272x92dp.png"></span>
No puedes hacer eso con CSS. El problema es que se supone que HTML y CSS funcionan en una variedad de navegadores y fuentes, y es casi imposible calcular el ancho de una cadena de forma consistente. Esta es una idea que podría ayudarte. Sin embargo, necesitarías hacer eso varias veces, hasta que encuentres la cadena con el ancho apropiado.
Otra puñalada:
function truncate( str, max, sep ) {
max = max || 10;
var len = str.length;
if(len > max){
sep = sep || "...";
var seplen = sep.length;
if(seplen > max) { return str.substr(len - max) }
var n = -0.5 * (max - len - seplen);
var center = len/2;
return str.substr(0, center - n) + sep + str.substr(len - center + n);
}
return str;
}
console.log( truncate("123456789abcde") ); // 123...bcde (using built-in defaults)
console.log( truncate("123456789abcde", 8) ); // 12...cde (max of 8 characters)
console.log( truncate("123456789abcde", 12, "_") ); // 12345_9abcde (customize the separator)
Para hacer un corte limpio y tener una palabra completa al final del texto acortado, utilicé la función siguiente.
function prepareText(text){
var returnString = text;
var textLimit = 35;
if(text.length > textLimit){
var lastWord = text.slice( text.lastIndexOf('' '')+1 );
var indexFromEnd = lastWord.length;
var ellipsis = ''... '';
returnString = text.slice(0, textLimit - indexFromEnd - ellipsis.length);
returnString = returnString + ellipsis + lastWord;
}
return returnString;
}
$(''#ex1Modified'').html( prepareText( $(''#ex1'').html() ) );
$(''#ex2Modified'').html( prepareText( $(''#ex2'').html() ) );
$(''#ex3Modified'').html( prepareText( $(''#ex3'').html() ) );
body{color:#777; font-family: sans-serif;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Shortened Quotes from Albert Einstein</h2>
<div id="ex1">"The true sign of intelligence is not knowledge but imagination."</div>
<div id="ex1Modified"></div>
<br>
<div id="ex2">"Look deep into nature, and then you will understand everything better."</div>
<div id="ex2Modified"></div>
<br>
<div id="ex3">"You can''t blame gravity for falling in love."</div>
<div id="ex3Modified"></div>