PDA

View Full Version : port crossFrame based on YUI to EXT



dolittle
29 Jan 2008, 6:32 AM
crossFrame (http://www.julienlecomte.net/blog/2007/11/31/) based on YUI allows cross-frame and cross domain communication demo (http://www.julienlecomte.net/blogfiles/cross-frame/):


In order to communicate with the mashup hosted in domain Y, the page, hosted in domain X, dynamically creates a hidden IFrame and points it to a special proxy file hosted in domain Y, using the URL fragment identifier to convey the message (step 1) When the special proxy file is loaded in the hidden IFrame, it reads its URL fragment identifier and passes it to a globally accessible function defined in the IFrame hosting the mashup (step 2) using parent.frames['mashup'] to get to it. The same technique can also be used by the mashup to communicate with the page (the proxy will use parent.parent to get to the page) Finally, when all is said and done, the hidden IFrame is automatically removed from the DOM by the library.

The proxy.html is being cached on the client so there is no round trip to the server.

The code includes cross-frame.js, proxy.html and yahoo-dom-event.js.
Because the code is loaded both in the parent frame and in the hosted iframe, it's important to keep it small. I need help from EXT experts to port it to EXT.
What are the minimum Ext files I should include and what are the equivalent to YUI methods?

To receive messages, subscribe to the onMessage event:


YAHOO.util.CrossFrame.onMessageEvent.subscribe(
function (type, args, obj) {
var message = args[0];
var domain = args[1];
// Do something with the incoming message...
}
);

To send a message, call YAHOO.util.CrossFrame.send():


YAHOO.util.CrossFrame.send("http://www.y.com/proxy.html",
"frames['mashup']",
"message");

cross-frame.js:

/**
* IFrame Message Routing Utility.
* Author: Julien Lecomte <jlecomte@yahoo-inc.com>
* Copyright (c) 2007, Yahoo! Inc. All rights reserved.
* Code licensed under the BSD License:
* http://developer.yahoo.net/yui/license.txt
*
* @requires yahoo, event
* @namespace YAHOO.util
* @title IFrame Message Routing Utility
*/

/**
* The CrossFrame singleton allows iframes to safely communicate even
* if they are on different domains. This utility requires a proxy HTML
* file (proxy.html)
*
* @class CrossFrame
*/
YAHOO.util.CrossFrame = (function () {

var r1 = /^(((top|parent|frames\[((['"][a-zA-Z\d-_]*['"])|\d+)\]))(\.|$))+/;
var r2 = /top|parent|frames\[(?:(?:['"][a-zA-Z]*['"])|\d+)\]/;

function parseQueryString(s) {

var r, a, p;

r = {};
a = s.split('&');
for (i = 0; i < a.length; i++) {
p = a[i].split('=');
if (p.length === 2 && p[0].length > 0) {
r[p[0]] = unescape(p[1]);
}
}

return r;
}

if (YAHOO.env.ua.opera) {

// Opera does not allow reading any property (including parent, frames)
// if the domain of the caller and the domain of the target window do
// not match. We work around this by chaining calls, and using Opera's
// postMessage function...
document.addEventListener("message", function (evt) {
var o = parseQueryString(evt.data);
if (YAHOO.lang.hasOwnProperty(o, "target") &&
YAHOO.lang.hasOwnProperty(o, "message") &&
YAHOO.lang.hasOwnProperty(o, "domain") &&
YAHOO.lang.hasOwnProperty(o, "uri")) {
if (o.target.length > 0) {
// Send the message to the next document in the chain.
YAHOO.util.CrossFrame.send(null, o.target, o.message, o.domain, o.uri);
} else {
// Let the application know a message has been received.
YAHOO.util.CrossFrame.onMessageEvent.fire(o.message, o.domain, o.uri);
}
}
}, false);

}

return {

/**
* Fired when a message is received.
*
* @event onMessageEvent
*/
onMessageEvent: new YAHOO.util.CustomEvent("onMessage"),

/**
* Sends a message to an iframe, using the specified proxy.
*
* @method send
* @param {string} proxy Complete path to the proxy file.
* @param {string} target Target iframe e.g: parent.frames["foo"]
* @param {string} message The message to send.
*/
send: function (proxy, target, message) {

var m, t, d, u, s, el;

// Match things like parent.frames["aaa"].top.frames[0].frames['bbb']
if (!r1.test(target)) {
throw new Error("Invalid target: " + target);
}

if (YAHOO.env.ua.opera) {

// Opera is the only A-grade browser that does not allow
// reading properties like parent.frames when this document and
// its parent are on separate domains. The solution is to use
// the parent as a "hub" to route messages to the appropriate
// IFrame, and use the Opera's postMessage function...

m = r2.exec(target);
// safe to eval...
t = eval(m[0]).document;

// Remove one element from the target chain.
target = target.substr(m[0].length + 1);

// Compose the message...
d = arguments.length > 3 ? arguments[3] : document.domain;
u = arguments.length > 4 ? arguments[4] : location.href;
s = "target=" + escape(target) +
"&message=" + escape(message) +
"&domain=" + escape(d) +
"&uri=" + escape(u);

// ...and send it!
t.postMessage(s);

} else {

// Create a new hidden iframe.
el = document.createElement("iframe");
el.style.position = "absolute";
el.style.visibility = "hidden";
el.style.top = el.style.left = "0";
el.style.width = el.style.height = "0";
document.body.appendChild(el);

// Listen for the onload event.
YAHOO.util.Event.addListener(el, "load", function () {
// First, remove the event listener or the iframe
// we intend to discard will not be freed...
YAHOO.util.Event.removeListener(this, "load", arguments.callee);
// Discard the iframe...
setTimeout(function () {
document.body.removeChild(el);
}, 1000);
});

// Compose the message...
s = "target=" + escape(target) +
"&message=" + escape(message) +
"&domain=" + escape(document.domain) +
"&uri=" + escape(location.href);

// Set its src first...
el.src = proxy + "#" + s;

// ...and then append it to the body of the document.
document.body.appendChild(el);
}
}
};

})();

proxy.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head><title></title></head>
<body>
<script type="text/javascript">

(function () {

var r, o, t;

// This function is copied from yahoo.js.
// This keeps this file free of dependencies.
function hasOwnProperty(o, prop) {

if (Object.prototype.hasOwnProperty) {
return o.hasOwnProperty(prop);
}

return typeof o[prop] !== "undefined" &&
o.constructor.prototype[prop] !== o[prop];
}

function parseQueryString(s) {

var r, a, p;

r = {};
a = s.split('&');
for (i = 0; i < a.length; i++) {
p = a[i].split('=');
if (p.length === 2 && p[0].length > 0) {
r[p[0]] = unescape(p[1]);
}
}

return r;
}

// Match things like parent.frames["aaa"].top.frames[0].frames['bbb']
r = /^(?:(?:(top|parent|frames\[(?:(?:['"][a-zA-Z\d-_]*['"])|\d+)\]))(?:\.|$))+/;

o = parseQueryString(location.hash.substr(1));

// The following properties may be missing as a result of preloading
// this file for example. Simply do nothing in that case...
if (hasOwnProperty(o, "target") && hasOwnProperty(o, "message") &&
hasOwnProperty(o, "domain") && hasOwnProperty(o, "uri")) {

if (!r.test(o.target)) {
throw new Error("Invalid target: " + o.target);
}

// Safe to eval...
t = eval("parent." + o.target);

// Let the application know a message has been received.
t.YAHOO.util.CrossFrame.onMessageEvent.fire(o.message, o.domain, o.uri);
}

})();

</script>
</body>
</html>