multiple contenteditable elements, using arrow keys to navigate - javascript

I got multiple <p contenteditable="true"></p> elements on a page. I'm looking for a solution to use arrow keys for navigating across those disjoint elements just as if they were one single editable element.
So for instance, if the caret is at the 10th character on the last line of the 1st paragraph and the user hits the down arrow key, the caret should jump to the 2nd paragraph and place the caret at the 10th character (if there's one) on its first line.
Appreciate any comments.

Revised answer
You can detect that the caret is at the start or end of the current editable element by using something like the following (example is for down array on the last line):
Detect the down arrow keydown event
Check if the caret is at the end of the paragraph by doing one of the following:
Create a Range (or TextRange in IE) from the selection object and comparing it to another Range that encompasses the whole paragraph. This is the slightly trickier but more seamless option. OR:
Store the selection and set a brief timer (say 1 millisecond) to allow the keypress to take effect. The function passed to the timer calls compares the current selection with the previously stored selection. If they're the same, the caret has not moved and must have been at the end of the paragraph.
If the caret is at the end of the paragraoph, move it to the start of the next editable paragraph.
This isn't the the usual behaviour of the caret but is reasonably easy to achieve and could be a reasonable compromise. The problem is that there's no reliable cross-browser way to work out the caret's coordinates.

What if you would make the container element editable, instead of every single paragraph?
For example:
<div contenteditable="true">
<p>Lorem ipsum</p>
<p>dolor sit</p>
</div>

Related

Is it possible to capture the value prior to an input type insertReplacementText event in a textarea?

When an insertReplacementText input event type, as defined in this W3C Editor's Draft, takes place on a textarea element, the data property or attribute provides the text that was added to the textarea value, replacing some other text, such as when right-click on a misspelled word and the context menu provides suggested words.
The misspelled word does not have to be selected first; and, if the textarea has the focus (the cursor could be far from the misspelled word), when the right click takes place, the cursor is not moved at all.
After the replacement, the cursor is positioned to the right of the new text, as in a paste event. The difficulty is determining the length of the text that was replaced and or it's value.
I ask because I'd like to capture the needed information to undo/redo this event.
Thank you.
Update:
If you maintain a copy of the last value of the textarea in RAM or other lcoal storage options, then there is a way to accomplish this; although the event itself provides little data. I was rather stupid at first, as I was testing this in a separate piece of code, because I forgot that, in the code of my particular project, there is always in RAM a copy of the last value in the textarea. Having that information makes this operation very similar to a paste event when there is a selection before the paste that is replaced by the pasted text. After the replacement is performed, the cursor is positioned immediately to the right of the last character of the replacement text. The data property of the insertReplacementText event contains the value of the inserted text.
Thus, it is a matter of arithmetic involving the length of the new text, the difference in the length of the previous copy of the textarea value's length and the length of the DOM element's value after replacement, and the cursor position after the replacement has been performed. The difference in the length's of the textarea values is the difference in the length of the old text and new text. This provides the selection range from which to extract the old text from the saved copy before updating the copy to the new value. The selectionStart is the same for both the old text and new text; the difference is in the selectionEnd based on the lengths, if not equal.
As long as the browser keeps positioning the cursor to the right of the last character of the replacement text, and you maintain a copy of the last value of the textarea, it appears that this ought to work.
Thank you.

Other than by wrapping each character with an html element, is there a way in javascript/jquery/etc to tell which letter in an element was clicked on?

Other than by wrapping each character with an html element, is there a way in javascript/jquery/etc to tell which letter in an element was clicked on?
Say you've got a heading -- "<h1>Happy</h1>" -- how can you tell which letter was clicked on, i.e., the user clicked on the second p or the a --without tag-wrapping each letter.
All the solutions that I've found suggest wrapping each letter in an html element (presumably a span), but that requires some pretty horrific html (even if you automate generating it) -- i.e., <h1><span id="letter00>H</span><span id="letter02">a</span><span id=letter03>p</p>...etc...</h1>. Surely there is someway to record letter positions as the rendering engine is drawing them and then relating those to clicks in the viewport.
I think if you used an <input type="text"> you have a selectionStart property which contains the character index of where your cursor is at. With html you can modify the textbox to remove the border and such so it doesnt look like a textbox. selectionStart and selectionEnd will help you figure out if any of the text is highlighted as well.

Create new textarea when current textarea reaches the end

I want to have a textarea pass along any overflowing text to another textarea which is added after the current one, like how a word processor creates a new page when you reach the end of the current page. I've thought about how to achieve this and the first thing that comes to mind is to add a new textarea after reaching the end of the current one and place the cursor at the start of the new one. The only thing is, I don't know how I would go about processing certain events such as:
Select text across multiple textareas.
Paste text near the end of one textarea and correctly split it so that part of the text is pasted in a new textarea.
Remove empty textareas except the first one.
Is there an easier way I could go about doing this? Is there any way I could perhaps style a single textarea so that it just looks like there is a space between two lines to give the illusion that there are more than one textareas (that I could also style individually)?

Save caret position after html changes in contenteditable div

I am trying to create a div where, when the user right clicks on a word, it becomes red. This div is editable, so the user can change the text in it.
<div contenteditable="true" id="test"><span class="word">text</span></div>
So far, what I have done is, every time the event listener "input" is called, I loop through all the spans in the div and use regular expressions on their content to match them with (spaces)(words) or (words)(spaces). Then, i add a new span after the current one that contains the second matched part, and replace the content of the current span by the first matched part. I also add the class word to the span that contains the words, depending on the expression that was matched.
So Far this approach words, and I am able to right click on individual words to either put them in red or not.
My problem however is that when I insert and remove spans inside my contenteditable div, the location of the caret changes. The reason for this is probably because the length of the html inside the div changes more than the length of the text.
How could I make it so that after I type, paste or remove some text in the div, and that after my function separates the spaces from the characters in different spans, the caret remains exactly where it was.
In other terms, I would like to store the current caret position, modify the html(not the text) of my div, and then restore the previous caret position.
Does anyone have an idea regarding how I could proceed? Thanks for the help!

How do I move the caret in a Window.selection() textbox?

I can identify my currently focussed textbox with Window.selection:
var selection = window.getSelection();
I can identify the caret position with Selection.focusOffset:
var focus = selection.focusOffset;
Let's say that focus is currently 8, so the caret is 8 characters in.
How do I move the caret position, so it's e.g. 5 characters in?
Example method:
selection.setFocusOffset(5); // this method does not exist, so I need something similar
The Selection.extend() and Selection.modify() methods are able to move around the caret to some extend, but in my usecase where I manipulate and replace content inside the selection I need a more simple way to just determine how many characters in I want to place the caret. Btw: my textbox is a wysihtml textarea, which means that it's not technically a textarea div.
If I'm understanding correctly, you are wanting to change the start offset of focus, but Selection.extend() is only used to change the end offset. Since Selection.modify() is not on any standards track, there will not be a "simple way".
You will need to use Selection.getRangeAt() which returns a range object. Use the range objects API to set the start offset of your returned range, then use Selection.addRange() to make the new selection. You may want/need to removeRange() to clear the previous selection. I don't know how the browsers would handle overlapping selections.

Categories

Resources