In an application that I am building at the moment, I had need to “mash-up” content from different sources into a SharePoint site. This SharePoint site would;
- Use an iframe to pull in a list of content from another server
- Launch a modal dialog (AJAX style) overlaid on top of the SharePoint portal with an iframed form to action against the data
- Display validation errors from that form as another modal dialog (owned by the parent SharePoint page so as not to be size limited to the owning dialog).
A picture says a thousand words;
In this case, we’d want the SharePoint host page to offer two methods
- launchTool(url) – which will launch the given URL in an iframe within a modal jquery overlay (using boxy in my instance).
- displayValidation(message) – which will be called by the form iframe to display the validation messages if the form can’t be submitted
And this is where we have a problem. If everything was on the same server, it would all be quite happy with this scenario and all the components would play together nicely but in this instance the content is spread across different servers. In this case, we’re not allowed to build this level of interaction using JavaScript as the content doesn’t fulfil the “same origin policy” – which means content from different domains can’t interrogate each others DOM nor invoke methods etc against each other.
Working around this isn’t just as simple as putting the sites into a different zone in the browser etc, we have to do something a little more innovative. If you are in total control of your infrastructure you can set all of the content servers to have a fully qualified domain name – eg: sp.mysite.com and forms.mysite.com and then use the document.domain property in JavaScript to set the domain to the higher level domain ie: mysite.com (document.domain = “mysite.com”) – but this does cause problems in my scenario where the SSRS report viewer web part in sharepoint doesn’t work (it does some funky stuff under the covers with iframes which fails miserably when we set document.domain in the host pages).
So, what can we do?
Well, the content from formserver can’t call anything within the sharepoint page and vice versa, but the formserver content could somehow create an iframe of it’s own with a special url on the sharepoint site that then calls the javascript we’re looking for in the sharepoint page. Clear as mud? No? here’s another diagram.
So, the list iframe doesn’t go back up the window stack to ask it’s parent to do something (which it has no rights to), it instead goes down – creating it’s own iframe and navigating it to a known page on the host and passes information to the page using a # bookmark. This known page then uses javascript on it’s page load event to determine what to do with the data passed in. If this indicates it should launch a modal dialog for a given URL, it passes the request to the overall parent, which, because it’s on the same domain, can be accessed.
It’s important to note the # part of the URL – by doing this, the cross domain receiver page can be fully cached in the browser, meaning there should be no lag between making the request down the stack to the parent actually processing that request.
I’ve wrapped the above into an API and built a sample that does the above, but also supports bi-directional message passing – so our host page has a list from another domain, it asks the host to display a form from yet another domain and this form requires confirmation, so it asks the host to display a message with options – the result of this message is then passed back down to the form.
Get the source code here: http://xdsframes.codeplex.com
(This isn’t a finished API in any way, just a starting off point for solving your own cross domain issues.)