Inserting text into an editable IFRAME at the caret position (IE) - javascript

I'm struggling with an actually straighforward problem: In Internet Explorer I want to insert plain text at the current caret position. This works really fine for simple TEXTAREA elements but it doesn't entirely work for editable IFRAMEs, which is what I have.
In the script I use I am creating a TextRange object from the document of the IFRAME which I use to paste the text as HTML at the cursor position.
<iframe id="editable">
<html>
<body>
Some really boring text.
</body>
</html>
</iframe>
<script type="text/javascript">
window.onload = function() {
var iframe = document.getElementById('editable');
var doc = iframe.contentDocument || iframe.contentWindow.document;
doc.body.innerHTML = iframe.textContent || iframe.innerHTML;
// Make IFRAME editable
if (doc.body.contentEditable) {
doc.body.contentEditable = true;
}
}
function insert(text) {
var iframe = document.getElementById('editable');
var doc = iframe.contentDocument || iframe.contentWindow.document;
iframe.focus();
if(typeof doc.selection != 'undefined') {
var range = doc.selection.createRange();
range.pasteHTML(text);
}
}
</script>
<input type="button" value="Insert" onClick="insert('foo');"/>
When I select some text in the IFRAME, the selection will be replaced with "foo" - this is expected behaviour. But when I just place the caret somewhere in the text, the insertion won't work.
Is this common behaviour, as there is "no real selection" for the case that I just place the cursor somewhere or is it a bug with editable IFRAMEs in IE, since it works pretty well with simple TEXTAREA elements?
Is there a workaround?

You may find it works if you use onmousedown rather than onclick in your button.
UPDATE
The reason why this makes a difference is that the click event fires after the iframe has lost focus (which destroys a collapsed selection in IE) whereas mousedown fires before.
FURTHER UPDATE
You could also try fixing this in IE by saving/restoring the selected TextRange as the iframe loses/receives focus. Something like this should work:
function fixIframeCaret(iframe) {
if (iframe.attachEvent) {
var selectedRange = null;
iframe.attachEvent("onbeforedeactivate", function() {
var sel = iframe.contentWindow.document.selection;
if (sel.type != "None") {
selectedRange = sel.createRange();
}
});
iframe.contentWindow.attachEvent("onfocus", function() {
if (selectedRange) {
selectedRange.select();
}
});
}
}
window.onload = function() {
var iframe = document.getElementById('editable');
fixIframeCaret(iframe);
};

Related

Copy data to clipboard without selecting any text

Is there any cross-platform, or even mostly cross-platform, way to copy text to the clipboard in JavaScript without making an element, putting it on the page, and then selecting the text? How do the websites with "Copy to clipboard" buttons do it? I don't want it to use input fields because the idea is to copy anything into the clipboard, even stuff that may not be in an element.
I believe these days you can use navigator.clipboard if you only care about this working in modern versions of chrome, firefox, edge and opera.
https://developer.mozilla.org/en-US/docs/Web/API/Clipboard
e.g.
var amazingText = "Hello World! How sweet the content";
navigator.clipboard.writeText(amazingText);
Your best best for safari, ie,old browsers and anything else support is to check if navigator.clipboard is defined and have a fallback to the old inefficient create throw away element select and copy as a last resort.
I have used this mainly when there is a reasonably large about of data to copy to the clipboard as i have noticed performance issues with the select and exec methods.
Edit*
I briefly looked on the clipboard.js website as suggested and there is a sentence which says "This library relies on both Selection and execCommand APIs." which suggests perhaps it does not provide answer the question. However I have not looked at the source to verify this assumption.
https://clipboardjs.com/#browser-support
Hope this is what you looking for.
document.getElementById("copyButton").addEventListener("click", function() {
copyToClipboard(document.getElementById("txt"));
});
setInterval(function(){
document.getElementById("txt").innerHTML = "Copy Me!!! # " + new Date().getTime();
},1000);
function copyToClipboard(elem) {
// create hidden text element, if it doesn't already exist
var targetId = "_hiddenCopyText_";
var isInput = elem.tagName === "INPUT" || elem.tagName === "TEXTAREA";
var origSelectionStart, origSelectionEnd;
if (isInput) {
// can just use the original source element for the selection and copy
target = elem;
origSelectionStart = elem.selectionStart;
origSelectionEnd = elem.selectionEnd;
} else {
// must use a temporary form element for the selection and copy
target = document.getElementById(targetId);
if (!target) {
var target = document.createElement("textarea");
target.style.position = "absolute";
target.style.left = "-9999px";
target.style.top = "0";
target.id = targetId;
document.body.appendChild(target);
}
target.textContent = elem.textContent;
}
// select the content
var currentFocus = document.activeElement;
target.focus();
target.setSelectionRange(0, target.value.length);
// copy the selection
var succeed;
try {
succeed = document.execCommand("copy");
} catch(e) {
succeed = false;
}
// restore original focus
if (currentFocus && typeof currentFocus.focus === "function") {
currentFocus.focus();
}
if (isInput) {
// restore prior selection
elem.setSelectionRange(origSelectionStart, origSelectionEnd);
} else {
// clear temporary content
target.textContent = "";
}
return succeed;
}
input {
width: 400px;
}
<div id="txt">copy me!!!</div><br><br><button id="copyButton">Copy</button><br><br>
<input type="text" placeholder="Click here and press Ctrl-V to see clipboard contents">
You can try Clipboard.js, plenty of examples out there.

How to get innerHTML content of iframe element

hi i am trying to get inner HTML of iframe element
my html document a structure is like this
<body>
<div>
<iframe id="frame1">
<html>
<button id="mybutton">click me</button>
</html>
</iframe>
</div>
</body>
i am creating a chrome extension i have to show an alert when button with id mybutton is clicked i write an a content script
var greeting = "hola, ";
document.body.innerHTML='<div><iframe id="frame1" src="http://onemoredemo.appspot.com/"></iframe></div>' ;
var iframe = document.getElementById("frame1");
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document
var button = iframeDocument.getElementById("mybutton") ;
if(button ==null)
alert("button is null") ;
i installed this extension in chrome when i visit a page then document body is changed into an iframe with a button in it.
but i am facing an alert which has button is null but there is button in iframe why i am getting null for this button??
To get the button inside of the iframe, this could work:
var iframe = document.getElementById("frame1");
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
var button = iframeDocument.getElementById("mybutton");
Obviously, you can navigate to get what you want with iframeDocument, and use .innerHTML as you seem to know. You cannot get the contents of the iframe if the iframe is pointing to a domain other than its parent.
UPDATE:
You need to use the code to get the frame's document and its contents after it's ready, so you should use something like this:
window.onload = function () {
var greeting = "hola, ";
var div1 = document.createElement("div");
var frame1 = document.createElement("iframe");
frame1.id = "frame1";
frame1.onload = function () {
alert("loaded");
var iframe = document.getElementById("frame1");
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
var button = iframeDocument.getElementById("mybutton");
if (button == null) {
alert("button is null");
}
};
frame1.src = "http://onemoredemo.appspot.com";
div1.appendChild(frame1);
document.body.appendChild(div1);
};
DEMO: http://jsfiddle.net/nqTnz/
The important thing is how the elements are created and appended to the DOM - not just using innerHTML. The onload method of the iframe is to guarantee it's ready. The actual manipulation code won't work in the jsFiddle because the cross-domain problems, but is what you should need.
In jQuery's source code the solution to get the iframe document is like this:
var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
And then you can usually use getElementsByTagName or getElementById to select the DOM-Elements:
var elem;
if (iframeDocument) {
elem = iframeDocument.getElementById('mybutton');
}
Have You tried ????
iframe.srcdoc="<HTML><a id='some_id'>old</a><script>function run(src){eval(src);}</script></HTML>";
And then
iframe.contentWindow.run("document.getElementById('some_id').innerHTML='new content';");

how to get selected text from iframe with javascript?

how to get selected text from iframe with javascript ?
var $ifx = $('<iframe src="filename.html" height=200 width=200></iframe>').appendTo(document.body);
$(document.body).bind('click', function(){
var u_sel;
if(window.getSelection){
u_sel = ifx[0].contentWindow.getSelection();
// u_sel.text() InternetExplorer !!
alert(u_sel);
}
});
That should do it, as long as the iframe src is targeting your own domain.
Tested only on FireFox 3.6.7 so far.
function getIframeSelectionText(iframe) {
var win = iframe.contentWindow;
var doc = iframe.contentDocument || win.document;
if (win.getSelection) {
return win.getSelection().toString();
} else if (doc.selection && doc.selection.createRange) {
return doc.selection.createRange().text;
}
}
var iframe = document.getElementById("your_iframe");
alert(getIframeSelectionText(iframe));
As noted by jAndy, this will only work if the iframe document is served from the same domain as the containing document.

Javascript: how to append more text to user copied text ala nydailynews.com

On nydailynews.com when you copy and paste any text from the site, a snippet of text is appended.
Read more: http://www.nydailynews.com/#ixzz0aN123abc
How do they achieve this?
I have searched all of the external JavaScript files (jquery) and can't seem to find anything that corresponds. Is this something that could be done in simple css?
If you use EventBug in Firefox, you'll see that a copy event fires. The JS on the page is listening for this event and changing the clipboard contents. There are so many files loaded by that page it's hard to find the source code, though.
Use this code to add extra text to the copied content
Source : http://bavotasan.com/2010/add-a-copyright-notice-to-copied-text/
<script type="text/javascript">
function addLink() {
var body_element = document.getElementsByTagName('body')[0];
var selection;
selection = window.getSelection();
var pagelink = "<br /><br /> Read more at: <a href='"+document.location.href+"'>"+document.location.href+"</a><br />Copyright © c.bavota"; // change this if you want
var copytext = selection + pagelink;
var newdiv = document.createElement('div');
newdiv.style.position='absolute';
newdiv.style.left='-99999px';
body_element.appendChild(newdiv);
newdiv.innerHTML = copytext;
selection.selectAllChildren(newdiv);
window.setTimeout(function() {
body_element.removeChild(newdiv);
},0);
}
document.oncopy = addLink;
</script>

RadEditor scrolls to top after pasting the contents

I am using Telerik RadEditor.
The issue:
On pasting the content into the Telerik Radeditor, the editor is getting scrolled to top. So, I searched the internet and also Telerik forums, but no luck. Finally, I worked on the following code with fix.
Code for RadEditor Server-Side Control:
<telerik:RadEditor
ID="E"
runat="server"
Width="100%"
AllowScripts="true"
AllowPaging="true"
EnableResize="false"
NewLineMode="P"
OnClientLoad="OnClientLoad"
OnClientModeChange="E_OnClientModeChanged"
EditModes="Design,Html"
StripFormattingOptions="Span,MsWordRemoveAll,CSS,Font,ConvertWordLists"
OnClientPasteHtml="radEditorControl_OnClientPasteHtml"
OnClientSelectionChange="OnClientSelectionChange">
</telerik:RadEditor>
Below is the Javascript Code with fix:
//Event on pasting the content into the RadEditor. Fixing the scrolling issue on pasting the content.
var isPasted = false;
function radEditorControl_OnClientPasteHtml(editor, args) {
if (editor != undefined)
isPasted = true;
}
function OnClientSelectionChange(editor, args) {
if (isPasted != undefined && isPasted == true && editor != undefined) {
isPasted = false;
editor.setFocus();
var iframeElement = editor._contentAreaElement; // the DOM element for the iframe;
if (iframeElement) {
//Get the iFrame cursor position.
var _focusNode = iframeElement.contentWindow.getSelection().focusNode;
if (_focusNode != undefined) {
//Focus node is not an element, get the previous element sibling
if (_focusNode.nodeType != 1) {
if (_focusNode.previousElementSibling != undefined)
_focusNode = _focusNode.previousElementSibling;
else
_focusNode = _focusNode.parentNode;
}
//Insert a div near focusNode(cursor) of the iFrame contentWindow.
var timeStamp = new Date().getUTCMilliseconds();
var _id = "scrollArea_" + timeStamp;
var focusElement = jQuery('<input type="text" id="' + _id + '" name="' + _id + '" onfocus="alert();" />').insertAfter(_focusNode)[0];
setTimeout(function () {
if (focusElement != undefined) {
focusElement.focus({ preventScroll: true });
focusElement.select();
var range = editor.getSelection().getRange(true); //returns an object that represents a restore point.
editor.getSelection().selectRange(range);
if (range != undefined && range.collapse !=undefined)
range.collapse(true);
jQuery(focusElement).replaceWith("");
}
}, 50);
}
}
}
}
The above code is working in IE and Chrome, but not in Firefox as focus() is not getting triggered for the input element which I am binding.
Please let me know if there is any other way for resolving the scroll issue on paste in RadEditor.
I am aware of such a problem within the older versions of RadEditor. My advice is to try the latest version which you can test at https://demos.telerik.com/aspnet-ajax/editor/examples/overview/defaultcs.aspx. If the problem still persists please drop us a line in the Telerik AJAX forums or via the support ticketing system and we will look deeper into it.

Categories

Resources