In below code I'm attempting to truncate the <a> tag text :
<a href='test'>
<script>
truncate("truncate this text");
</script>
</a>
function truncate(string){
if (string.length > 5)
return string.substring(0,5)+'...';
else
return string;
};
https://jsfiddle.net/fcq6o4Lz/6/
But returns error Uncaught ReferenceError: truncate is not defined
How can this function be invoked from within <a> tag ?
Why
The reason you get the error is because your computer hasn't run the code that defined truncate yet. That function is running before the page finishes loading, that includes the JavaScript. Put the code in a window.onload with a setTimeout to be safe.
window.onload = function(){setTimeout(function () {
truncate("truncate this text");
},1);};
How
Also, unlike languages such as PHP. return won't place any text. Do something like:
<a id="result-location" href='test'>
<script>
window.onload = function(){setTimeout(function () {
document.getElementById('result-location').innerHTML = truncate("truncate this text");
},1);};
</script>
</a>
Fiddle
JSFiddle Fix
Remember to keep the function outside of a window.onload. You can change this in JSFiddle by setting it no no-wrap
CSS
You can use CSS to truncate text
.truncate {
width: 50px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
}
This will cause the text to truncate, after 50px;
.truncate {
width: 50px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
}
<a class="truncate">This text is truncated</a>
You don't invoke javascript code like this. Although you could use document.write to print result of javascript function into HTML element, it is stongly advised to avoid this, as it makes code really confusing.
Instead try something like this: select HTML element in question with CSS selector, select corresponding HTML element, and finally modify its inner content.
function truncate(selector) {
var obj = document.querySelector(selector),
string = obj.innerHTML;
if (string.length > 5) string = string.substring(0, 5) + '...';
obj.innerHTML = string;
};
truncate('#link');
truncate this text
You have to address the element with an ID, like this:
truncate this text
<script>
function truncate(id){
var string = document.getElementById(id).innerHTML;
if (string.length > 5) {
document.getElementById(id).innerHTML = string.substring(0,5)+'...';
}
};
truncate("test-id");
</script>
JSFiddle-Demo: http://jsfiddle.net/c8s3dc6q/1/
All javascript, including the function definition, should happen within a <script> ... </script> block. And that script block should stay in the end of the page, where the function "selects" the a tag with an id or class.
However I think that you might want to achieve the same results using pure CSS.
<a class="trim-text">This text should be trimmed!</a>
// add this to your css file / block
.trim-text {
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
h1 {
max-width: 100px;
}
If you're open to a css only method there's a way to do that. It's based on width and not character count so more precise for styling.
fiddle
http://jsfiddle.net/Hastig/ufe1t66v/3/
html
<a class="truncated-anchors">This be way too long</a>
<a class="truncated-anchors">This too is too long</a>
<a class="truncated-anchors">This as well, far too long</a>
<a class="truncated-anchors">This one is even longer if I add some more words</a>
css
.truncated-anchors {
display: inline-block;
width: 100px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
A more thorough explanation
http://makandracards.com/makandra/5883-use-css-text-overflow-to-truncate-long-texts
And there are options to not use ellipsis and just end it immediately.
Simply define the function before its call in the code, then use document.write to receive the output of the function
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<script>
function truncate(string){
if (string.length > 5)
return string.substring(0,5)+'...';
else
return string;
};
</script>
</head>
<body>
hhhhhhh<br />
<a href='test'>
<script>
document.write(truncate("truncate this text"));
</script>
</a>
</body>
</html>
Checkout this DEMO
Related
Hello stackoverflow community, I have a question regarding the use of the <object> html tag. Below is a description of what I want to do:
I am using the summernote editor, however I would like every change within the editor to be presented to the user as the html page will be. I am currently using the following code:
$('#summernote').summernote({
placeholder: 'Hello bootstrap 4',
tabsize: 2,
height: 300,
lang: 'pt-BR'
});
$("#summernote").on("summernote.change", function(e) { // callback as jquery custom event
console.log('it is changed');
myFunction();
});
var i = 0;
var dragging = false;
$('#dragbar').mousedown(function(e) {
e.preventDefault();
dragging = true;
var main = $('#main');
var ghostbar = $('<div>', {
id: 'ghostbar',
css: {
height: main.outerHeight(),
top: main.offset().top,
left: main.offset().left
}
}).appendTo('body');
$(document).mousemove(function(e) {
ghostbar.css("left", e.pageX + 2);
});
});
$(document).mouseup(function(e) {
if (dragging) {
var percentage = (e.pageX / window.innerWidth) * 100;
var mainPercentage = 100 - percentage;
$('#console').text("side:" + percentage + " main:" + mainPercentage);
$('#sidebar').css("width", percentage + "%");
$('#main').css("width", mainPercentage + "%");
$('#ghostbar').remove();
$(document).unbind('mousemove');
dragging = false;
}
});
function myFunction(data) {
var text = $('#summernote').summernote('code');
document.getElementById("demo").innerHTML = "<!DOCTYPE html><html><meta charset='UTF-8'>" + text + "</html>";
console.log(document.getElementById("demo"));
console.log(text);
}
.clearfix:after {
content: '';
display: table;
clear: both;
}
#main {
float: right;
width: 50%;
}
#sidebar {
width: 50%;
float: left;
overflow-y: hidden;
}
#dragbar {
/*background-color: #a9a9a9;*/
background: transparent;
height: 100%;
float: right;
width: 3px;
cursor: col-resize;
}
#ghostbar {
width: 3px;
background-color: #a9a9a9;
opacity: 0.5;
position: absolute;
cursor: col-resize;
z-index: 999
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Summernote Editor</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.9/summernote-bs4.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.9/summernote-bs4.js"></script>
<script src="summernote-pt-BR.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<!--<div id="summernote"></div>-->
<div id="sidebar" class="col">
<span id="position"></span>
<div id="dragbar">
</div>
sidebar
<form method="post">
<textarea id="summernote" name="editordata"></textarea>
<button type="submit" class="btn btn-primary">Salvar</button>
</form>
</div>
<div id="main">main
<p id="demo"></p>
</div>
</div>
</div>
</body>
</html>
But instead of using the <p> tag along with innerHtml, I'd like to use the <object> tag, and its contents being changed daily.
If you have other better solutions, feel free to make suggestions.
Note: I have already tried using the tag but somehow using this tag hinders the resize that I need to perform between the editor and html viewer.
Note 2: I'm a beginner, and my English is not good. So sorry if something went wrong without making sense. I used Google translate to explain the issue.
Hi Rafael — thanks for clarifying.
The reason your code looks different in the iframe or object tags is due to the differing CSS. When you use an iframe and set the source dynamically, the CSS comes from the User Agent Stylesheet. The tag does not inherit the parent's styles. Currently, your CSS in the p tag is from Bootstrap 4.
Option 1: You could customize the CSS on this element to make it appear consistent in a non-Bootstrap context.
Option 2: If you still want to change tags, I think you are better off using an iframe instead of an object tag, per the MDN docs and the discussion on this SO thread.
Change <p id="demo"></p> to <iframe id="demo"></iframe>, and your myFunction to:
function myFunction(data) {
var text = $('#summernote').summernote('code');
var frame=document.getElementById("demo");
frame.srcdoc="<!DOCTYPE html><html><meta charset='UTF-8'>" + text + "</html>";
}
If you support IE11, Edge, and Opera Mini (srcdoc is not supported there) you can use a polyfill.
One final consideration with this route is performance — I couldn't find much on this, but I suspect that setting the innerHTML of your p tag is far less expensive than re-rendering an iframe. You might want to investigate and consider reducing the update interval if this becomes a problem.
This question already has answers here:
Setting a max character length in CSS
(15 answers)
Closed 2 years ago.
I have the following mark-up:
<h5>
I am a very long title and I need to be shortened
</h5>
How can I make it so that if the h5 text is above a certain number of characters, I get rid of the other characters and replace them with a "..."?
This should work. You have to display the inline element as a block.
Edit: Just realized you want to add dots if the H5 exceeds a number of characters, not if it exceeds a width. I think to do that you will need to use JS - check out the other answer for that.
h5 {
display: block;
white-space: nowrap;
width: 12em;
overflow: hidden;
text-overflow: ellipsis;
color: red; /* This needs to match the color of the anchor tag */
}
a:link {
color: red;
}
<h5>
I am a very long title and I need to be shortened
</h5>
You can do this:
var name = $('a').text();
if (name.length > 20) {
var shortname = name.substring(0, 20) + " ...";
$('a').replaceWith(shortname);
}
If you want to use javascript, you can extend String object by prototyping:
String.prototype.limit = function(length) {
return this.length > length ? (this.substring(0, length) + '...') : this;
}
var str = 'qwertyuiop';
console.log(str.limit(5)); // qwert...
<h5 id="expansion">
<a id="myLink" href="javascript:void(0);">I am a very long title and I need to be shortened And Also I am a very long title and I need to be shortened</a>
</h5>
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
if($('#myLink').text().length > 20){
var linkText = $('#myLink').text();
$('#myLink').html(linkText.substring(0,20)+"...")
$('#myLink').on("click",function(){
console.log("linkText :: ",linkText);
$('#myLink').html(linkText);
});
}
</script>
This one is working
<h5>
<a class ="one" href="javascript:void(0);">I am a very long title and I need to be shortened</a>
</h5>
<style>
.one
{
white-space: nowrap;
overflow:hidden;
text-overflow: ellipsis;
display:inline-block;
width : 100px;
}
</style>
set the width according to your website design
I have one div container which will be visible only on printing. This div on certain user action should be injected with some content and then sent to print.
#media print {
html body * {
display: none;
}
#toPrint{
display: block;
}
}
#media screen {
#toPrint {
display: none;
}
}
inside Layout page I have following structure
<html>
<body>
#RenderBody()
<div id="toPrint"></div>
</body>
</html>
and inside view page under dom.ready I have script
var content = $("<table />").append(
$("<tr />").append(
$("<td />").append("TEST")
));
$("#toPrint").append(content);
appending with this 'complex element' doesn't work, but with following code works
var content = "abc";
$("#toPrint").append(content);
I tried to decorate elements with single quotes, tried to inject div instead of table, nothing helper, works just plain string without decorated elements.
Where is div id="toAppend" in your code?
Have you try console.log(content) ?
var content = $("<table />").append(
$("<tr />").append(
$("<td />").append("TEST")
));
$("#toPrint").append(content);
#media print {
html body * {
display: none;
}
#toPrint{
display: block;
}
}
#media screen {
#toPrint {
display: none;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='toPrint'>
</div>
What you've posted works just as you are wanting it to work, so I don't think anyone is going to be able to help you based on the available information. I assume simplifying the problem resolved whatever issue you were having. Just run the above snippet to see that the TEST is indeed hidden.
Hi there my code is quite simple but Id like for the design purposes to keep everything neat , at the moment Im pulling all the description which is like Some could be huge others can be quite small , anyway to make it fair I decided to make a read more button and once I click it just expand on the text like , SO somehow to make it show the first 160 characters after that ... then ReadMore link button that when you click it expands and shows the whole text
Heres my script that I use for now :
<p><?PHP echo $thismovie['description']; ?></p> <div style="text-align:right">
So I would like to know how this is done and if possible only using javascript, thanks !
While you could of course use PHP, another way is to use the text-overflow property of css correctly.
This method will put less strain on the server, especially when there are a bunch of descriptions on the page. Using PHP to concatenate every single one is not efficient and is not the correct way to do this.
Removing a class is much simpler. And you can add it back when you want to show less.
<style>
.ellipsis {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
height: 14px;
}
.description {
width: 300px;
background: #ccc;
padding: 3px;
margin-top: 30px;
margin-bottom: 0;
}
</style>
<!-- It is likely you would use a PHP loop for this but for illustration
purposes I've listed them out -->
<p class="description ellipsis"><?=$movie[0]['description']?></p>
Read More
<p class="description ellipsis"><?=$movie[1]['description']?></p>
Read More
<p class="description ellipsis"><?=$movie[2]['description']?></p>
Read More
<!-- use as many as you want with no additional strain on server. -->
WITH JQUERY... http://jsfiddle.net/kx2nbv3z/
<!-- Include jQuery -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$(document)
.on('click','.read-more',function() {
$(this).removeClass('read-more').addClass('show-less').html('Show Less').prev('.description').removeClass('ellipsis');
})
.on('click','.show-less',function() {
$(this).removeClass('show-less').addClass('read-more').html('Read More').prev('.description').addClass('ellipsis');
})
;
</script>
WITH PURE JAVASCRIPT... http://jsfiddle.net/8wsbw0u8/
<script>
if (document.body.addEventListener) {
document.body.addEventListener('click',yourHandler,false);
}
else {
document.body.attachEvent('onclick',yourHandler);//for IE
}
function yourHandler(e) {
e = e || window.event;
var target = e.target || e.srcElement;
prev = target.previousSibling.previousSibling;
if (target.className.match(/read-more/)) {
target.className="show-less";
target.innerHTML = "Show Less";
prev.setAttribute("class","description");
console.log(prev);
}
else if (target.className.match(/show-less/)) {
target.className="read-more";
target.innerHTML = "Read More";
prev.setAttribute("class","description ellipsis");
}
}
</script>
for PHP way:
$firstdesc=substr($thismovie['description'], 0, 160);
and when read-more pressed.
$totaldesc=substr($thismovie['description'], 160);
Ofcourse you can do it with Javascript too.
use the css style `text-overflow: ellipsis; and jquery for the full feature.
$('#read-more').click(function() {
$('#description').css('width','100%');
});
#description {
white-space: nowrap;
width: 12em;
overflow: hidden;
text-overflow: ellipsis;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="description">This is some long text that will not fit in the box</div> <a id="read-more" href="#">Read More</a>
I have a list of paths (for lack of a better word, maybe bread crumb trails describes them better). Some of the values are too long to display in their parent so I'm using text-overflow: ellipsis. The problem is that the important information is on the right, so I'd like the ellipsis to appear on the left. Something like this this ascii art:
----------------------------
|first > second > third |
|...second > third > fourth|
|...fifth > sixth > seventh|
----------------------------
Notice that the first row is short enough so it remains left aligned, but the other two are too long so the ellipsis appears on the left hand side.
I'd prefer a CSS only solution, but JS is fine if it can't be avoided. It's ok if the solution only works in Firefox and Chrome.
EDIT: At this point I'm looking for a work around for the bugs in Chrome that prevent it from rendering properly when a document is mixed RTL and LTR. That was all I really needed from the outset, I just didn't realize it.
How about something like this jsFiddle? It uses the direction, text-align, and text-overflow to get the ellipsis on the left. According to MDN, there may be the possibility of specifying the ellipsis on the left in the future with the left-overflow-type value however it's considered to still be experimental.
p {
white-space: nowrap;
overflow: hidden;
/* "overflow" value must be different from "visible" */
text-overflow: ellipsis;
width: 170px;
border: 1px solid #999;
direction: rtl;
text-align: left;
}
<p>first > second > third<br /> second > third > fourth > fifth > sixth<br /> fifth > sixth > seventh > eighth > ninth</p>
I finally had to crack and do something in JavaScript. I was hoping that someone would come up with a hail-mary CSS solution but people seem to just be up-voting the answer that should be correct if it weren't for the Chrome bugs. j08691 can have the bounty for his work.
<html>
<head>
<style>
#container {
width: 200px;
border: 1px solid blue;
}
#container div {
width: 100%;
overflow: hidden;
white-space: nowrap;
}
</style>
<script>
function trimRows() {
var rows = document.getElementById('container').childNodes;
for (var i=0, row; row = rows[i]; i++) {
if (row.scrollWidth > row.offsetWidth) {
var textNode = row.firstChild;
var value = '...' + textNode.nodeValue;
do {
value = '...' + value.substr(4);
textNode.nodeValue = value;
} while (row.scrollWidth > row.offsetWidth);
}
}
}
</script>
</head>
<body onload='trimRows();'>
<div id="container" >
<div>first > second > third</div>
<div>second > third > fourth > fifth > sixth</div>
<div>fifth > sixth > seventh > eighth > ninth</div>
</div>
</body>
</html>
Fiddle
Why not just using direction:rtl;
It's a little buggy, but maybe a point in the right direction
http://jsfiddle.net/HerrSerker/ZfbaD/50/
$('.container')
.animate({'width': 450}, 4000)
.animate({'width': 100}, 4000)
.animate({'width': 170}, 4000)
.container {
white-space: nowrap;
overflow: hidden; /* "overflow" value must be different from "visible" */
text-overflow: ellipsis;
width:170px;
border:1px solid #999;
direction:rtl;
}
.container .part {
direction:ltr;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<span class="part">second</span>
<span class="part">></span>
<span class="part">third</span>
<span class="part">></span>
<span class="part">fourth</span>
<span class="part">></span>
<span class="part">fifth</span>
<span class="part">></span>
<span class="part">sixth</span>
</div>
These solutions solve the problem with misinterpreted preceding or trailing weak or neutral BiDi characters such as /, \, ~, ., etc. (basically any punctuation or special characters).
CSS Solution
Use a combination of:
direction: rtl & ltr
unicode-bidi: bidi-override
p {
direction: rtl;
max-width: 180px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; /* or pre (e.g. preserve multiple spaces) */
}
span {
direction: ltr;
unicode-bidi: bidi-override; /* or isolate, isolate-override, embed */
}
<p><span>/path/to/a/very/long/file.name</span></p>
<bdo> Solution
Another possibility uses the <bdo> Bidirectional Text Override element:
p {
max-width: 180px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; /* or pre (e.g. preserve multiple spaces) */
}
<bdo dir="rtl">
<p>
<bdo dir="ltr">/path/to/a/very/long/file.name</bdo>
</p>
</bdo>
Using #Hemlocks, #Brian Mortenson and #Jimbo's solutions, I've built a jQuery plugin to solve this problem.
I've also added support to return the initial value using .html() rather than having it return the current innerHTML. Hopefully it will be useful to someone...
(function($) {
$.trimLeft = function(element, options) {
var trim = this;
var $element = $(element), // reference to the jQuery version of DOM element
element = element; // reference to the actual DOM element
var initialText = element.innerHTML;
trim.init = function() {
overrideNodeMethod("html", function(){ return initialText; });
trimContents(element, element);
return trim;
};
trim.reset = function(){
element.innerHTML = initialText;
return trim;
};
//Overide .html() to return initialText.
var overrideNodeMethod = function(methodName, action) {
var originalVal = $.fn[methodName];
var thisNode = $element;
$.fn[methodName] = function() {
if (this[0]==thisNode[0]) {
return action.apply(this, arguments);
} else {
return originalVal.apply(this, arguments);
}
};
};
var trimContents = function(row, node){
while (row.scrollWidth > row.offsetWidth) {
var childNode = node.firstChild;
if (!childNode)
return true;
if (childNode.nodeType == document.TEXT_NODE){
trimText(row, node, childNode);
}
else {
var empty = trimContents(row, childNode);
if (empty){
node.removeChild(childNode);
}
}
};
};
var trimText = function(row, node, textNode){
var value = '\u2026' + textNode.nodeValue;
do {
value = '\u2026' + value.substr(4);
textNode.nodeValue = value;
if (value == '\u2026'){
node.removeChild(textNode);
return;
}
}
while (row.scrollWidth > row.offsetWidth);
};
trim.init();
};
$.fn.trimLeft = (function(options){
var othat = this;
var single = function(that){
if (undefined == $(that).data('trim')) {
var trim = new $.trimLeft(that, options);
$(that).data('trim', trim);
$(window).resize(function(){
$(that).each(function(){
trim.reset().init();
});
});
}
};
var multiple = function(){
$(othat).each(function() {
single(this);
});
};
if($(othat).length>1)
multiple(othat);
else
single(othat);
//-----------
return this;
});
})(jQuery);
Initiate using:
//Call on elements with overflow: hidden and white-space: nowrap
$('#container>div').trimLeft();
//Returns the original innerHTML
console.log($('#test').html());
fiddle
Using a slightly more complex markup (using the bdi-tag and an extra span for the ellipsis), we can solve the problem fully in CSS, no JS required at all -- cross browser (IE, FF, Chrome) and including keeping punctuation marks to the right:
http://jsbin.com/dodijuwebe/1/edit?html,css,output
Granted, this is something of a hack, involving pseudo-element goodness. However, our team has been using this code in production and we haven't had any issues whatsoever.
The only caveats are: The height of the line needs to be fixed and the background color needs to be known explicitly (inherit won't work).
If you don't care the indexing of those texts, you could use this method (it reverses the text lines):
If you have in your texts other HTML elements besides <br> you need to make some arrangements to use this method.
HTML code:
<p>first > second > third<br/>
second > third > fourth <br>
fifth > sixth > seventh</p>
CSS code:
p{
overflow: hidden;
text-overflow: ellipsis;
unicode-bidi: bidi-override;
direction: rtl;
text-align: left;
white-space: nowrap;
width: 140px;
}
JavaScript code
[].forEach.call(document.getElementsByTagName("p"), function(item) {
var str = item.innerText;
//Change the operators
str = str.replace(/[<>]/g, function(char){ return ({"<" : ">", ">" : "<"})[char] });
//Get lines
var lines = str.split(/\n/);
//Reverse the lines
lines = lines.map(function(l){ return l.split("").reverse().join("") });
//Join the lines
str = lines.join("<br>");
item.innerHTML = str;
});
jsfiddle
Based on your edit:
At this point I'm looking for a work around for the bugs in Chrome
that prevent it from rendering properly when a document is mixed RTL
and LTR. That was all I really needed from the outset, I just didn't
realize it.
Have you looked into the unicode-bidi css property (see Sitepoint or W3C)? I actually just learned about this myself on another recent post. My guess is you would want to use the embed value for those pieces going the opposite direction to the main site. So in j08691's answer where it is direction: rtl add unicode-bidi: embed to the CSS. This should solve "mixed RTL and LTR" issues you are having.
I put some JavaScript together to regex out three items and add the ellipsis in where necessary. This does not explicitly look at how much text will fit in the box but if the box is fixed this may not be an issue.
<style>
p {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width:170px;
border:1px solid #999;
direction:rtl;
text-align:left;
}
</style>
<p>first > second > third<br />
second > third > fourth > fifth > sixth<br />
fifth < sixth < seventh < eighth < ninth</p>
<script>
var text = $( 'p' ).text(),
split = text.split( '\n' ),
finalStr = '';
for( i in split ){
finalStr = finalStr.length > 0 ? finalStr + '<br />' : finalStr;
var match = /(\w+\s?(<|>)?\s?){3}$/.exec( split[i] );
finalStr = finalStr + ( split[i].length > match[0].length ? '...' : '' ) + match[0];
}
$( 'p' ).empty().html( finalStr );
</script>