Usually we put our JavaScript <script> tags at the bottom of an HTML document, right before the closing </body> tag, with the benefit that they are executed after all the elements are already available in the DOM and some more things.
However, I'm using a frame document1 which does have a <frameset> instead of a <body> tag. I don't want to put them in the <head> of the document because they wouldn't have immediate access the DOM elements below3. And I don't want to use <iframe>s in a standard body tag either4. I've tried
<head>
<title>Framesets are interesting</title>
</head>
<frameset cols="50%,50%">
<frame id="frame-a" src="a.html">
<frame id="frame-b" src="b.html">
<script type="text/javascript">
console.log("hello world!");
console.log(document.getElementById("frame-a")); // this is what I'm after
</script>
</frameset>
However, the script was not executed at all, it didn't even show up in the DOM inspector. Sure, a <frameset> may only contain <frame> and <noframes> tags. But, is there really no way to get scripts execute after a <frame> tag?
Just for reference, placing them after </frameset> like it's sometimes done with <body>s doesn't work either.
1: Yes, I know they're deprecated. They were just the natural choice2 for my project, a neat side-by-side view that shows two documents and scrolls them together in a sophisticated manner.
2: …and I never used them before, so I wanted to give it a try.
3: That is what I ended up with, after all an onload handler is trivial. Still the question remains, I'm curious.
4: works fine, but requires intricate CSS styling
A <script> element can only appear in either a <head> element or <body> element. It cannot appear as a child of a <frameset> element; a <frameset> can only contain <frame> elements, <noframes> elements, or other <frameset> elements. See the Transitional DTD:
<!ELEMENT FRAMESET - - ((FRAMESET|FRAME)+ & NOFRAMES?) -- window subdivision-->
Normally, browsers are happy to insert elements into other elements where they don't belong in complete defiance of what the DTD says since the DTD is just a rulebook, but this doesn't always happen (for example, you can never put any other flow element into an HTMLParagraphElement no matter how hard you try), so if a browser is refusing to place an HTMLScriptElement in an HTMLFrameSetElement, chances are this is why.
Any workarounds will involve placing a <script> element in either the frameset's <head> element, or within one of the frames. (You can also place a <script> element within a <noframes> element since <noframes> has the same content model as <body>, but this won't solve your problem for obvious reasons.)
Similar problem was solved here: Dynamically set frame src using javascript
<head>
<title>Framesets are interesting</title>
<script type="text/javascript">
function LoadPage(){
console.log("hello world!");
console.log(document.getElementById("frame-a")); // this is what I'm after
}
</script>
</head>
<frameset cols="50%,50%" onload="LoadPage();">
<frame id="frame-a" src="a.html">
<frame id="frame-b" src="b.html">
</frameset>
You can put the script by inserting a frame with a data URI:
<head>
<title>Framesets are interesting</title>
</head>
<frameset cols="50%,50%">
<frame id="frame-a" src="a.html">
<frame id="frame-b" src="b.html">
<frame src="data:text/html,<script type='text/javascript'>with(parent) {
console.log('hello world!');
console.log(document.getElementById('frame-a'));
}</script>">
</frameset>
Of course, you will need to be careful with quotes, and the script will run in another realm. You can use parent or top to access the window of the outer document.
Related
Background
I am attempting to read (and eventually change) content within the body of an IFrame (in my example this involves h1 tags) embedded in a Confluence page.
Confluence Behavior
Initially I didn't think it was significant, but as comments by #ScottMarcus illustrate; it does matter that this work is for a possible Confluence plugin. This is because I am using a page decorator containing JavaScript that executes when a user edits a Confluence page.
IFrame Restrictions
This means that (to my knowledge) I cannot have JavaScript execute after the editable IFrame has been added to the DOM. It also means that I cannot control what content is added to the IFrame (although this is OK/expected, as the idea is to enhance the user experience if they add tables and install the plugin).
Example
For reference, here is what the wysiwyg Confluence editor looks like for my page (annotated with a couple key elements from my HTML below):
Problem
Although I have been able to read/log the HTML present within the IFrame, I cannot seem to access elements in the same way I am able to within the main document. I have tried different variations on what I have below, doing things like...
selecting elements by ID--for some reason this seems less reliable in this context?
trying to get the contents() or children() of elements--in many cases I get null reference exceptions when trying this
accessing the body from my IFrame object--again, this doesn't seem the same as doing document.body
JavaScript
function doStuff() {
$('#wysiwygTextarea_ifr').ready(function () {
let iFrame = document.getElementById('wysiwygTextarea_ifr');
let frameDoc = iFrame.contentDocument ? iFrame.contentDocument : iFrame.contentWindow.document;
let h1Tags = frameDoc.getElementsByTagName('h1');
//would like to iterate over the collection of h1 tags here, but it always seems to be empty
});
}
HTML
<!DOCTYPE html>
<html>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="../Libraries/main.js" type="text/javascript"></script>
<script type="text/javascript">
doStuff();
</script>
<iframe id="wysiwygTextarea_ifr">
#document
<!DOCTYPE html>
<html>
<head>
<title>blah</title>
</head>
<body id="tinymce">
<h1 id="meh">abcde table</h1>
<h1 id="neh">zzz</h1>
</body>
</html>
</iframe>
</html>
In this case i have two HTML page (just let say two)
named index.html and list.html
index.html
<html>
<head>
<title>Frame</title>
</head>
<frameset rows="20%,80%" bordercolor='blue' noresize id="judul">
<frame src="Judul.html" id="atas">
<frameset cols="15%,85%" id="kolom">
<frame src="list.html" id="daftar">
<frame src="new 2.html" id="tengah">
</frameset>
</frameset>
</html>
list.html
<html>
<head>
<title>List</title>
</head>
<body>
Main page
About Us
</body>
</html>
So what i want is when the link from list.html call the page the targetted frame will show a loading GIF and then hide it when the load complete.
And the question is what code should i put there ? and where should i put it ?
and please make it as detail as possible,since i'm very new to HTML and it's stuff
and thanks for all suggestion
The best way is still CSS or Jquery since framesets are deprecated anyway...
Example CSS, using the :hover modifier (assuming you have onhover trigger function):
.myloading_gif {
display: none:
}
.myloading_gif:hover {
display: block:
}
If its a click element you cannot solve it with CSS, then you should consider JQuery:
$("#myHrefID").click(function() {
$("#myLoadingIcon").toggle();
});
And when the loading is finished just call "toggle" again.
$("#myLoadingIcon").toggle();
There are many ways to achieve this. My examples just should be just a little help since I am not 100% sure that I got your point.
My site is setup like this:
<frameset rows="80,*">
<frame name="top" id="top" src="header.html">
<frameset id="innerframe" cols="300,*">
<frame name="nav" src="nav.html">
</frameset>
</frameset>
In header.html I have:
function fAlert() {
alert('test');
}
How can I call fAlert() in nav.html?
I tried
var fframe = parent.document.getElementById('top');
fframe.fAlert();
and also
parent.frames.top.fAlert();
but it didnt work (fAlert is undefined).
Any ideas how I can accomplish this?
First off, don't use framesets and frames. Use iframes--frames are deprecated.
Secondly, provide an id for the iframe (or frame, if you must) in order to direct the function call correctly. (You've already pretty much done this, but I'm being methodical.) I wouldn't name it 'top' because 'top' already has a meaning in terms of windows and frames.
From inside the nav frame, parent.insertYourFrameIdHere.fAlert() should work correctly. This assumes two things: 1) The page and the frame contents come from the same domain, and 2) header.html loaded correctly and there were no script errors in it. Script errors or other issues could keep the function from ever being created.
For the html in your question following should work.
window.parent.parent.frames[0].fAlert();
For a frameset, i want to open a link from page of A frame by using onmouseover and open it in another B frame? when mouseover the link from A frame, it will open the page on B frame. Give a hint.
When I worked with <frame> it has taking a long time ago (seven or more years).
Because you didn't post any html sourcode :-|, I created a theoretical situation:
<html>
<head>
<script type="text/javascript">
function nullRand () {
//document.getElementById("frameBid").src = "myNewInternalPage.html";
document.getElementById("frameBid").src = document.getElementById("frameAid").src;
}
</script>
</head>
<frameset cols="25,*" frameborder="no" border="0" framespacing="0" framepadding="0">
<frame id="frameAid" name="frameAname" src="myHtmlFile.html" noresize>
<frame id="frameBid" name="frameBname" src="" noresize>
</frameset>
</html>
SIn my theoretical file 'myNewInternalPage.html' you have to instert the method call
An link
Note: frame is not approiate to show external content. That's why iframe exists.
Update:
After a hard fight with the OP I got something to my hands. Here is a solution:
1st: Replace the old Javascript code from 'nullRand()' with the new one
function nullRand (linkObject)
{
document.getElementById("frameBid").src = linkObject.href; // The new way to access to a frame
//top.frames["center"]..src = linkObject.href; <-- The old way to access to a frame */
}
2nd: Modyfiy the a tag -where the radio streams are listed- as follow:
...
So it should work. In my eyes you should think about a new concept for your task.
I am using frameset in my page. In the frameset i have taken two frames and in the first frame i have written some javascript code. How the javascript function of the frame will call the javascript function of the main page.
Can anyone please help :)
This will do it :
parent.FrameName.FunctionName()
If your frames are set up like this:
<frameset rows="50, 50">
<frame src="menu.html" name="menu">
<frame src="main.html" name="main">
</frameset>
Then you can access functions in the frame named main from the frame named menu using top.main.functionName().
parent.main.functionName() will also work in this case, but if you have more nested levels of frames then I find it less confusing to reference top (which is always the topmost frame) and 'drill down'.