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)
Related
I want to create a CMS like wordpress. In my text editor I want the user to be able to create a hyperlink via a button click. But I don't want to show an alert so the user can input the url but a div shown under the selected word/sentence inside or over the text area with an text input. How do I get the location of the selected word?
I already tried to append a textnode to it like this:
window.getSelection().appendChild(document.createTextNode("testing"));
but I get an error, that .appendChild() is not a function.
$('#btnLink').click(function() {
window.getSelection().appendChild(document.createTextNode("testing"));
})
I expect the textnode is appended to the selected word, but it doesnt work
The getSelection() method will not return a node to append text to.
I've used some code from a different answer (added below the code) to achieve what you're asking.
$('#btnLink').click(function() {
var elm = getRange();
var div = document.createElement("div");
div.appendChild( document.createElement("input") );
elm.collapse(false);
elm.insertNode(div);
});
function getRange() {
var range, sel, container;
if (document.selection) {
range = document.selection.createRange();
range.collapse(isStart);
return range.parentElement();
} else {
sel = window.getSelection();
if (sel.getRangeAt) {
if (sel.rangeCount > 0) {
range = sel.getRangeAt(0);
}
} else {
// Old WebKit
range = document.createRange();
range.setStart(sel.anchorNode, sel.anchorOffset);
range.setEnd(sel.focusNode, sel.focusOffset);
// Handle the case when the selection was selected backwards (from the end to the start in the document)
if (range.collapsed !== sel.isCollapsed) {
range.setStart(sel.focusNode, sel.focusOffset);
range.setEnd(sel.anchorNode, sel.anchorOffset);
}
}
if (range) {
return range;
}
}
}
This code is copied and altered from How can I get the DOM element which contains the current selection? to demonstrate the use for this specific question.
A JSFiddle: https://jsfiddle.net/zuvq9nyc/5/
try this:
$('#btnLink').click(function() {
window.getSelection.append(document.createTextNode('testing'));
})
.appendchild() is a javascript function, jquery can't use it. use .append() instead and use .createTextNode() inside it.
I'm building a chrome extension where selected text can have different highlighting styles applied to it. I used ranges to get this all to work, and I clone the range, put a span around it, and then delete the range and replace it with the cloned one. Everything seems fine except I've somehow managed to disable right clicking by triggering this behavior through the extension. I've narrowed it down the single line of range.surroundContents(span), but here's the full code section:
// Determines the selected text
document.onmouseup = function() {
var selection = document.getSelection();
selection = getSelectedText(color);
};
// Finds the text selected in the page, spans it, and gives it a class
function getSelectedText(inputColor) {
var span = document.createElement('span');
span.setAttribute('class', inputColor);
if(document.getSelection) {
var selection = document.getSelection();
if(selection.rangeCount == true) {
var range = selection.getRangeAt(0).cloneRange();
range.surroundContents(span);
selection.removeAllRanges();
selection.addRange(range);
}
}
}
Is there a way I can counter this? I've already tried using document.oncontextmenu = false directly following the problem line, but that's not bringing back right click. I also tried replacing it with newNode.appendChild(range.extractContents()); range.insertNode(newNode) as recommended by https://developer.mozilla.org/en-US/docs/Web/API/Range/surroundContents but then instead of highlighting text, it seems to just be removing it from the page.
#wOxxOm answered my question in a comment, but a setTimeout() is what worked. So for anyone else who might have a similar issue in the future:
// Finds the text selected in the page, spans it, and gives it a class
function getSelectedText(inputColor) {
var span = document.createElement('span');
span.setAttribute('class', inputColor);
if(document.getSelection) {
var selection = document.getSelection();
if(selection.rangeCount == true) {
var range = selection.getRangeAt(0).cloneRange();
setTimeout(function(){
range.surroundContents(span);
selection.removeAllRanges();
selection.addRange(range);
}, 100)
}
}
}
In my site I am using a WYSIWYG editor that uses an iframe.
When I select a text with double click in order to add a link to it, in Chrome, Safari and Firefox the selected text is the right one and the link is added.
However, when I click an image instead, the selection is done only in Firefox. Chrome and Safari have an empty selection and in order to select the image and add a link on it, I have to drag the mouse over it, like a manual select.
My code is:
var sel = parent.document.getElementById('myframe').contentWindow.document.getSelection();
if (sel.rangeCount > 0) {
var range = sel.getRangeAt (0);
var docFragment = range.cloneContents ();
var tmpDiv = document.createElement ("div");
tmpDiv.appendChild (docFragment);
selHTML = tmpDiv.innerHTML;
}
if (selHTML != '') {
parent.document.getElementById('myframe').contentWindow.document.execCommand(id,false,value);
}
Is there any way to solve this problem?
Thanks in advance.
I change the code to that one according to #Tim suggestions:
var iframeWin = parent.document.getElementById('myframe').contentWindow;
var iframeDoc = iframeWin.document;
var sel = iframeWin.getSelection();
var range = iframeDoc.createRange();
var referenceNode = document.getElementsByTagName("img").item(0);
range.selectNode(referenceNode);
sel.removeAllRanges();
sel.addRange(range);
parent.document.getElementById('myframe').contentWindow.document.execCommand(id,false,value);
But still not works. Any more suggestions?
You could just do this manually using the dblclick event, but beware of breaking the regular image resize handles you get in non-WebKit browsers.
Live demo: http://jsfiddle.net/x49hv/3/
Code:
var iframeWin = parent.document.getElementById('myframe').contentWindow;
var iframeDoc = iframeWin.document;
// Prevent errors in IE < 9, which does not support DOM Range and Selection
if (iframeWin.getSelection && iframeDoc.createRange) {
iframeDoc.ondblclick = function(e) {
if (e.target.nodeName.toLowerCase() == "img") {
var sel = iframeWin.getSelection();
var range = iframeDoc.createRange();
range.selectNode(e.target);
sel.removeAllRanges();
sel.addRange(range);
}
};
}
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.
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();