Javascript Set Caret in ContentEditable Div - javascript

I have a div tag that is contenteditable so that users can type in the div. There is a function that adds a link into the div when the user presses a button. I would like the caret to be positioned after the link so that users can continue to type. The link can be inserted many times.
Example Code:
<div id="mydiv" contenteditable="true" tabindex="-1">before link after</div>
I require this code to work in: IE, Firefox, Opera, Safari and Chrome.
Can anyone offer any help?

Assuming you have a reference to the <a> element you've inserted in a variable called link:
function setCaretAfter(el) {
var sel, range;
if (window.getSelection && document.createRange) {
range = document.createRange();
range.setStartAfter(el);
range.collapse(true);
sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (document.body.createTextRange) {
range = document.body.createTextRange();
range.moveToElementText(el);
range.collapse(false);
range.select();
}
}
setCaretAfter(link);

I looked inside the CKEditor (http://ckeditor.com/) code and found that it has an appendBogus() function as well as inserts an extra <br><span> </span></br> that is then deleted.
The problem of course is that Gecko/IE browsers also have nuances about how <br> tags work too (i.e. whether to use \r or \n to insert into the range vs. adding an <br> element)
You can read through the _source/plugins/enterkey/plugin.js to see the different nuances with handling IE & Gecko. It seems like one big hack...

Related

IE11 drop plain text into contenteditable div

I have a div that is contenteditable but I don't want to allow users to paste or drop formatted content into the div as this will - very likely - break the layout of the page.
The question how to handle HTML content that is pasted into such a div has already been raised several times and I was able to solve this problem as described here:
Javascript trick for 'paste as plain text` in execCommand
In one of the comments of the above question the point was raised that - in order to avoid HTML formatted content in the div at all - one needs to handle dropped content as well.
I need to support FF, Chrome, Edge and IE11. For all but IE11 I was able to implement a custom drop handler:
$("div[contenteditable=true]").on('drop', function(e) {
e.preventDefault();
var text = e.originalEvent.dataTransfer.types.indexOf && e.originalEvent.dataTransfer.types.indexOf('text/plain') >= 0 ? e.originalEvent.dataTransfer.getData('text/plain') : e.originalEvent.dataTransfer.getData('Text');
var range;
if (!document.caretRangeFromPoint) { // IE11 doesn't support caretRangeFromPoint
range = document.createRange();
range.setStart(e.currentTarget, 0);
range.setEnd(e.currentTarget, 0);
} else {
range = document.caretRangeFromPoint(e.originalEvent.clientX, e.originalEvent.clientY);
}
_insertText(text, range);
});
function _insertText(text, range) {
range.deleteContents();
var textNode = document.createTextNode(text);
range.insertNode(textNode);
range.selectNodeContents(textNode);
range.collapse(false);
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<h4 style="color:red">Drag Me</h4>
<div style="border: 1px solid;" contenteditable="true">Drop here</div>
</body>
https://jsfiddle.net/m25z6ch6/
As IE11 doesn't support document.caretRangeFromPoint I already tried to manually create a range as can be seen in the above snippet like this:
range = document.createRange();
range.setStart(e.currentTarget, 0);
range.setEnd(e.currentTarget, 0);
But This only works for dropping the content at the start of the already existing text. If I want to drop content into already existing text (e.g. between "Drop" and "here" in the above example), I somehow need to compute the offset to use. But I can't figure out how to do this for IE.
Is there a way to create a range object with correct offset given the information in a drop event (e.g. x,y coordinates and/or drop target element)?
Or is there any other way to customize the dropped content in order to allow plain text only for IE11?

execCommand not working in javascript jQuery to copy text to clipboard

i'm trying to copy a text to the clipboard. But've already shown the text as selected in the modal window where it appears after an ajax call.The code is the following:
jQuery.fn.selectText = function(){
var doc = document
, element = this[0]
, range, selection
;
if (doc.body.createTextRange) {
range = document.body.createTextRange();
range.moveToElementText(element);
range.select();
} else if (window.getSelection) {
selection = window.getSelection();
range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
}
so after range = document.createRange(); i tryied inserting range.execCommand('copy'); cause i've read this tutorial about it but it doesn't mention any problem with this command. The error i'm getting is the following:
TypeError: range.execCommand is not a function
This is a mozilla tutorial about execCommand.
A range doesn't have an execCommand function, the execCommand function belongs to the document object.
Taken from the same tutorial:
When an HTML document has been switched to designMode, the document
object exposes the execCommand method which allows one to run commands
to manipulate the contents of the editable region. Most commands
affect the document's selection (bold, italics, etc), while others
insert new elements (adding a link) or affect an entire line
(indenting). When using contentEditable, calling execCommand will
affect the currently active editable element.

Check if any formatting have been given in a Page

While searching text in a document
window.find(t)
Will highlight the text in document. But how can I highlight all the text in a web page. That means how can I highlight all the text in web page as giving complete design mode text as input to the window.find()
The original intention behind this is using the trick provided by Tim Down in this page I want to check whether any formatting have been given in the document.
Please let me know if you need any other input to be more helpful.
Try this
window.find(document.body.innerText)
or
function selectElementContents(el) {
var range;
if (window.getSelection && document.createRange) {
range = document.createRange();
var sel = window.getSelection();
range.selectNodeContents(el);
sel.removeAllRanges();
sel.addRange(range);
} else if (document.body && document.body.createTextRange) {
range = document.body.createTextRange();
range.moveToElementText(el);
range.select();
}
}
selectElementContents(document.body)
If you want all the text in the document's body, you would use document.body.innerText. If you want all the HTML in the document's body, you would use document.body.innerHTML.

Editable Div Caret Position

I have an editable div and I am using a button to insert an image into the div. Right now, I am just doing document.getElementById('elementid').innerHTML. += ; in order to get the image added to the end of the div. I would like to enter the image where the caret is. How would I go about doing this?
Thanks
To insert an element at the caret is not too hard. The following function inserts a node at the caret (or at the end of the selection, if content is selected) in all major browsers:
function insertNodeAfterSelection(node) {
var sel, range, html;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.collapse(false);
range.insertNode(node);
}
} else if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
range.collapse(false);
html = (node.nodeType == 3) ? node.data : node.outerHTML;
range.pasteHTML(html);
}
}
I hate to sound negative, but this is so hard it's ridiculous. You have to deal with IE and others, and the implementations are vastly different. But where it gets uber-hard is that if you click a button to insert the image, you lose focus and the caret position, so you need to remember the position with some onblur bookmarking ability (again, IE different). The focus thing is not so much an issue if your editablecontent is in an iframe and maintains its own focus. (Note: not dissing IE here, I actually prefer their implementation to the W3C standard drek.)
You can look at some open source text editors for clues and hints. But you'll find an enormous amount of code to handle these simple tasks.
Does this help: http://jsfiddle.net/8akDr/

getSelection() and insertNode -- Javascript Text Selection

Does anyone know how to set the browser selection to a newly / independently created range? I understand how to get the text selection from the browser, and I understand how to create a range, but I don't know how to tell the browser to change the selection to the range I've created. I would have thought it would be something like "setSelection".
To be clear, I'm not trying to cause the selection of a textarea - I'm talking about p / div / ul tags etc.
I was referencing the following site (maybe it'll give you an idea?):
http://www.quirksmode.org/dom/range_intro.html
Thanks in advance for your time.
Assuming that you have a range that is a DOM Range in non-IE browsers and a TextRange in IE:
function selectRange(range) {
var sel;
if (window.getSelection) {
// Non-IE browsers
sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (document.selection && range.select) {
// IE
range.select();
}
}

Categories