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);
}
};
}
Related
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)
}
}
}
I'm working on a blog where I want a section to add a post. I'm imagining it very similar to the StackExchange editor I'm using right now to write this post.
I've managed to work with the textarea to get things like current caret position, insert at position, etc.
The problem I'm running into now is not losing the highlighted text in the textarea when the user clicks on another element, ie: the bold tool.
By default (at least in Chrome) when you highlight text in a textarea and then click elsewhere on the page, the textarea loses focus and the highlighted text with it.
When the textarea loses focus it will by default lose any previous selection, so at the onblur event you can save the current selection using the following function:
function getSelectedText() {
var txtarea = document.getElementById(textBoxScript);
var start = txtarea.selectionStart;
var finish = txtarea.selectionEnd;
var sel = txtarea.value.substring(start, finish);
return sel;
}
And to set it back on focus event you can use the following function:
function selectText(startPos, endPos, tarea) {
// Chrome / Firefox
if (typeof (tarea.selectionStart) != "undefined") {
tarea.focus();
tarea.selectionStart = startPos;
tarea.selectionEnd = endPos;
return true;
}
// IE
if (document.selection && document.selection.createRange) {
tarea.focus();
tarea.select();
var range = document.selection.createRange();
range.collapse(true);
range.moveEnd("character", endPos);
range.moveStart("character", startPos);
range.select();
return true;
}
}
I can get selected text using this code in internet explorer:
var selectedText;
// IE version
if (document.selection != undefined)
{
textComponent.focus();
var sel = document.selection.createRange();
selectedText = sel.text;
}
but, how to delete selected text in TEXTAREA, for example, using JavaScript in both Google Chrome and Internet Explorer?
You might need to play around with the indexes a bit, but the below code should more or less work.
var originalText = document.getElementById("yourTextAreaId").value;
var selectedText = window.getSelection();
var startIndex = originalText.indexOf(selectedText) + 1;
var endIndex = startIndex + selectedText.length;
var newText = originalText.substring(0,startIndex) + orignalText.substring(endIndex);
document.getElementById("yourTextAreaId").value = newText
the answer given by user2793390 is not entirely correct!
it doesn't work if the selected text is not the first occurrence of it in whole text!
I had a similar problem and i used another approach!
var selectedElemnt = document.getElementById("yourTextAreaId");
var selectedText = selectedElemnt.value;
var newText = selectedText.substr(0, selectedElemnt.selectionStart) + selectedText.substr(selectedElemnt.selectionEnd);
selectedElemnt.value = newText;
If you are dealing with IE v9 or later, use window.getSelection() which works across all modern browsers.
I know how to set an <a /> tag with the href attribute in a contenteditable like this:
execCommand("CreateLink", false, "#jumpmark");
which will result in
selection
However I cannot figure out how to set an anchor name instead of the href.
This is my desired result:
<a name="jumpmark">selection</a>
Can anyone help me?
Side notes: I am using jQuery and Rangy as libraries, however I would prefer a solution that works directly with execCommand.
Update: Here's a jsfiddle: http://jsfiddle.net/fjYHr/ Select some text and click the button. All I want is that with the button click a link is inserted with a name attribute set instead of the href.
You could use something like the following, which is adapted from the pasteHtmlAtCaret() function from this answer of mine:
Demo: http://jsfiddle.net/F8Zny/
Code:
function surroundSelectedText(element) {
var sel, range;
if (window.getSelection) {
// IE9 and non-IE
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
element.appendChild( document.createTextNode(range.toString()) );
range.deleteContents();
range.insertNode(element);
// Preserve the selection
range = range.cloneRange();
range.setStartAfter(element);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
} else if (document.selection && document.selection.type != "Control") {
// IE < 9
var selRange = document.selection.createRange();
element.appendChild( document.createTextNode(selRange.text) );
selRange.pasteHTML(element.outerHTML);
}
}
If you must use document.execCommand() then you could use the InsertHTML command in non-IE browsers. However, IE does not support it.
document.execCommand("InsertHTML", false, '<a name="jumpmark">selection</a>');
I see you're using Rangy, but I don't how to use it at all. Before I realized what Rangy was, I looked up how to get the current selection. I found a function that gets it and replaces it with a passed in value. I ended up modfiying it, but here it is:
http://jsfiddle.net/fjYHr/1/
$(document).ready(function () {
$("#setlink").click(function () {
replaceSelectedText("jumplink");
});
});
function replaceSelectedText(nameValue) {
var sel, sel2, range;
if (window.getSelection) {
sel = window.getSelection();
sel2 = ""+sel; // Copy selection value
if (sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
var newA = document.createElement("a");
newA.name = nameValue;
newA.innerHTML = sel2;
range.insertNode(newA);
}
} else if (document.selection && document.selection.createRange) {
// Not sure what to do here
range = document.selection.createRange();
var newA = "<a name='" + nameValue.replace(/'/g, "") + "'>" + range.text + "</a>";
range.text = newA;
}
}
Notice how I store the original current selection, then replace it with an <a> element that gets its name set with the passed-in value.
As for the document.selection part (which seems to be used by IE < 9), I'm not 100% sure that the code I provided will work (actually allow HTML in the selection, and not escaping it). But it's my attempt :)
As you've seen execCommand is rather limited in the attributes you can set, as such you cannot set the name attribute using it - only the href.
As you have jQuery set as a tag, you can use that as an alternative:
var $a = $('<a></a>').attr('name', 'jumpmark').appendTo('body');
Update
I need to work on the current selection. Specifically I don't have a jQuery object that I can append to, meaning I don't have a DOM node that I can work on
In this case use a plugin such as Rangy to get the selection which you can then amend with jQuery as required.
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)