Get length of last incomplete line of text in div - javascript

Given a div that contains a lot of text that may or may not wrap, I'm looking for the x position of the end of the text in said div. This is user generated text so I don't know what's going to be in it, and also, it needs to be XSS safe, so I cannot use <span> elements in my code because a user could write some script that could execute.
The solutions given here are great, but would allow for unsafe scripts to potentially execute in the browser.
find out length of last incomplete line of text in container
Ideally, I would have a method with a signature something like this:
int getPixelsFromLeftMostSideOfDiv(Element e)

this should be XSS safe assuming that the way you put the user text on the screen is XSS safe.
It follows your linked solution's method of appending a span to the div and getting the x position of that span. Ie
var text = document.getElementById('text');
var span = document.createElement('span');
text.appendChild(span);
console.log(span.getBoundingClientRect().left);
JSFiddle attached for you to play with
https://jsfiddle.net/1d29c24d/1/

Related

Javascript: Get text in a contenteditable up to the caret

I'm surprised I'm having trouble with this and unable to find an answer. I'm trying to get the text in a contenteditable, from the start of the contenteditable to the users cursor/caret.
Here's a jsFiddle of what I've attempted (click around the contenteditable and watch console.log).
I get the caret location and then I attempt to get the content:
I tried using textContent of the contenteditable which works but if there's content like foo<br>bar it outputs foobar when ideally it should output foo\r\nbar (Note: This is for a chrome extension I have no control over the content of the contenteditable).
innerText works as expected outputting foo\r\nbar, but as can be seen in the jsFiddle once the html in contenteditable gets a little complex the caret position doesn't seem to match the location in innerText and I have trouble outputting up to the caret.
Found some code using the Range interface and modified it to meet my needs in this jsFiddle but had the same problem with <br> as textContent did.
Note: The user will continue typing as I get the content, so looking for something that doesn't break this flow.
Just looking for direction, any quick tips on what I should try?
In your fiddle I replaced the JavaScript content with:
document.querySelector("#edit").addEventListener("click", function(){
var target = document.querySelector('#edit');
var sel = document.getSelection();
if(!sel.toString()) {
var range = document.getSelection().getRangeAt(0);
var container = range.startContainer;
var offset = range.startOffset;
range.setStart(target, 0);
//do your stuff with sel.toString()
console.log(sel.toString());
//restore the range
range.setStart(container, offset);
}
});
Hope this helps.
Edit: since you said
Note: The user will continue typing as I get the content, so looking for something that doesn't break this flow.
I thought that the click event was just an example; getting the text while user is typing implies:
the entry point can't be click event but probably a setInterval function
while user is typing there is no selections, only the caret
To solve the reported bug is enough changing the code as I did, anyway this is only an example to get the result you are interested in; than you have to work on it to achieve the desired behavior for all the possible case of your real scenario.

Parsing plain text Markdown from a ContentEditable div

I know there are other questions on editable divs, but I couldn't find one specific to the Markdown-related issue I have.
User will be typing inside a ContentEditable div. And he may choose to do any number of Markdown-related things like code blocks, headers, and whatever.
I am having issues extracting the source properly and storing it into my database to be displayed again later by a standard Markdown parser. I have tried two ways:
$('.content').text()
In this method, the problem is that all the line breaks are stripped out and of course that is not okay.
$('.content').html()
In this method, I can get the line breaks working fine by using regex to replace <br\> with \n before inserting into database. But the browser also wraps things like ## Heading Here with divs, like this: <div>## Heading Here</div>. This is problematic for me because when I go to display this afterwards, I don't get the proper Markdown formatting.
What's the best (most simple and reliable) way to solve this problem as of 2015?
EDIT: Found a potential solution here: http://www.davidtong.me/innerhtml-innertext-textcontent-html-and-text/
if you check the documentation of jquery's .text() method,
The result of the .text() method is a string containing the combined text of all matched elements. (Due to variations in the HTML parsers in different browsers, the text returned may vary in newlines and other white space.)
so getting whitespaces is not guaranteed in all browsers.
try using the innerText property of the element.
document.getElementsByClassName('content')[0].innerText
this returns the text with all white spacing intact. But this is not cross browser compatible. It works in IE and Chrome, but not in Firefox.
the innerText equivalent for Firefox is textContent (link), but that strips out the whitespaces.
This is what I've been able to come up with using that link I posted above in my edit. It's in Coffeescript.
div = $('.content')[0]
if div.innerText
text = div.innerText
else
escapedText = div.innerHTML
.replace(/(?:\r\<br\>|\r|\<br\>)/g, '\n')
.replace(/(\<([^\>]+)\>)/gi, "")
text = _.unescape(escapedText)
Basically, I'm checking whether or not innerText works, and if it doesn't then we do this other thing where we:
Take the HTML, which has escaped text.
Replace all the <br> tags with line breaks.
Strip out any tags (escaped ones won't be stripped, i.e. the stuff the user types).
Unescape the escaped text.

Javascript : Close open HTML tags in a string

I have a javascript string that has HTML code. I display it and I have attached a read more/less toggler based on the number of words. The problem is, when I shrink the HTML code, it might have open tags, for suppose
<p>A computer is a general purpose device that can be <b>programmed</b> to carry out a finite set of arithmetic or logical operations</p>
when shrinked becomes
<p>A computer is a general purpose device that can be <b>programmed...more</p>
Because of unclosed bold tag, the following data becomes bold.
I want a javascript solution to close the unclosed tags in a string. Any kind of help is highly appreciated. Thank you all in advance.
Use this code
function fixHtml(html){
var div = document.createElement('div');
div.innerHTML=html
return (div.innerHTML);
}
using
var fixed = fixHtml("<b>some text")
will return
<b>some text</b>
The "...more" should not even be in the paragraph. Try adding it separately, out of the paragraph.
You might want to wrap everything in a div instead, and shrink that.
<div class="shrinkable">
<p>A computer is a general purpose device that can be <b>programmed</b> to carry out a finite set of arithmetic or logical operations</p>
<span class="see-more">...more</span>
</div>
I ran into the same problem and used the following solution. I adjusted it to your example.
var divContent = document.createElement('div');
get the html from the div you want to shrink
var get_html = $('.shrinkable').html();
use innerHTML, this takes care of any open tags in the html
divContent.innerHTML = get_html;
replace the html and add the see
$('.shrinkable').html(divContent.innerHTML).append('<span class="see-more">...more</span>');

Get css width from a string

I have a string that I want to display on a web page that is dynamically passed in. I want to be able to dynamically determine the css width needed to display this string and then wrap it in an html element with the exact size needed to display it.
I am currently using javascript and dojo, so answers using those two are fine, but anything else won't work.
More Detail
I guess I should clarify. I want to display the string in an input field, so not as simple as a div (I think at least)
If you're wanting to set the <input> length to show all characters in the string, you can set it like so:
var myString = "abcdefg"; // this is what got input dynamically
var myInputElement = document.getElementById('someInput');
myInputElement.size = myString.length;
Since usually a good measure of characters are by em.
You can do this;
var element = Document.getElementById("ID");
element.style.length = element.value.length + " em";
You have to remember that before calculating the string's pixel width with regards to it's character count you have to somehow be aware of the metrics on the font used.
If then, you were to take the input string, wrap it in a <span>, embed it in the document, calculate the element's width, then remove the span and add the value to it's final destination you'd have a pretty decent projection of the intended width as long as your span has the same font style rules as the destination element.
If you want to get really fancy and technical about it, then the HTML 5 <canvas> tag is your friend.
A good article to better understand the complexity of font metrics in javascript which will also help you solve this: http://mudcu.be/journal/2011/01/html5-typographic-metrics/#measure
you can create an element and put some callback in it's load event
var span = $("<span/>").text("your input").load(function(e){
console.log($(this).width());
});
this way you can get the current width. don't define any width for the span element and don't float.

Is there a way to lengthen a <textarea> by one row every time the user types in the next row with javascript?

I have a <textarea> that I want to grow by one row every time the user enters into the last row shown in the <textarea>. Is this possible?
I have seen it done before, but can't figure out how to do it.
Okay, I just created this off the top of my head, so there may be browser compatibility issues. The concept is pretty simple however. Basically, on every keyup event, append a newline to the current text in the textarea element, then check if scrollHeight is greater than offsetHeight. If this is the case, set the elements height to be equal to scrollHeight. After all this, remove the appended newline. Assuming your textarea element has the id ta:
EDIT -- Okay, my original idea caused the cursor position to jump to the end of the text even if the user moved the cursor back, not good. The fix I came up with involves creating an invisible clone of the text area, and inserting the extra newline in that one, as to not disturb the cursor position in the visible one. Not sure I'm enterily comfortable with this method, but it works for now. If there is a better method I'd be happy to hear it. Here's the updated code:
var shadow = document.createElement('textarea');
shadow.className = 'autosize';
shadow.style.visibility = 'hidden';
document.getElementById('ta').onkeyup = function() {
this.parentNode.appendChild(shadow);
shadow.value = this.value + '\n';
if (shadow.scrollHeight > shadow.offsetHeight) {
this.style.height = shadow.scrollHeight + 'px';
}
this.parentNode.removeChild(shadow);
};
And the updated test http://jsfiddle.net/7wezW/1/
Now back to your regular programming...
Works well in Chrome, if someone points out issues in other browsers, I will try work them out.
PS, I should point out that if the user pastes text using just the mouse, the size of the textarea element will not adjust. Should be a trivial issue, but I'll leave it out as not to over-complicate things.
There are code and a demo at http://webdesign.torn.be/tutorials/javascript/prototype/auto-expand-contract-textarea/.
There's also a non-IE6 version that doesn't use frameworks:
http://scrivna.com/blog/2008/04/12/javascript-expanding-textareas/
Yes, there are many plugins for JQuery, such as this one, which comes with a demo: http://james.padolsey.com/javascript/jquery-plugin-autoresize/
Very customizable in terms of maximum height, buffer space, etc.

Categories

Resources