document.getSelection().toString() is always " " in ie while working with iframe - javascript

I wanted to get the selected text onmouseup.
I also tried
setTimeout(() => {
var selectedData = contentWrapper.getSelection().toString();
alert(selectedData)
}, 1008)
html code
<iframe src="url"></iframe>
js code
var contentWrapper=document.getElementsByTagName("iframe")[0].contentDocument;
contentWrapper.body.addEventListener('mouseup', this.CheckSelections, false);
function CheckSelections() {
var selectedData = contentWrapper.getSelection().toString();
alert(selectedData)
}

This way it works in IE, Chrome & FF (testing on local), but I am not able to touch iframe here.
function showSelection() {
var selectedData = document.getSelection().toString();
alert(selectedData)
}
var contentWrapper;
function attachIF() {
if(location.href == "https://stacksnippets.net/js") return;
var ifr = document.createElement("iframe");
ifr.src="javascript:'"+ // Access is denied. Here on stackoverflow.com
"<script>window.onload=function(){"+
"document.write(\\'<script>if(document.domain)document.domain=\\\""+document.domain+"\\\";"+
"document.write(\""+parent.document.body.innerText+"\");"+
"<\\\\/script>\\');"+
"document.close();"+
"parent.contentWrapper = document;"+
"document.body.onmouseup=parent.CheckSelections;"+
"};<\/script>'";
document.body.appendChild(ifr);
}
function CheckSelections() {
var selectedData = contentWrapper.getSelection().toString();
alert(selectedData)
}
<body onmouseup="showSelection()" onload=attachIF()>
<iframe src="https://stacksnippets.net/js"></iframe>
Some text to be selected.
</body>

Related

How to add JavaScript to newly created document with DOMImplementation.createHTMLDocument()

The following code snippet creates a new DOM document with a button inside it and adds it to an iframe.
I want to add a JavaScript code inside the new DOM document so that when I click the button id dose something like alert.
I tried the following code but it doesn't work.
<html>
<head>
</head>
<body>
<p><button id="btn" >Click Here</button> to create a new document and insert it below.</p>
<iframe id="theFrame" src="about:blank"></iframe>
<script type="text/javascript">
document.getElementById("btn").onclick = function () {
var frame = document.getElementById("theFrame");
var doc = document.implementation.createHTMLDocument("New Document");
var button = doc.createElement("button");
button.innerHTML = "Alert";
button.setAttribute("id","btn1");
var script = doc.createElement("script");
script.innerHTML = "document.getElementById('btn1').onclick = function() {alert('button clicked!')};";
try {
doc.body.appendChild(button);
} catch(e) {
console.log(e);
}
try {
doc.body.appendChild(script);
} catch(e) {
console.log(e);
}
// Copy the new HTML document into the frame
var destDocument = frame.contentDocument;
var srcNode = doc.documentElement;
var newNode = destDocument.importNode(srcNode, true);
destDocument.replaceChild(newNode, destDocument.documentElement);
}
</script>
</body>
You really don't need to create a new document.
Just get a reference to the document within the frame and do everything within that context.
document.getElementById("btn").onclick = function () {
var frame = document.getElementById("theFrame");
// reference to the iframe document instead of createHTMLDocument
var doc = frame.contentDocument
var button = doc.createElement("button");
button.innerHTML = "Alert";
button.setAttribute("id","btn1");
var script = doc.createElement("script");
script.innerHTML = "document.getElementById('btn1').onclick = function() {alert('button clicked!')};";
try {
doc.body.appendChild(button);
} catch(e) {
console.log(e);
}
try {
doc.body.appendChild(script);
} catch(e) {
console.log(e);
}
}
Plunker demo

Cannot communicate between captivate html and parent html

I have a published captivate html file that is loaded into an iframe of another html. I cannot communicate between the two, not even with localStorage. Can anyone tell me what I'm missing?
Parent html
var everythingLoaded = setInterval(function () {
if (/loaded|complete/.test(document.readyState)) {
clearInterval(everythingLoaded);
init();
}
}, 10);
function init() {
ScormProcessInitialize();
var studentID = ScormProcessGetValue("cmi.core.student_id");
var student_name = ScormProcessGetValue ("cmi.core.student_name");
var nameArraya = student_name.split(" ");
var nameArrayb = nameArraya[1].split(",");
var studentNumber = nameArrayb[0];
ScormProcessSetValue("cmi.core.lesson_status", "incomplete");
localStorage.setItem("_studentNumber", studentNumber);
alert("Student Number: " + studentNumber + " Student Mame: " + student_name);
setTimeout(function () {
document.getElementById("iFrame_a").innerHTML = "<iframe name='iframe_1' id='frame_1' src='//somepath.com/sandbox/somecourse/index.html' frameborder='0' width='1000px' height='605px'></iframe>";
}, 250);
}
function sendComplete() {
alert("Send from index start!");
ScormProcessSetValue("cmi.core.lesson_status", "completed");
alert("send status: Completed");
}
window.onbeforeunload = function (){
cpInfoCurrentSlide = localStorage.getItem("_cpInfoCurrentSlide")
alert(cpInfoCurrentSlide);
if(cpInfoCurrentSlide >= 40)
{
alert("onbeforeunload called: " + cpInfoCurrentSlide )
ScormProcessSetValue("cmi.core.lesson_status", "completed");
}
}
iframe code snippet
localStorage.setItem("_cpInfoCurrentSlide", cpInfoCurrentSlide);
I believe your problem is with onbeforeunload. As I remember captivate packages clobber any functions associated with onbeforeunload in the parent frame when they load.
Try this instead, override your SCORM api setvalue method:
var oldLMSSetValue = window.API.LMSSetValue;
window.API.LMSSetValue = function(key, value){
if(key === 'cmi.core.lesson_status' && value === 'completed'){
//do your stuff here
cpInfoCurrentSlide = localStorage.getItem("_cpInfoCurrentSlide")
alert(cpInfoCurrentSlide);
}
//call the original scorm api function so that it runs as expected.
oldLMSSetValue(key,value);
};
edit: this code would go in the parent window, not the iframe.

How to detect onscroll event on an iframe? the iframe's source is of the same domain of the page

The plan is not to have a scroll bar to the iframe that I am adding to my page. So the idea to do it as I thought is to have a onscroll function.
So whenever a user scrolls the iframe, I will call this function
function resizeIframe(obj) {
obj.style.height = obj.contentWindow.document.body.scrollHeight + 'px';
}
But I do not know how to detect onscroll event inside an iframe.
PS: the source of the iframe is of the same domain as the page.
My iframe:
<iframe id="externalIframe" scrolling="auto" frameborder="0" allowtransparency="true" style="width: 1240px; height: 489px; display:block" src="http://www.example.com/" onload="resizeIframe(this);" onscroll="resizeIframe(this);" onclick="resizeIframe(this)"></iframe>
JQuery solution:
$("#yourFrameId").load(function () {
var iframe = $("#yourFrameId").contents();
$(iframe).scroll(function () {
//your code here
});
});
Use this snippet. Bind the onscroll function on the iframe load event.
function getFrameTargetElement(objI)
{
var objFrame = objI.contentWindow;
if(window.pageYOffset==undefined)
{
objFrame = (objFrame .document.documentElement) ? objFrame .document.documentElement : objFrame =document.body;
}
//- return computed value
return objFrame ;
}
$("#externalIframe").load(function (){
var frame = getFrameTargetElement(document.getElementById("externalIframe"));
frame.onscroll = function (e) {
resizeIframe(obj);
}
});
var iframe = angular.element(document.getElementById('terms'));
iframe.load(() => {
var checkIndex = $scope.stageContent.checkbox.length; // Take last slot for the scroll check
checks[checkIndex] = false;
var iframeDoc = iframe.contents();
var treshold = iframeDoc.height() - (iframe.height() * 1.5);
iframeDoc.scroll(() => {
if (iframeDoc.scrollTop() >= treshold) {
$timeout(() => {
checks[checkIndex] = true;
checkCanContinue();
});
iframeDoc.off('scroll');
}
});
});

Close an injected iframe

I have a content script that runs from my chrome extension.
this script injects an iframe to the body of the current page.
i want to have the possibility to close the iframe from within the iframe.
how do i do this?
when i searched this issue on the web, almost each solution uses the window.parent.document property which for some reason is undefined in my case. any ideas?
EDIT - Code Sample:
in the HTML of the iframe:
<script type="text/javascript">
function frameClose() {
var windowFrames = window.parent.frames;
for (var i = 0; i < windowFrames.length; i++) {
var aFrame = windowFrames[i];
if (aFrame.name == 'myFrame') {
alert('in frame');
// WHAT TO DO HERE?
// window.parent.document is undefined
// aFrame.parentNode.removeChild(aFrame); - THIS DOES NOT WORK ALSO
break;
}
}
}
</script>
this is how i inject the iframe:
Extension.js
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, {
file : "/js/PushIFrame.js"
}, function() {
if (chrome.extension.lastError) {
}
});
});
and in PushIFrame.js i have:
chrome.extension.sendMessage({
action: "pushFrame",
source: pushIframe(document)
});
function pushIframe(document) {
var existingFrame = document.getElementById('bmarkFrame');
if (existingFrame == null) {
var temp = document.createElement('iframe');
temp.id = 'myFrame';
temp.name = 'myFrame';
temp.setAttribute('scrolling', 'no');
temp.setAttribute('allowtransparency', 'true');
temp.style.border = 'none';
temp.style.height = '100%';
temp.style.width = '100%';
temp.style.position = 'fixed';
temp.style.zIndex = 99999999;
temp.style.top = 0;
temp.style.left = 0;
temp.style.display = 'block';
temp.src = 'https://www.mysite.com/';
document.body.appendChild(temp);
}
else {
existingFrame.style.display = 'block';
}
}
Let the content script (say PushIframe.js) bind a message event to the main frame. Then, whenever you want to hide the iframe, call parent.postMessage to notify the main frame. This message is received by the content script, from where you can hide the frame (as defined in your function pushIframe).
// PushIframe.js:
addEventListener('message', function(ev) {
if (ev.data === 'closeIframe') {
pushIframe(document); // Your code
}
});
// Iframe:
<script>
function frameClose() {
parent.postMessage('closeIframe', '*');
}
</script>

Why document.execCommand('paste') is not working in my extension

I am creating a Google chrome extension which can read the contents of clipboard.
But I am unable to get the documentation for this. I want to get the clipboard content as in IE's clipboard API.
In the manifest file i gave permissions to
clipboardRead and clipboardWrite.
I have created a function in Background page as below
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.method == "getClipData")
sendResponse({data: document.execCommand('paste')});
else
sendResponse({}); // snub them.
});
And in Content Script I am calling the function like this
chrome.extension.sendRequest({method: "getClipData"}, function(response) {
alert(response.data);
});
But this returns me undefined...
document.execCommand('paste') returns success or failure, not the contents of the clipboard.
The command triggers a paste action into the focused element in the background page. You have to create a TEXTAREA or DIV contentEditable=true in the background page and focus it to receive the paste content.
You can see an example of how to make this work in my BBCodePaste extension:
https://github.com/jeske/BBCodePaste
Here is one example of how to read the clipboard text in the background page:
bg = chrome.extension.getBackgroundPage(); // get the background page
bg.document.body.innerHTML= ""; // clear the background page
// add a DIV, contentEditable=true, to accept the paste action
var helperdiv = bg.document.createElement("div");
document.body.appendChild(helperdiv);
helperdiv.contentEditable = true;
// focus the helper div's content
var range = document.createRange();
range.selectNode(helperdiv);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
helperdiv.focus();
// trigger the paste action
bg.document.execCommand("Paste");
// read the clipboard contents from the helperdiv
var clipboardContents = helperdiv.innerHTML;
If you want plain-text instead of HTML, you can either use helperdiv.innerText, or you can switch to using a textarea. If you want to parse the HTML in some way, you can walk the HTML dom inside the DIV (again, see my BBCodePaste extension)
var str = document.execCommand('paste');
You will need to add the clipboardRead permission too.
We cant access clipboard from javascript instead IE for chrome and other browsers.
The hack for this is very simple: create own custom clipboard which store text on cut and from where we paste it directly
function copy(){
if (!window.x) {
x = {};
}
x.Selector = {};
x.Selector.getSelected = function() {
var t = '';
if (window.getSelection) {
t = window.getSelection();
} else if (document.getSelection) {
t = document.getSelection();
} else if (document.selection) {
t = document.selection.createRange().text;
}
return t;
}
var mytext = x.Selector.getSelected();
document.getElementById("book").innerHTML =mytext;
}
function cut(){
if (!window.x) {
x = {};
}
x.Selector = {};
x.Selector.getSelected = function() {
var t = '';
if (window.getSelection) {
t = window.getSelection();
} else if (document.getSelection) {
t = document.getSelection();
} else if (document.selection) {
t = document.selection.createRange().text;
}
return t;
}
var mytext = x.Selector.getSelected();
document.getElementById("book").innerHTML =mytext;
x.Selector.setSelected()="";
}
function paste()
{
var firstDivContent = document.getElementById('book');
var secondDivContent = document.getElementById('rte');
secondDivContent.innerHTML += firstDivContent.innerHTML;
rte.focus();
}
function clear()
{
document.getElementById('rte').innerHTML="";
rte.focus();
}
<button id="cut"onclick="cut();">Cut</button>
<button id="copy"onclick="copy();">Copy</button>
<button id="paste"onclick="paste();">Paste</button>
Working Div
<div id="rte" contenteditable="true" style="overflow:auto;padding:10px;height:80vh;border:2px solid black;" unselectable="off" ></div>
Own Clipboard(hack)
<div id="book" contenteditable="true"style="background-color:#555;color:white;"> </div>

Categories