Let's say I highlight some text on the page using my mouse. How can I remove all highlighted text using JavaScript?
Thank you.
I've understood the question a bit differently. I believe you want to know how to delete the selected text from the document, in which case you could use:
function deleteSelection() {
if (window.getSelection) {
// Mozilla
var selection = window.getSelection();
if (selection.rangeCount > 0) {
window.getSelection().deleteFromDocument();
window.getSelection().removeAllRanges();
}
} else if (document.selection) {
// Internet Explorer
var ranges = document.selection.createRangeCollection();
for (var i = 0; i < ranges.length; i++) {
ranges[i].text = "";
}
}
}
If you just want to clear the highlight itself, and not remove the text being highlighted, the following should do the trick:
function clearSelection() {
if (window.getSelection) {
window.getSelection().removeAllRanges();
} else if (document.selection) {
document.selection.empty();
}
}
IE 4 and old Netscape used to have a method to do just this... It's not longer proper (nor supported).
Your best guess would be to use Javascript to focus() on an object, and then blur() as well -- effectively like clicking away from the object.
document.getElementById("someObject").focus();
document.getElementById("someObject").blur();
Related
Within a contenteditable DIV, I want to determine, if the user made a selection from left-to-right or from right-to-left. Does someone have a Javascript solution for the Browsers Firefox, Chrome, Safari, Opera? And when possible, also one for IE?
<div id="editor" contenteditable>
Selection from Cursor end | here <strong>over bold</strong> to Cursor start | here.
</div>
I prepared the code in jsFiddle here: http://jsfiddle.net/ecUka/
Thank's in advance :-)
Here's a function that uses the fact that setting the end of a DOM Range to be at an earlier point in the document than the start of the range will collapse the range.
Demo: http://jsfiddle.net/97MDR/17/
Code:
function isSelectionBackwards() {
var backwards = false;
if (window.getSelection) {
var sel = window.getSelection();
if (!sel.isCollapsed) {
var range = document.createRange();
range.setStart(sel.anchorNode, sel.anchorOffset);
range.setEnd(sel.focusNode, sel.focusOffset);
backwards = range.collapsed;
}
}
return backwards;
}
Demo:
function isSelectionBackwards() {
var backwards = false;
if (window.getSelection) {
var sel = window.getSelection();
if (!sel.isCollapsed) {
var range = document.createRange();
range.setStart(sel.anchorNode, sel.anchorOffset);
range.setEnd(sel.focusNode, sel.focusOffset);
backwards = range.collapsed;
}
}
return backwards;
}
document.addEventListener("selectionchange", function() {
document.getElementById("selReport").textContent = isSelectionBackwards();
});
<p>Select something forwards and backwards in here</p>
<p>Selection is backwards: <strong id="selReport">false</strong><p>
Unless you need to support Internet Explorer <9, which seems highly unlikely in 2023, you can safely ignore the rest of this answer, which I'm leaving here for posterity.
The above works in all major browsers except IE < 9, which does not support the same Range and Selection APIs as other browsers.
For IE < 9, there is simply nothing in the selection API to tell you about the selection direction. The best I can suggest is using the selectionchange event to keep track of the previously selected range and see which end has changed each time it fires. It seems to work in the following example but has had no testing apart from that, so use at your own risk.
Demo: http://jsfiddle.net/97MDR/18/
Additional code specific to IE < 9 that won't work in modern browsers:
var selectedRange, selectionBackwards;
document.onselectionchange = function(evt) {
evt = evt || window.event;
var sel = document.selection;
if (sel && sel.type !== "Control") {
if (sel.type == "Text") {
// Selection is not collapsed, so compare range end points
var newRange = sel.createRange();
if (selectedRange) {
var startChanged = (newRange.compareEndPoints("StartToStart", selectedRange) != 0);
var endChanged = (newRange.compareEndPoints("EndToEnd", selectedRange) != 0);
if (startChanged && !endChanged) {
selectionBackwards = true;
} else if (endChanged && !startChanged) {
selectionBackwards = false;
} else if (startChanged && endChanged) {
// Both ends have changed, which is confusing.
// I suspect this can happen when the selection snaps
// to words. In this case we can tell nothing, so leave
// selectionBackwards alone.
} else {
// Neither end has changed, so we can tell nothing.
}
}
selectedRange = newRange;
} else {
// Selection is collapsed
selectionBackwards = false;
}
}
};
range.setStart(anchorNode, anchorOffset);
range.setEnd(focusNode, focusOffset);
if(range.collapsed == false){
colsole.log('forward Selected');
}else{
colsole.log('backward Selected');
}
Here is my question:
When the user makes a selection in an article or in the editing area of a WYSWYG editor widget,
the selection can span over multiple elements,
like anchors, images, span tags... even block-level elements (but no table in my problem).
I know how to retrieve a Range object from the selection,
but could not find a reliable solution to get the content text of the Range object.
I'm not looking for a solution for IE (its TextRange object has a .text property).
Thanks!
Have you looked at the quirksmode article on Range?
Based on this article, you could create a method like this:
function getRangeText() {
var userSelection;
if (window.getSelection) {
userSelection = window.getSelection();
} else if (document.selection) {
userSelection = document.selection.createRange();
}
var selectedText = userSelection;
if (userSelection.text) {
selectedText = userSelection.text;
}
return selectedText;
}
I tested this in FF5, Opera 11, Safari on the Mac, as well as IE6 and IE7. It's worth testing in the other IE browsers, but my guess is it works in them, as well.
This returns a string and works in all major browsers:
function getSelectionText() {
var text = ""
if (window.getSelection) {
text = window.getSelection().toString();
} else if (document.selection && document.selection.type == "Text") {
text = document.selection.createRange().text;
}
return text;
}
I have this function
function smth() {
var container = null;
var newContainer = null;
if (window.getSelection) { // all browsers, except IE before version 9
alert("first if");
var selectionRange = window.getSelection();
if (selectionRange.rangeCount > 0) {
var range = selectionRange.getRangeAt(0);
container = range.commonAncestorContainer;
newContainer = container;
}
}
else {
if (document.selection) { // Internet Explorer
alert("second if");
var textRange = document.selection.createRange();
container = textRange.parentElement();
}
}
if (newContainer) {
return newContainer.nodeName;
}
else {
alert("Container object for the selection is not available!");
}
}
Now after i do what i need to do with the selection i need to clear it. i tried a few things nothing worked, any ideas?
document.selection.clear ()
this didnt work.
For the problematic browser:
document.selection.empty()
For other browsers:
window.getSelection().removeAllRanges()
See http://help.dottoro.com/ljigixkc.php
Note: in case you are selecting the text of an input or textarea element then your code would have more cross browser support if you would use the standard native html element select method of the input or textarea.
If an html input or textarea element was selected using the native select method then using the methods suggested above does not work on my firefox 44.0.2. What worked for it, and I suppose works on ALL BROWSERS, is running the following code which creates a new element and selects it. The new element can't be with display:none or visibility:hidden because then it is not selected in my Firebox so the trick is to make it invisible by forcing all size attributes to 0\none.
var tempElement = document.createElement("input");
tempElement.style.cssText = "width:0!important;padding:0!important;border:0!important;margin:0!important;outline:none!important;boxShadow:none!important;";
document.body.appendChild(tempElement);
tempElement.select();
/* Use removeChild instead of remove because remove is less supported */
document.body.removeChild(tempElement);
Use
tinymce.activeEditor.selection.collapse()
if that does not work then use
const range = tinymce.activeEditor.dom.createRng();
tinymce.activeEditor.selection.setRng(range)
If the user highlights the text within an <h1> with their cursor, how do I get that <h1> object? Or if they selected text within an <li>, how do i get that <li>?
You can get the selection on Document as,
dd = window.getSelection();
desiredElement = dd.focusNode.parentNode; // h1 or li or other
desiredTag = desiredElement.tagName; // its tagname
Happy Coding.
You need to deal with window.getSelection().
See
See Here
Here
and Here
$('h1').click(function(){
alert(this); // `this` is the <h1> object clicked.
});
is there some tricky part I missed in your question?
You can get the parent element of a selection in all modern mainstream browsers as follows. Bear in mind that Firefox allows multiple selections by default these days; this code will use only the first.
See also my answer here: How can I get the DOM element which contains the current selection?
function getSelectionContainerElement() {
var sel, el;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt) {
if (sel.rangeCount) {
el = sel.getRangeAt(0).commonAncestorContainer;
return (el.nodeType == 3) ? el.parentNode : el;
}
} else {
// This happens in old versions of Safari. A workaround
// exists, if you need it
}
} else if (document.selection && document.selection.createRange) {
return document.selection.createRange().parentElement();
}
}
I'm trying to make a JavaScript bookmarklet that will act as a highlighter, changing the background of selected text on a webpage to yellow when the bookmarklet is pressed.
I'm using the following code to get the selected text, and it works fine, returning the correct string
function getSelText() {
var SelText = '';
if (window.getSelection) {
SelText = window.getSelection();
} else if (document.getSelection) {
SelText = document.getSelection();
} else if (document.selection) {
SelText = document.selection.createRange().text;
}
return SelText;
}
However, when I created a similar function to change the CSS of the selected text using jQuery, it isn't working:
function highlightSelText() {
var SelText;
if (window.getSelection) {
SelText = window.getSelection();
} else if (document.getSelection) {
SelText = document.getSelection();
} else if (document.selection) {
SelText = document.selection.createRange().text;
}
$(SelText).css({'background-color' : 'yellow', 'font-weight' : 'bolder'});
}
Any ideas?
The easiest way to do this is to use execCommand(), which has a command to change the background colour in all modern browsers.
The following should do what you want on any selection, including ones spanning multiple elements. In non-IE browsers it turns on designMode, applies a background colour and then switches designMode off again.
UPDATE
Fixed in IE 9.
function makeEditableAndHighlight(colour) {
var range, sel = window.getSelection();
if (sel.rangeCount && sel.getRangeAt) {
range = sel.getRangeAt(0);
}
document.designMode = "on";
if (range) {
sel.removeAllRanges();
sel.addRange(range);
}
// Use HiliteColor since some browsers apply BackColor to the whole block
if (!document.execCommand("HiliteColor", false, colour)) {
document.execCommand("BackColor", false, colour);
}
document.designMode = "off";
}
function highlight(colour) {
var range, sel;
if (window.getSelection) {
// IE9 and non-IE
try {
if (!document.execCommand("BackColor", false, colour)) {
makeEditableAndHighlight(colour);
}
} catch (ex) {
makeEditableAndHighlight(colour)
}
} else if (document.selection && document.selection.createRange) {
// IE <= 8 case
range = document.selection.createRange();
range.execCommand("BackColor", false, colour);
}
}
Here is a crude example of how it could work. As Zack points out you'll need to be aware of cases where the selection spans multiple elements. This isn't intended to be used as-is, just something to help get ideas flowing. Tested in Chrome.
var selection = window.getSelection();
var text = selection.toString();
var parent = $(selection.focusNode.parentElement);
var oldHtml = parent.html();
var newHtml = oldHtml.replace(text, "<span class='highlight'>"+text+"</span>");
parent.html( newHtml );
To make the highlight stick permanently, I believe you are going to have to wrap the selection in a new DOM element (span should do), to which you can then attach style properties. I don't know if jQuery can do that for you. Keep in mind that selections can span element boundaries, so in the general case you're going to have to inject a whole bunch of new elements
Have a look at a little example i made at http://www.jsfiddle.net/hbwEE/3/
It does not take into account selections that span multiple elements..
(IE will do but will mess the html a bit ..)
In Firefox, you can use the ::-moz-selection psuedo-class.
In Webkit, you can use the ::selection pseudo-class.
I like Tim's answer, it's clean and fast. But it also shuts down the doors to doing any interactions with the highlights.
Inserting inline elements directly around the texts is a bad choice, as they broke the text flow and mess things up in complex situations,
So I suggest a dirty hack that
calculates the absolute layout of each line of selected text (no matter where they are),
then insert colored, semi-transparent inline-block elements in the end of the document body.
This chrome extension is an example of how this can be done.
It uses API from this library to get the absolute layout of each selected line.