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

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

Related

JS & jQuery script inside iframe function as if from parent html

The below code is in a script which has been loaded into the iframe #contframe source html. The button is inside the iframe.
Why does this only work when I reference the function as if it is coming from the parent HTML?
For example, the below code works:
$(document).ready(function() {
var kuf = $('#contframe').contents().find('#zbtn');
kuf.click(function() {
alert("hello");
});
});
However the below function does not work at all:
$(document).ready(function() {
$('#zbtn').click(function() {
alert("oi");
});
});
I was completely appending my scripts; I believe using the doc.createElement fixed the issue.
The following solved my issue - some slight edits from Andriy F. https://stackoverflow.com/a/13344966/10824788
//CREATES NEW JS & CSS TAGS RESPECTIVELY
function insertScript(doc, target, src, callback) {
var insertjs = doc.createElement("script");
insertjs.type = "text/javascript";
insertjs.src = src;
target.appendChild(insertjs);
}
function insertCss(doc, target, href, callback) {
var insertcss = doc.createElement("link");
insertcss.type = "text/css";
insertcss.rel = "stylesheet";
insertcss.href = href;
target.appendChild(insertcss);
}
//ADDS ABOVE TO IFRAME
$('#contframe').on('load', function(){
var context = this.contentDocument;
var frameHead = context.getElementsByTagName('head').item(0);
insertScript(context, frameHead, '/scripts/jquery.min.js');
insertScript(context, frameHead, '/scripts/content.js');
insertCss(context, frameHead, '/scripts/content.css');
});

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

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>

JavaScript: function fires in different order

I don't understand why function alert() fires before setting style to indicator in this code:
JavaScript:
var MyClass = function()
{
th = this;
th.func = function(){alert('yes');};
th.Click = function(){
document.getElementById('indicator').style.color = "#0f0";
document.getElementById('indicator').innerHTML = "YES";
th.func(); // here it fires before above style changing
};
th.Start = function()
{
var a = document.getElementById('button1');
a.addEventListener('click', th.Click, false);
};
th.Init = function()
{
th.Start();
};
}
var a = new MyClass().Init();
Html:
<button id='button1'>Click Me</button>
<div id='indicator' style='color:#f00'>NO</div>
I want it to fire after.
That is because of the Single Threaded Nature of the Javascript. The alert / modal window actually stops everything else from running until it is dismissed.
That includes the changing of color. Javascript actually says hey browser start changing colors and moves on but as it hits an alert the changing of colors or whatever processes that happen will be paused and it will not start continuing again until the modal window aka alert is dismissed. A workaround might be to do something like this: codepen
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<button id='button1'>Click Me</button>
<div id='indicator' style='color:#f00'>NO</div>
<script type="text/javascript">
var MyClass = function() {
th = this;
th.func = function() { window.alert('yes'); };
th.Click = function() {
document.getElementById('indicator').style.color = "#0f0";
document.getElementById('indicator').innerHTML = "YES";
// The setTimeout fix
// ====
setTimeout(th.func, 100);
};
th.Start = function()
{
var a = document.getElementById('button1');
a.addEventListener('click', th.Click, false);
};
th.Init = function()
{
th.Start();
};
}
var a = new MyClass().Init();
</script>
</body>
</html>

Creating two elements using js and then having access to them later in another function

I am building some js functionality where I will be creating 2 elements on a page
var createBtn = function(
var btn = document.createElement('button')
...
)
var createIframe = function(
var iframe = document.createElement('iframe')
...
)
Pretty basic stuff, but later on I want to add an event listener to the button that will apply a style attribute to the iframe.
Something like:
var displayIframe = function(
Iframe.style['display'] = 'block'
)
button.addEventListener('click', displayIframe)
My question is how can I access the elements after I have created them without going through the annoyance of attaching classes to them and accessing them all over again that way. Is there someway of getting access to them in the create functions from the beginning.
Your codes is almost correct, but some changes is needed
var btn, iframe;
var createBtn = function () {
btn = document.createElement('button');
...
}
var createIframe = function () {
iframe = document.createElement('iframe');
...
}
Callback function
var displayIframe = function(){
iframe.style['display'] = 'block'
}
Attach click listener
btn.addEventListener('click', displayIframe);
Your mistakes:
you should declare btn and iframe as global variables to be accessible to other functions
function starts with { and ends with } not (, )
so far your codes is correct, without any error, but you won't see anything on the page because you have not attached your newly created elements to the body, For accomplish this try this function
function attachToBody(){
document.body.appendChild(btn);
document.body.appendChild(iframe);
}
In your example, I dont know why you use functions to create element, but you must have your point. Try this and let me know does this work for you.
//this is equivalent to: var btn = document.createElement('button');
var btn = (function(){
var btn = document.createElement('button');
return btn;
})();
var iframe = (function{
var iframe = document.createElement('iframe');
return iframe;
})();
document.getElementById("parentId").appendChild(btn);
document.getElementById("parentId").appendChild(iframe);
btn.addEventListener('click', function(){
iframe.style.display = "none";
});
var createBtn = function() {
var btn = document.createElement('button')
btn.setAttribute("id", "myButton");
return btn;
}
var createIframe = function() {
var iframe = document.createElement('iframe')
iframe.setAttribute("id", "myFrame");
return iframe;
}
document.body.appendChild(createBtn()); // Append button to body.
document.body.appendChild(createIframe()); // Append iFrame to body.
// Get Elements by Id.
var myButton = document.getElementById("myButton");
var myFrame = document.getElementById("myFrame");
// Add event listener.
myButton.addEventListener("click", function() {
myFrame.style.display = "none", false);
}

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>

Categories