Rangy applyToSelection at the cursor if the selected range is empty? - javascript

This feels like a stupid question.
I'm using the excellent Rangy library in javascript to apply CSS classes from a dropdown to selected text, as if in a rich text editor.
But if the user is simply typing text without making a selection, and they apply a class via a dropdown, rangy's "applyToSelection" does nothing since,presumably, it's an empty range.
I know there are difficult ways to add a proper div at the selected cursor location and enter into it, but, before I embark on those, am I missing a simple way to do it, either using Rangy or normal JS?
Thanks!

Here's the code I ended up with, which worked perfectly in IE11 but has not been tested in other browsers yet:
var actual_textarea = document.getElementById("my_input_textarea");
actual_textarea.focus();
var selectedInstance = this.ne.selectedInstance;
var range = selection.getRangeAt(0);
range.deleteContents();
var new_div = document.createElement("div");
new_div.innerHTML = "<div class='" + this.rangyClassPrefix + elm + "'></div>";
var frag = document.createDocumentFragment();
var node, lastNode;
while (node = new_div.firstChild)
{
lastNode = frag.appendChild(node);
}
range.insertNode(frag);
if (lastNode)
{
range = range.cloneRange();
range.selectNodeContents(lastNode);
range.collapse(false);
selection.removeAllRanges();
selection.addRange(range);
}
Notice that I set focus first since the style is being applied by focus-changing clicks on other elements.
I'm still a little fuzzy at the thought of range clones being value rather than reference clones but still working perfectly when added, since that's counterintuitive, but it does work.
Thanks!

Related

Set the caret at the end of the content in Froala 2

I'm using Froala 2 and the documentation doesn't seem to have anything that implies a simple way to set the location of the caret, let alone at the beginning or end. I'm trying to seed the editor instance with a little content in certain cases and when I do using html.set, the caret just stays where it is at the beginning and I want to move it to the end. The internet doesn't seem to have anything helpful around this for v2.
Froala support provided an answer for me that works:
var editor = $('#edit').data('froala.editor');
editor.selection.setAtEnd(editor.$el.get(0));
editor.selection.restore();
As far as I know, Froala 2 doesn't provide any API to do this, but you can use native JavaScript Selection API.
This code should do the job:
// Selects the contenteditable element. You may have to change the selector.
var element = document.querySelector("#froala-editor .fr-element");
// Selects the last and the deepest child of the element.
while (element.lastChild) {
element = element.lastChild;
}
// Gets length of the element's content.
var textLength = element.textContent.length;
var range = document.createRange();
var selection = window.getSelection();
// Sets selection position to the end of the element.
range.setStart(element, textLength);
range.setEnd(element, textLength);
// Removes other selection ranges.
selection.removeAllRanges();
// Adds the range to the selection.
selection.addRange(range);
See also:
How to set caret(cursor) position in contenteditable element (div)?
Set caret position at a specific position in contenteditable div

Move selection after a DOM element

I'm currently building a Markdown editor for the web. Markdown tags are previewed in realtime by appending their HTML equivalents via the Range interface. Following code is used, which should be working according to MDN:
var range = document.createRange()
var selection = window.getSelection()
range.setStart(textNode, start)
range.setEnd(textNode, end + 2)
surroundingElement = document.createElement('strong')
range.surroundContents(surroundingElement)
var cursorRange = document.createRange()
cursorRange.setStartAfter(surroundingElement)
selection.removeAllRanges()
selection.addRange(cursorRange)
Firefox works: Some bold text
Chrome not: Some bold text
Any suggestions what could be wrong? Information on this subject are rare.
Answer
Thanks to #Tim Down, I fixed it using the invisible character workaround he describes in one of the links mentioned in his answer. This is the code I'm using now:
var range = document.createRange()
range.setStart(textNode, start)
range.setEnd(textNode, end + 2)
surroundingElement = document.createElement('strong')
range.surroundContents(surroundingElement)
var selection = window.getSelection()
var cursorRange = document.createRange()
var emptyElement = document.createTextNode('\u200B')
element[0].appendChild(emptyElement)
cursorRange.setStartAfter(emptyElement)
selection.removeAllRanges()
selection.addRange(cursorRange)
The problem is that WebKit has fixed ideas about where the caret (or a selection boundary) can go and is selecting an amended version of your range when you call the selection's addRange() method. I've written about this a few times on Stack Overflow; here are a couple of examples:
Set cursor after span element inside contenteditable div
How to set caret/cursor position in a contenteditable div between two divs.

How to set cursor position in contenteditable span

I have a span, it becomes editable after double clicking on it. However, some text is selected due to double click and I remove that selection using this code:
function removeSelectedText(element) {
if (window.getSelection || document.getSelection) {
oSelection = (window.getSelection ? window:document).getSelection();
oSelection.removeAllRanges();
} else {
document.selection.empty();
}
}
After this operation, now-editable non-selected span loses focus. All I want to move the caret to the last clicked place in the span. I try the code below but didn't work ('element' is span itself):
...
var selection = (window.getSelection ? window:document).getSelection();
var position = selection.getRangeAt(0).focusOffset;
element.focus();
var range = document.createRange();
range.setStart(element, position);
range.setEnd(element, position);
range.collapse(true);
selection.removeAllRanges();
selection.addRange(range);
I try whatever I found but couldn't get it working. I can't focus it anymore due to frustration. That would be awesome if you help me...
UPDATE: In range.setStart() and range.setEnd(), element.firstChild should be used instead of element.
A similar problem and its solution is here, I am surprised for finding it in the second day of search considering my offensive search yesterday. Any better solution is welcomed, since even this one cannot bypass text selection at first double click.

How to select everything inside a span tag, including the span tag itself?

I have a contenteditable div, in which I have a span tag, which contains some text. How do I select the span tag and all of its contents, so when the user presses backspace or delete, the span and its contents get removed?
UPDATE: When I say select, I mean highlight. Sorry for the inconvenience.
UPDATE 2: I'm thinking along the lines of 'element.outerHTML.select()'. See if that helps.
In Firefox you have the Selection API which allows you to do that. Combine it with the DOM2 Range API and you have what you want:
var r = document.createRange();
r.selectNode(domElement);
var s = window.getSelection();
s.removeAllRanges();
s.addRange(r);
The Selection API found its way in a future standard, HTML Editing APIs, but it will be a while until it becomes available in a majority of browsers.
yesterday I answered your other question. I revised the jsfiddle accompanying that answer, please recheck it. Use shift+delete from within an editable span to bring up a dialog and to 'select' the current span.
Try this:
var span = document.getElementById("myspan");
span.onclick = function() {
var range = document.createRange();
range.selectNodeContents(span);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
};​

get range and coordinate of selected text

How to select the text of the page in FireFox?
For example, there's a paragraph of text, user select the text in those paragraph in a regular way.then, I want to know in which paragraph the text selected by user (in which position-xy coordinates, range position).
You've asked about selection coordinates twice before. I know I've given you a working answer, so why are you asking again?
Here's some code that will return you the innermost element containing the selection in Firefox (assuming a single selection; Firefox allows multiple selections). Hope it's helpful.
function getSelectionContainerElement() {
var sel = window.getSelection(), el = null;
if (sel.rangeCount) {
var range = sel.getRangeAt(0);
el = range.commonAncestorContainer;
if (el.nodeType != 1) {
el = el.parentNode;
}
}
return el;
}
refer the getSelection(), to get an object which contains information about the selected text and its position in the parent Element
Selection - MDC might help you to find answer of all your questions.
You can find the exact answer here
but this module is under construction, You can browse project and find this module.

Categories