Find a word line number in a paragraph with JavaScript - javascript

Let's say I have a very long paragraph. When I click on a line, JS/jQuery will add an empty <span> tag at the beginning of this specific line - right before the first word in this line.
f.e: This is my paragraph:
<p>
It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has.
</p>
When I click the second line, a <span> tag will be insert before the first word in the second line.
Any ideas how to do it?

jQuery can't detect where a wrapped line occurs, unless it happens with a hard-coded break (<br /> or similar).
That said, there is one option, although it's a little hacky.
Duplicate the container
Give it a left of -3000 (to make it invisible, without using display:none because that gives it 0 height)
Remove one word at a time (using .lastIndexOf(' ')), and measure the height each time. When it resizes to the smallest non-zero height, that's where you want to insert your <span>, so then...
.substring() with the position you've just found - .substring(0, position) + '<span>' + .substring(position)

Hello Friend You can find the possible duplicate here in the following link
Get caret position in contentEditable div
Hope this solves your problem.

Related

Contenteditable div set caret after replacing text with HTML

I'm trying to make a web-based code editor, and I came up with a way to sweep the entire text and replace anything that matches my super simple regex to colored HTML. See it here:
$("#text-area").on('keyup', function(e){
var html = $("#text-area").html();
var filter = html.replace(/function/g, '<span style="color:pink;">function</span>');
$("#text-area").html(filter);
});
I spent hours digging stackoverflow and found similar situations, but subtly different that I can't apply to my situation here. Here is the problem:
1) Once I sweep the text and replace selective words to colored HTML, the caret is returned to the beginning of the div.
2) Since it is a code-editor(reading other files), I need white-space: pre or pre-wrap. But then caret positions are the same for any number of line breaks, so the caret doesn't move and new lines are just added below the caret, and from any new empty line it jumps up to whichever line isn't empty.
I have the simplified version of my situation in the JSFiddle
There is better ways but this is the close solution I got to yours.
Have something have something like when you detect the word you like:
<div>
<span class="normal_text"> First part </span>
<span style="color:pink;">function</span>
<span class="normal_text"> | </span>
</div>
And in the end put the selection equal to range with offset 0 and focus node as the last span. Your function looking for the word "function" should also be listening the last span only to repeat everything.

Keep caret position in contenteditable after editing the content via jscript

I've got a contenteditable div which's content is being edited via javascript after each textchange(textchange.js) like adding html tags(only span-tags for changing the color of some words) and adding or removing some whitespaces here and there, but my problem is since the content is being changed while the user is editing it, the caret changes its position after every keypress, which makes it nearly impossible to write a single word.
I'm at the moment searching for a way to prevent this jumping around, I've already thought of adding a special char which wouldn't be used anyway as a kind of marker at the position of the caret before editing it, removing it when finished and putting the caret back to this position, but since I'm using regex a lot(currently about 25 times after each textchange) this special character would ruin nearly every single one of them and I would have to add something like \x40? every where, which would not look nice and clear at all:
/\s<span class="b0">hello\sworld</span>/g
to:
/\s\x40?<span class="b0">\x40?h\x40?e\x40?l\x40?l\x40?o\x40?\s\x40?w\x40?o\x40?r\x40?l\x40?d\x40?</span>/g
I don't know if it helps but here is an example on how the content is changed(after each keypress):
foo +++ <span class="c3">bar</span> - baz -<span class="c0">qux</span>
to:
<span class="c1">foo</span> + <span class="c3">bar</span> - <span class="c1">baz</span> * <span class="c0">qux</span>
I'd be grateful for every advice, tip or hint on how to solve this problem, or a better way to do this marker-thing.
Thank you :)
Probably this is not the best solution, but I created 2 divs, one to display the text and other to edit it, the second one above the first one and with some level of transparency.
Like this:
<div style="position: absolute; left: 48px; top: 16px;" unselectable="on" onselectstart="return false">
<code id="code_show">Type here.</code>
</div>
<div style="position: absolute; left: 48px; top: 16px;">
<span style="opacity:0.33"><code id="code_area" contenteditable="true" onkeyup="colorize();">Type here.</code></span>
</div>
The onselectstart="return false" and the unselectable="on" ensure that the first one is not selectable. The onkeyup="colorize();" ensures that the javascript function colorize is called everytime that the user presses a key to edit the text.
So you have to define it to update the contents of code_show to match the ones in code_area but with colors.
For instance, this code paints every word RED in red color:
<script>
function colorize(){
var code_area= document.getElementById('code_area');
var code_show= document.getElementById('code_show');
var inner= code_area.innerHTML;
inner= inner.replace(/RED/g,"<span style=\"color: red\">RED</span>");
code_show.innerHTML= inner;
}
</script>
You could create an abstraction that would add special characters to otherwise readable regexes. It's simple and presumably requires minimal changes to your current code.
There might be a more elegant solution though. If you never replace text that has a caret in a middle of it - as in repl|aced - you could split the original string into two and apply the filter on both parts. The caret position remains at the division, that is at length of the first gist.
If you do however need to replace even at caret position, you could start with the split anyway. After that, run the filters again, one by one. If the filter matched, move caret to a predetermined relative position - say to replaced ++|+ (pipe denoting the caret) with ××. You could even let it be, which would result in ××|. Or have a hardcoded relative caret move for each filter, which is great if you do code replacements, because you can move the caret to proper location (say you replace <|i></i> with <em>|<em>; notice the caret conveniently moved to where the user would probably want it).

How to measure word/caret position in Google Docs?

For those who haven't worked with the Google Docs editor here's a short explanation of how it works:
Google Docs has no visible editable textarea or contentEditable elements.
Google Docs listens for keydown/press/up in a separate iFrame where they place the OS cursor for event listening.
When the iFrame catches an event Google handles it by performing the equivalent operations on the visible document.
The "caret" in Google Docs is a DIV that is styled and scripted to look and act like an OS cursor.
With that out of the way, here's my request:
I'm working on a plugin that interacts with the Google Doc and I need to be able to do two things:
Highlight words with an opaque overlay DIV.
Determine cursor position inside a word.
I've been exhausting a lot of ideas about just how to handle this, but so far I've only manage to get a buggy solution for the latter problem (I perform a backspace, determine where the text changed and undo the backspace).
I'm looking for all the best ideas you can come up with to solve these problems. They don't need to be cross browser, but they do need to be able to be turned into something robust that will also handle things such as font size changed mid line.
A little bit of extra info explaining what a Google Doc looks like in HTML:
<wrapper> // Simplified wrapper containing margins, pagination and similar
<div class="kix-paragraphrenderer"> // single DIV per page wrapping all content
// Multiple paragraphs separated by linebreak created by Enter key:
<div class="kix-paragraphrendeder">...</div>
<div class="kix-paragraphrendeder">...</div>
<div class="kix-paragraphrendeder">
// Multiple wrapper divs created by Google's word wrapping:
<div class="kix-lineview">...</div>
<div class="kix-lineview">...</div>
<div class="kix-lineview">
// Single inner wrapper, still full width of first wrapper paragraph:
<div class="kix-lineview-content">
// Single wrapper SPAN containing full text of the line, but not display:block
<span class="kix-lineview-text-block">
// Multiple spans, one per new font change such as normal/bold text,
// change in font size, indentation and similar:
<span>This is normal text</span>
<span style="font-size:40px; padding-left:4px;">This larger text.</span>
<span style="font-weight:bold; padding-left:10px;">This is bold text</span>
<span style="padding-left:4px;">More normal text</span>
</span>
</div>
</div>
</div>
</div>
</wrapper>
After more tinkering I came to the conclusion that it is extremely troublesome - if not impossible - to try and programmatically determine cursor position with regard to a letter inside a <span>, simply because the <span> is the smallest element that is measurable (correct me if I am wrong).
So how to solve the problem? Here's what I ended up doing:
I create an offscreen positioned <div>
I get the text of the current paragraph (<div class="kix-paragraphrenderer">) - I could get the entire text, but wanted to limit the computational load.
I extract each single character of the paragraph by looping through its children in the following way:
Loop through linveviews of the paragraph (<div class="kix-lineview">)
Get the lineview content (<div class="kix-lineview-content">)
Loop through text blocks of the lineview content (<span class="kix-lineview-text-block">)
Loop through <span>'s of the text block
Loop through innerText of the <span>
I append each character in my offscreen <div> with the currently applied style extracted from style.cssText of the current <span>
For each character appended I measure the width of the <div> and save this in an array. I now have a position of each single character.
I measure the position of the cursor relative to my widths and voila - I know where the cursor is positioned in the text.
This is obviously a bit simplied (I left out details about margins and paddings of the different elements), but it covers the idea behind how it's possible to get the cursor position.
It works quite well, but there are many pitfalls and a lot of measuring required. On top of that it's also required to post-parse the text if you want to use it for anything, since tabs, spaces and linebreaks aren't always included in innerText (depending on where these are in the text, Google may or may not make them through positioning of new elements).
I made something like Kix two years ago Google Docs. And for any HTML design and yes, for IE6 too :-) How? All we need is to compute letter absolute position. How? Replace textNode with inline element without layout, that's important, and then use Element.getClientRects I remember I also needed wrap just letter and compute its position via fast and reliable https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect
The trick how to detect lines and wraps for home and end keys was based on some vertical heuristic letter position change. Something like if base line is different, than stop caret walking. It was pretty fast and with any markup and without any caching. Holy grail :)
The only not resolvable problem was justified text, because letters were distributed randomly and spaces between them was not computable.
That project is dead http://webeena.com now. Bad management killed it (and me almost too).

Using Javascript or CSS, how can I add additional space at the end of a block of text, but only if it does not start on a new line?

Let's say I have some text, with a (more)... link at the end of each paragraph. It ends up looking something like this:
This is just a test paragraph. Click on the more link for more info. (more...)
Now I'd like to add some space between the link and the paragraph text, so I wrap the link in a <span> tag and push it to the right with a margin-left: 10px:
This is just a test paragraph. Click on the more link for more info. (more...)
The problem here is, if the text wraps right on the more so that it shows up on a second line by itself, it will look indented:
This is just a test paragraph. Click on the more link for more info. Push it down!
(more...)
When the desired output should be:
This is just a test paragraph. Click on the more link for more info. Push it down!
(more...)
Is it possible to achieve this effect using either Javascript or CSS?
Side note: It is possible to achieve this effect by removing the <span> tag and using &nbspcharacters to push the more linke to the right with proper text wrapping, but this is a solution I'd like to avoid unless there is no other choice. Or I could use Javascript to insert the &nbsp's before the span, but that's not exactly a nice solution either.
You could set a width on the paragraph and then float the span to the right.
That way the (more...) remains on the the right always.
Not exactly what you are after but I think it looks decent.
Example: http://jsfiddle.net/WFuBd/1/
If you wrap the content before the link in a span and apply a margin-right to that, you'll get the desired effect. (Unfortunately, this, too, is not really a nice solution)
Why not use 2 div's. Div one floats left, div two floats right... Make sure overflow=hidden on div one, and (more...) is on div two.
[div 1 lots of text i.e.: 300px] [div 2(more...) i.e.: 40px]
It will look perfect every time. You'll have to play around with it to look right, but it'll work. You could then just do a little jQuery when you click more...to show the rest and hide 'more'.

javascript string clicked position

If I have a string in a div
<div id="article">
lots of text goes here
<strong> it's really interesting</strong>
and it's free to read
</div>
if a user double click or single click on a particular word, is there a way to determine the position/index of the character clicked?
If that cannot be done, how about determining how many space character there are before the clicked position. So if I click on the word 'goes' in the above example, it returns 3 because there are three spaces before the word goes which is clicked.
Thank You very much for your time.
The ugly hack solution to such a problem involves programming converting the characters into event capturing objects.
For instance
<div id="article">
<span>lots </span><span>of </span><span>text</span>...
</div>
Now this can be done programmatically.
You can grab whatever the current content of a div and convert it to something like the formatting above. Then attach event handlers to the contained spans which count the number of spans preceding it in the same container.
a way to determine the position/index of the character clicked
Well, first I need to use a fixed width size font like Courier.
Then, I'd create two span with only a char each. With those two, I should be able to know the width of a char (beware padding and margin) and its height.
Then, you need to know your upper left coordinates for your div whose id is 'article' and capture click event with event.x and event.y.
After that,
var line = (event.x - divLeft) / charHeight;
var column = (event.y - divTop) / charWidth;

Categories