I'm running a script in a UIWebView which sends data back to the host application (in Objective-C). If I put a link on the page pointing to myprotocol://some_data, I receive the information on the host side.
How can I achieve the same behaviour in pure Javascript, without user interaction? Something like a AJAX call, but not over HTTP?
I'm using AngularJS, but any solution in Javascript is welcome.
I found that there was no way to do this without "cheating" in some way. I decided to create a <a> element in my page and dynamically change its href attribute, then triggering the click event on it with Javascript. Here is what I did :
CSS
a#sendToiOS {
display:block;
position: fixed;
bottom: -1px;
right: -1px;
z-index: -1;
opacity: 0;
width: 1px;
height: 1px;
}
Javascript
var sendToiOS = function(protocol, action, params) {
var e = document.createElement('a');
e.id = 'sendToiOS';
var strParams = "";
if(typeof params !== 'undefined') {
Object.keys(params).forEach(function(key) {
strParams += strParams != "" ? '&' : '';
strParams += key+'='+encodeURI(params[key]);
});
}
e.href = strParams.length > 0 ? protocol+'://'+action+'?'+strParams : protocol+'://'+action;
document.getElementsByTagName('body')[0].appendChild(e);
e.click();
e.parentNode.removeChild(e);
}
Calling sendToiOS('mycustomprotocol', 'some_action', {foo: 'bar', foo2: 1337}); would then trigger a call to mycustomprotocol://some_action?foo=bar&foo2=1337.
OK, I dug around inside the guts of Cordova and it seems like they use an iframe bridge for this. Essentially they dynamically create an iframe (so the iframe domain is the same as the calling page), then update the iframe src to a custom protocol URL.
Interestingly the iframe bridge is a fallback mode for iOS4; they do use an XMLHttpRequest, but I'm not yet certain how they work around the same-domain policy.
EDIT: To do this they register a custom NSURLProtocol, and then issue a HEAD request along with the desired data.
If you want to take a closer look, search for the exec.js file inside the cordova-js.zip file which comes with Cordova. You can find the custom protocol as CDVURLProtocol.m inside cordova-ios.zip.
Related
I want to create a sticky note that appears on and webpage and as I type the contents is stored in the DB along with the URL as a reference
For example, I go to a BBC page, I click cmd+escap and my sticky note appears (it's a tampermonkey script)
function addEmbed(){
localStorage.setItem("myUniqueAPIcode", window.location);
var iframe = document.createElement("iframe");
iframe.type="text/html"
iframe.src="http://localhost:8080/webhighlights"
iframe.style.cssText = `position: absolute;
top: 0;
right: 0;
z-index: 999999;
height: 100vh;`
return iframe
}
That code works, in that the sticky note appears. It is a Vue page. But I can not access the local storage value
mounted() {
if (typeof Storage !== "undefined") {
if (localStorage.myUniqueAPIcode) {
this.api = localStorage.myUniqueAPIcode
}
}
},
};
I kind of know why, The tampermonkey script is setting the value on the BBC page, and the Vue code is looking in the localhost page.
But, before this, I tried to append the sticky form inside the page themselves but some websites didn't allow to perform fetch requests.
Is there a way to do this?
I know this question won't be well received but I searched far and long and can't find anything, probably not using the right keywords.
I own an online radio station and I want to create a js player that once added to a website will stay in the header on all the domains of the site. I first saw this thing on a tumblr music player(http://scmplayer.net/) , you would add their code to your page and once opened the player will stay as a header even if you browse to other sub-pages of your blog.
I'm searching for this to use in forums, where you change your page so often you can't listen to anything using a built-in radio player.
I found a similar solution by using a button that opens a really small pop-up with the player, but I'd like to know if it's possible to do what I want, and how.
Even a right link, query or term to search for would help me greatly, I don't want someone to do this for me, just point me in the right way.
Edit::
Here's some stuff I forgot to mention. I'm trying to build a code users can just copy paste into their website and have it work.
If it was only for me, I wouldn't be here, since I went trough iframes and jquery to load content too(see www.r4ge.ro).
I can't expect other people to tamper with their website only to embed my radio there, and I can't iframe their site content and add my radio as an index because that would ruin google ranking and indexing.
There are multiple ways of doing this, here goes one!
First thing, I'd personally use backbone.js - backbone.js allows you to create 'partial' views that can be updated independently of another. For your scenario, it seems ideal to create a header view and then a content view.
Both the header and the content could have their own logic, and update at separate times that you specify and under your control.
Take a look at http://backbonetutorials.com/why-would-you-use-backbone/ to get started. prepare yourself ample time to do a lot of reading and following tutorials. Backbone takes time to ramp up on, but once you get it, you'll be making some awesome apps!
You basically have three options:
The one you found, opening a really small pop-up (perhaps with just the media controls visible), so that when the user navigates, it isn't affected by the page being torn down.
The same thing using frames.
The same thing using ajax to load content when navigating instead of actually navigating.
As you didn't like #1 much, let's look at #2, then come back to #3.
When the use opens the player, you'd really be going to a page with the player and a very large iframe with the rest of the content:
<!doctype html>
<html>
<head>
<!-- ... -->
</head>
<body>
<!-- player here -->
<iframe class="main" src="main.html"></iframe>
</body>
</html>
You'd use CSS to make that as seamless as you could. To make it linkable, you could use a large fragment in the URL which is the URL of the page that should go in the frame, e.g.:
http://example.com/#forum.html§ion=23
When your main page loads, you grab the fragment, and use it as the src on the iframe.
You can listen for navigation events on the iframe and update the hash fragment on the main window, so that bookmarks work, and/or have JavaScript on each page of your site that might be navigated to that tells the container page (parent) what its URL is.
#3 is similar to #2 except that rather than letting navigation happen the normal way, you load everything via ajax as the user clicks around, loading it into (say) a main content div rather than an iframe. This can also use hash fragments to ensure that it's fully linkable/bookmarkable, etc., but requires that all links in the pages loaded get rewritten so they update the hash fragment rather than the main URL instead.
#2 and #3 (and #1) all have their advantages and disadvantages. #1 is probably the least work. #2 probably comes in second, then #3, but I could have those backward.
Here's a quick and dirty version of #2 that polls for hash updates so that the pages loaded in the frame don't have to know anything about this at all. Note that all you'd have to give to the other people is the page; their pages remain the same. If they're concerned about page rank, they'll want to include the canonical URL of their pages in the markup.
withplayer.html:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Example</title>
<style>
html, body {
padding: 0;
margin: 0;
}
html {
height: 100%;
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
height: 100%;
position: relative;
}
div.player {
height: 30px;
padding: 2px;
}
iframe.content {
border: none;
position: absolute;
top:30px;
width: 100%;
/*bottom: 0px; Sigh, this works on elements other than iframe, see 'resize' JavaScript below */
}
</style>
</head>
<body>
<div class="player"></div>
<iframe class="content"></iframe>
<script>
(function() {
// Fill in our "player"
var dt = new Date().toISOString();
document.querySelector(".player").innerHTML =
"This div is our pretend player: The div was loaded on " +
dt.substring(0, 10) + " at " + dt.substring(11, 19) + ".";
// Get the iframe
var content = document.querySelector(".content");
// Listen for hash changes
window.onhashchange = loadContent;
// Load any initial hash we have
loadContent();
// Get our current hash, without the leading #
function getHash() {
return location.hash.replace(/^#/, '');
}
// Get the hash equivalent of the current content in the content iframe
function getContentHash() {
var loc, hash;
loc = content && content.contentWindow && content.contentWindow.location;
hash = loc && loc != "about:blank" ? loc.pathname + loc.search + loc.hash : undefined;
return hash;
}
// Load the content for the current hash
function loadContent() {
// If we have an initial hash, apply to the iframe
var hash = getHash();
if (hash) {
content.src = hash;
}
}
// Poll for changes to the frame's location, update our hash if
// it doesn't match
setInterval(pollContent, 100);
function pollContent() {
var newHash;
newHash = getContentHash();
if (newHash !== undefined && newHash !== getHash()) {
location.hash = "#" + newHash;
}
}
// Stoopid iframes won't stick to the bottom, have to resize their height
resize();
window.onresize = resize;
function resize() {
content.style.height = (window.innerHeight - 30) + "px";
}
})();
</script>
</body>
</html>
How can I control the background image and colour of a body element within an iframe? Note, the embedded body element has a class, and the iframe is of a page that is part of my site.
The reason I need this is that my site has a black background assigned to the body, and then a white background assigned to divs that contain text. A WYSIWYG editor uses an iframe to embed content when editing, but it doesn't include the div, so the text is very hard to read.
The body of the iframe when in the editor has a class that isn't used anywhere else, so I'm assuming this was put there so problems like this could be solved. However, when I apply styles to class.body they don't override the styles applied to body. The weird thing is that the styles do appear in Firebug, so I've no idea what's going on!
Thanks
UPDATE - I've tried #mikeq's solution of adding a style to the class that is the body's class. This doesn't work when added to the main page's stylesheet, but it does work when added with Firebug. I'm assuming this is because Firebug is applied to all elements on the page whereas the CSS is not applied within iframes. Does this mean that adding the css after window load with JavaScript would work?
The below only works if the iframe content is from the same parent domain.
The following code works for me. Tested on Chrome and IE8. The inner iframe references a page that is on the same domain as the parent page.
In this particular case, I am hiding an element with a specific class in the inner iframe.
Basically, you just append a style element to the head section of the document loaded in a frame:
frame.addEventListener("load", ev => {
const new_style_element = document.createElement("style");
new_style_element.textContent = ".my-class { display: none; }"
ev.target.contentDocument.head.appendChild(new_style_element);
});
You can also instead of style use a link element, for referencing a stylesheet resource.
An iframe is a 'hole' in your page that displays another web page inside of it. The contents of the iframe is not in any shape or form part of your parent page.
As others have stated, your options are:
give the file that is being loaded in the iframe the necessary CSS
if the file in the iframe is from the same domain as your parent, then you can access the DOM of the document in the iframe from the parent.
You cannot change the style of a page displayed in an iframe unless you have direct access and therefore ownership of the source html and/or css files.
This is to stop XSS (Cross Site Scripting)
This code uses vanilla JavaScript. It creates a new <style> element. It sets the text content of that element to be a string containing the new CSS. And it appends that element directly to the iframe document's head.
Keep in mind, however, that accessing elements of a document loaded from another origin is not permitted (for security reasons) -- contentDocument of the iframe element will evaluate to null when attempted from the browsing context of the page embedding the frame.
var iframe = document.getElementById('the-iframe');
var style = document.createElement('style');
style.textContent =
'body {' +
' background-color: some-color;' +
' background-image: some-image;' +
'}'
;
iframe.contentDocument.head.appendChild(style);
Override another domain iframe CSS
By using part of SimpleSam5's answer, I achieved this with a few of Tawk's chat iframes (their customization interface is fine but I needed further customizations).
In this particular iframe that shows up on mobile devices, I needed to hide the default icon and place one of my background images. I did the following:
Tawk_API.onLoad = function() {
// without a specific API, you may try a similar load function
// perhaps with a setTimeout to ensure the iframe's content is fully loaded
$('#mtawkchat-minified-iframe-element').
contents().find("head").append(
$("<style type='text/css'>"+
"#tawkchat-status-text-container {"+
"background: url(https://example.net/img/my_mobile_bg.png) no-repeat center center blue;"+
"background-size: 100%;"+
"} "+
"#tawkchat-status-icon {display:none} </style>")
);
};
I do not own any Tawk's domain and this worked for me, thus you may do this even if it's not from the same parent domain (despite Jeremy Becker's comment on Sam's answer).
An iframe has another scope, so you can't access it to style or to change its content with javascript.
It's basically "another page".
The only thing you can do is to edit its own CSS, because with your global CSS you can't do anything.
This should work with cross domain if you're the owner of the both
The trick here is to assign a global css variable to your body, to listen message with the new color, and then to change the global css variable once receive a message.
I'm using angular, but it should work with pure javascript
My use case was to show to the user what he how the color change would impact his website in the iframe before saving it
Domain A
#ViewChildren('iframeContainer') iframeContainer: QueryList<ElementRef>
sendDataToIframe(
data = {
type: 'colorChange',
colors: {primary: '#000', secondary: '#fff'},
},
): void {
if (this.targetUrl)
this.iframeContainer.first.nativeElement.contentWindow.postMessage(data) // You may use document.getElementById('iframeContainer') instead
}
Domain B
acceptedEditOrigins = [
'https://my.origine.ccom', // Be sur to have a correct origin, to avoid xss injecto: https://en.wikipedia.org/wiki/Cross-site_scripting
]
constructor() {
// Listen to message
window.addEventListener('message', (event) => this.receiveMessage(event), false)
}
receiveMessage(event: MessageEvent) {
if (this.acceptedEditOrigins.includes(event.origin))
switch (event.data.type) {
case 'colorChange': {
this.setWebsiteConfigColor(event.data.colors)
}
}
}
setWebsiteConfigColor(colors: WebsiteConfigColors) {
if (colors) {
const root = document.documentElement
for (const [key, value] of Object.entries(colors)) {
root.style.setProperty(`--${key}`, value) // --primary: #000, --secondary: #fff
}
}
}
body {
background-color: var(--primary);
}
If you have control of the page hosting the iframe and the page of the iframe, you can pass a query parameter to the iframe...
Here's an example to add a class to the iframe based on whether or not the hosting site is mobile...
Adding iFrame:
var isMobile=$("mobile").length; //detect if page is mobile
var iFrameUrl ="https://myiframesite/?isMobile=" + isMobile;
$(body).append("<div id='wrapper'><iframe src=''></iframe></div>");
$("#wrapper iframe").attr("src", iFrameUrl );
Inside iFrame:
//add mobile class if needed
var url = new URL(window.location.href);
var isMobile = url.searchParams.get("isMobile");
if(isMobile == "1") {
$("body").addClass("mobile");
}
For juste one iframe, you can do something like this:
document.querySelector('iframe').contentDocument.body.style.backgroundColor = '#1e1e2d';
In case you have multiple iframe you're dealing with:
document.querySelectorAll('iframe').forEach((iframe) => {
iframe.contentDocument.body.style.backgroundColor = '#1e1e2d';
});
Perhaps it's changed now, but I have used a separate stylesheet with this element:
.feedEkList iframe
{
max-width: 435px!important;
width: 435px!important;
height: 320px!important;
}
to successfully style embedded youtube iframes...see the blog posts on this page.
give the body of your iframe page an ID (or class if you wish)
<html>
<head></head>
<body id="myId">
</body>
</html>
then, also within the iframe's page, assign a background to that in CSS
#myId {
background-color: white;
}
I have an iframe as you can see on the following link;-
http://one2onecars.com
The iframe is the online booking in the centre of the screen. The problem I have is that although the height of the iframe is okay as the page loads, I need it to somehow auto adjust the height as the page content adjusts. For example, if I do a postcode search in the online booking it creates a dropdown menu and then makes the 'Next Step' button not viewable.
What I need to happen is that when the content of the online booking changes, the iframe auto adjusts to the new height of the iframe (dynamically) as it is not loading any other pages.
I have tried several different scripts using jquery to try resolving this issue, but they all only seem to auto adjust the height of the iframe when the page first loads and not as the contents of the iframe changes.
Is this even possible to do?
The code I have at the moment is with a set height at the moment:-
<div id="main-online-booking">
<iframe id="main-online-frame" class="booking-dimensions" src="http://www.marandy.com/one2oneob/login-guest.php" scrolling="no" frameborder="0"></iframe>
</div>
#main-online-booking {
height: 488px;
border-bottom: 6px #939393 solid;
border-left: 6px #939393 solid;
border-right: 6px #939393 solid;
z-index: 4;
background-color: #fff;
}
.booking-dimensions {
width: 620px;
height: 488px;
}
If anybody can help me with this I would be much appreciated!
setInterval
The only (corrected due to advances in browser tech, see David Bradshaw's answer) backwards compatible way to achieve this with an iframe is to use setInterval and keep an eye on the iframe's content yourself. When it changes its height, you update the size of the iframe. There is no such event you can listen out for that will make it easy unfortunately.
A basic example, this will only work if the iframe content that has changed in size is part of the main page flow. If the elements are floated or positioned then you will have to target them specifically to look for height changes.
jQuery(function($){
var lastHeight = 0, curHeight = 0, $frame = $('iframe:eq(0)');
setInterval(function(){
curHeight = $frame.contents().find('body').height();
if ( curHeight != lastHeight ) {
$frame.css('height', (lastHeight = curHeight) + 'px' );
}
},500);
});
Obviously depending on what you want you can modify the perspective of this code so that it works from the iframe, on itself, rather than expecting to be part of the main page.
cross-domain issue
The problem you will find is that due to browser security it wont let you access the content of the iframe if it is on a different host to the main page, so there isn't actually anything you can do unless you have a way of adding any script to the html that appears in the iframe.
ajax
Some others are suggesting trying to use the third-party service via AJAX, unless the service supports this method it will be very unlikely you'll be able to get it to work -- especially if it is a booking service that will most likely need to operate over https/ssl.
As it appears you have full control over the iframe content, you have full options open to you, AJAX with JSONP would be an option. However, one word of warning. If your booking system is multistepped you need to make sure you have a well designed UI -- and possibly some history/fragment management code -- if you are to go down the AJAX route. All because you can never tell when a user will decide to navigate forward or back in their browser (which an iframe would automatically handle, within reason). A well designed UI can detract users from doing this.
cross-domain communication
If you have control of both sides (which it sounds like you do) you also have the cross domain communication option using window.postMessage - see here for more information https://developer.mozilla.org/en-US/docs/DOM/window.postMessage
Modern browser and in part IE8 have some new features that make this task easier than it use to be.
PostMessage
The postMessage API provides a simple method for comunicating between an iFrame and it's parent.
To send a message to the parent page you call it as follows.
parent.postMessage('Hello parent','http://origin-domain.com');
In the other direction we can send the message to the iFrame with the following code.
var iframe = document.querySelector('iframe');
iframe.contentWindow.postMessage('Hello my child', 'http://remote-domain.com:8080');
To recevie a message create an event listerner for the message event.
function receiveMessage(event)
{
if (event.origin !== "http://remote-domain.com:8080")
return;
console.log(event.data);
}
if ('addEventListener' in window){
window.addEventListener('message', receiveMessage, false);
} else if ('attachEvent' in window){ //IE
window.attachEvent('onmessage', receiveMessage);
These examples uses the origin property to limit where the message is sent to and to check where it came from. It is possible to specify * to allow sending to any domain and you may in some cases you may want to accept messages from any domain. However, if you do this you need to consider the security implications and implement your own checks on the incoming message to ensure it contains what your expecting. In this case the iframe can post it's height to '*', as we might have more than one parent domain. However, it's a good idea to check incoming messages are from the iFrame.
function isMessageFromIFrame(event,iframe){
var
origin = event.origin,
src = iframe.src;
if ((''+origin !== 'null') && (origin !== src.substr(0,origin.length))) {
throw new Error(
'Unexpect message received from: ' + origin +
' for ' + iframe.id + '. Message was: ' + event.data
);
}
return true;
}
MutationObserver
The other advance in more modern broswers is MutationObserver which allows you to watch for changes in the DOM; so it is now possible to detect changes that could effect the size of the iFrame without having to constantly poll with setInterval.
function createMutationObserver(){
var
target = document.querySelector('body'),
config = {
attributes : true,
attributeOldValue : false,
characterData : true,
characterDataOldValue : false,
childList : true,
subtree : true
},
observer = new MutationObserver(function(mutations) {
parent.postMessage('[iframeResize]'+document.body.offsetHeight,'*');
});
log('Setup MutationObserver');
observer.observe(target, config);
}
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
if (MutationObserver){
createMutationObserver();
}
Working out an accurate height
Getting an accurate height for the iFrame is not as simple as it should be, as you have a choice of six different properties that you can check and none of them give a constantly right answer. The best solution I've come up with is this function that works so long as you don't use CSS to overflow the body tag.
function getIFrameHeight(){
function getComputedBodyStyle(prop) {
return parseInt(
document.defaultView.getComputedStyle(document.body, null),
10
);
}
return document.body.offsetHeight +
getComputedBodyStyle('marginTop') +
getComputedBodyStyle('marginBottom');
}
This is the IE9 version, for the much long IE8 version see this answer.
If you do overflow the body and you can't fix your code to stop this, then using either the offsetHeight or scrollHeight properties of document.documentElement are your best options. Both have pros and cons and it best just to test both and see which works for you.
Other issues
Other things to consider include, having more than one iFrame on the page, CSS :Checkbox and :Hover events causing page resize, avoiding the use of height auto in the iFrames' body and html tags and lastly the window being resized.
IFrame Resizer Library
I've wrapped all this up in a simple dependancy free library, that also provides some extra functions not discussed here.
https://github.com/davidjbradshaw/iframe-resizer
This works with IE8+.
I wrote this script and it's working perfectly for me. Feel free to use it!
function ResizeIframeFromParent(id) {
if (jQuery('#'+id).length > 0) {
var window = document.getElementById(id).contentWindow;
var prevheight = jQuery('#'+id).attr('height');
var newheight = Math.max( window.document.body.scrollHeight, window.document.body.offsetHeight, window.document.documentElement.clientHeight, window.document.documentElement.scrollHeight, window.document.documentElement.offsetHeight );
if (newheight != prevheight && newheight > 0) {
jQuery('#'+id).attr('height', newheight);
console.log("Adjusting iframe height for "+id+": " +prevheight+"px => "+newheight+"px");
}
}
}
You can call the function inside a loop:
<script>
jQuery(document).ready(function() {
// Try to change the iframe size every 2 seconds
setInterval(function() {
ResizeIframeFromParent('iframeid');
}, 2000);
});
</script>
ResizeObserver allows your code to remain encapsulated inside the iframe and decoupled from the outer scope (i.e., versus postMessage), and it is ligher weight than the general-purpose MutationObserver.
Simple example below (or good example at Mozilla):
const myElement = document.getElementById('my-element');
const resizeObserver = new ResizeObserver((entries) => {
const dims = myElement.getBoundingClientRect(); // or see Mozilla for `entries` example
console.log(`new height (${dims.height}) and width (${dims.width})`);
});
resizeObserver.observe(myElement);
use this script:
$(document).ready(function () {
// Set specific variable to represent all iframe tags.
var iFrames = document.getElementsByTagName('iframe');
// Resize heights.
function iResize() {
// Iterate through all iframes in the page.
for (var i = 0, j = iFrames.length; i < j; i++) {
// Set inline style to equal the body height of the iframed content.
iFrames[i].style.height = iFrames[i].contentWindow.document.body.offsetHeight + 'px';
}
}
// Check if browser is Safari or Opera.
if ($.browser.safari || $.browser.opera) {
// Start timer when loaded.
$('iframe').load(function () {
setTimeout(iResize, 0);
});
// Safari and Opera need a kick-start.
for (var i = 0, j = iFrames.length; i < j; i++) {
var iSource = iFrames[i].src;
iFrames[i].src = '';
iFrames[i].src = iSource;
}
} else {
// For other good browsers.
$('iframe').load(function () {
// Set inline style to equal the body height of the iframed content.
this.style.height = this.contentWindow.document.body.offsetHeight + 'px';
});
}
});
Note : use it on webserver.
I am trying to create a bookmarklet, so that when you click on it, it will load example.com/yourdata.php in a div box.
How can I make it get the data from example.com?
IFRAME? or is there a better solution?
You may have issues with creating a bookmarklet within another page that grabs data from a different domain (to load into a <div /> using Ajax).
Your best option is probably to insert an IFrame with the content as the source of the page.
If you want to do this as a very basic lightbox, you could do something like this:
(function() {
var iFrame = document.createElement('IFRAME');
iFrame.src = 'http://google.com';
iFrame.style.cssText = 'display: block; position:absolute; '
+ 'top: 10%; left: 25%; width: 50%; height: 50%';
document.body.insertBefore(iFrame, document.body.firstChild);
})();
And here is the same code in bookmarklet format:
javascript: (function() { var iFrame = document.createElement('IFRAME'); iFrame.src = 'http://google.com'; iFrame.style.cssText = 'display: block; position:absolute; top: 10%; left: 25%; width: 50%; height: 50%'; document.body.insertBefore(iFrame, document.body.firstChild); })();
You could also style this a lot more if you wanted something pretty. This is just a basic example of what is possible. As another person said, it would be easiest to make it pretty by loading jQuery using an Ajax request, but that is a little more involved.
Do an AJAX call directly in your bookmarklet, and then set the innerHTML of your div to the returned content. Not sure if there are security restrictions on this or not.
Edit: You don't want to use JQuery, as you can't easily load a javascript library from a bookmarklet. (Although maybe you could get it via AJAX and then eval it...)
You need to do a classic XMLHttpRequest.
Some more info here.
With The Dojo Toolkit you can use dijit.layout.ContentPane or dojox.layout.ContentPane to do exactly what you want in one single div.
The difference between dijit.layout.ContentPane and dojox.layout.ContentPane is that you can run inline javascript inside the dojox.layout.ContentPane.
I got around the domain restriction by making a php function on my server that outputs a page on another domain. that way, javascript thinks it is in the same domain when I do an ajax.updater call.
$sSrcPage = $_REQUEST['SrcPage'];
echo file_get_contents($sSrcPage, 0);