source: Dev/branches/rest-dojo-ui/client/dojox/io/windowName.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 8.1 KB
Line 
1define(["dojo/_base/kernel", "dojo/_base/window", "dojo/_base/xhr", "dojo/_base/sniff", "dojo/_base/url", "dojo/domReady!"], function(dojo){
2dojo.getObject("io.windowName", true, dojox);
3// Implements the window.name transport
4
5dojox.io.windowName = {
6        send: function(/*String*/ method, /*dojo.__IoArgs*/ args){
7                // summary:
8                //              Provides secure cross-domain request capability.
9                //              Sends a request using an iframe (POST or GET) and reads the response through the
10                //              frame's window.name.
11                //
12                //      method:
13                //              The method to use to send the request, GET or POST
14                //
15                //      args:
16                //              See dojo.xhr
17                //
18                //      args.authElement: DOMNode?
19                //              By providing an authElement, this indicates that windowName should use the
20                //              authorized window.name protocol, relying on
21                //              the loaded XD resource to return to the provided return URL on completion
22                //              of authorization/authentication. The provided authElement will be used to place
23                //              the iframe in, so the user can interact with the server resource for authentication
24                //              and/or authorization to access the resource.
25                //
26                //      args.onAuthLoad: Function?
27                //              When using authorized access to resources, this function will be called when the
28                //              authorization page has been loaded. (When authorization is actually completed,
29                //              the deferred callback function is called with the result). The primary use for this
30                //              is to make the authElement visible to the user once the resource has loaded
31                //              (this can be preferable to showing the iframe while the resource is loading
32                //              since it may not require authorization, it may simply return the resource).
33                //
34                //      description:
35                //              In order to provide a windowname transport accessible resources/web services, a server
36                //              should check for the presence of a parameter window.name=true and if a request includes
37                //              such a parameter, it should respond to the request with an HTML
38                //              document that sets it's window.name to the string that is to be
39                //              delivered to the client. For example, if a client makes a window.name request like:
40                //      |       http://othersite.com/greeting?windowname=true
41                //              And server wants to respond to the client with "Hello", it should return an html page:
42                // |    <html><script type="text/javascript">
43                // |    window.name="Hello";
44                // |    </script></html>
45                //              One can provide XML or JSON data by simply quoting the data as a string, and parsing the data
46                //              on the client.
47                //              If you use the authorization window.name protocol, the requester should include an
48                //              authElement element in the args, and a request will be created like:
49                //      |       http://othersite.com/greeting?windowname=auth
50                //              And the server can respond like this:
51                // |    <html><script type="text/javascript">
52                // |    var loc = window.name;
53                // |    authorizationButton.onclick = function(){
54                // |            window.name="Hello";
55                // |            location = loc;
56                // |    };
57                // |    </script></html>
58                //              When using windowName from a XD Dojo build, make sure to set the
59                //              dojo.dojoBlankHtmlUrl property to a local URL.
60                args.url += (args.url.match(/\?/) ? '&' : '?') + "windowname=" + (args.authElement ? "auth" : true); // indicate our desire for window.name communication
61                var authElement = args.authElement;
62                var cleanup = function(result){
63                        try{
64                                // we have to do this to stop the wait cursor in FF
65                                var innerDoc = dfd.ioArgs.frame.contentWindow.document;
66                                innerDoc.write(" ");
67                                innerDoc.close();
68                        }catch(e){}
69                        (authElement || dojo.body()).removeChild(dfd.ioArgs.outerFrame); // clean up
70                        return result;
71                }
72                var dfd = dojo._ioSetArgs(args,cleanup,cleanup,cleanup);
73                if(args.timeout){
74                        setTimeout(function(){
75                                        if(dfd.fired == -1){
76                                                dfd.callback(new Error("Timeout"));
77                                        }
78                                },
79                                args.timeout
80                        );
81                }
82                dojox.io.windowName._send(dfd, method, authElement, args.onAuthLoad);
83                return dfd;
84        },
85        _send: function(dfd, method, authTarget, onAuthLoad){
86
87                var ioArgs = dfd.ioArgs;
88                var frameNum = dojox.io.windowName._frameNum++;
89                var sameDomainUrl = (dojo.config.dojoBlankHtmlUrl||dojo.config.dojoCallbackUrl||dojo.moduleUrl("dojo", "resources/blank.html")) + "#" + frameNum;
90                var frameName = new dojo._Url(window.location, sameDomainUrl);
91                var doc = dojo.doc;
92                var frameContainer = authTarget || dojo.body();
93                function styleFrame(frame){
94                        frame.style.width="100%";
95                        frame.style.height="100%";
96                        frame.style.border="0px";
97                }
98                if(dojo.isMoz && ![].reduce){
99                        // FF2 allows unsafe sibling frame modification,
100                        // the fix for this is to create nested frames with getters and setters to protect access
101                        var outerFrame = doc.createElement("iframe");
102                        styleFrame(outerFrame);
103                        if(!authTarget){
104                                outerFrame.style.display='none';
105                        }
106                        frameContainer.appendChild(outerFrame);
107
108                        var firstWindow = outerFrame.contentWindow;
109                        doc = firstWindow.document;
110                        doc.write("<html><body margin='0px'><iframe style='width:100%;height:100%;border:0px' name='protectedFrame'></iframe></body></html>");
111                        doc.close();
112                        var secondWindow = firstWindow[0];
113                        firstWindow.__defineGetter__(0,function(){});
114                        firstWindow.__defineGetter__("protectedFrame",function(){});
115                        doc = secondWindow.document;
116                        doc.write("<html><body margin='0px'></body></html>");
117                        doc.close();
118                        frameContainer = doc.body;
119                }
120                var frame;
121                if(dojo.isIE){
122                        var div = doc.createElement("div");
123                        div.innerHTML = '<iframe name="' + frameName + '" onload="dojox.io.windowName['+frameNum+']()">';
124                        frame = div.firstChild;
125                }else{
126                        frame = doc.createElement('iframe');
127                }
128                ioArgs.frame = frame;
129                styleFrame(frame);
130                ioArgs.outerFrame = outerFrame = outerFrame || frame;
131                if(!authTarget){
132                        outerFrame.style.display='none';
133                }
134                var state = 0;
135                function getData(){
136                        var data = frame.contentWindow.name;
137                        if(typeof data == 'string'){
138                                if(data != frameName){
139                                        state = 2; // we are done now
140                                        dfd.ioArgs.hash = frame.contentWindow.location.hash;
141                                        dfd.callback(data);
142                                }
143                        }
144                }
145                dojox.io.windowName[frameNum] = frame.onload = function(){
146                        try{
147                                if(!dojo.isMoz && frame.contentWindow.location =='about:blank'){
148                                        // opera and safari will do an onload for about:blank first, we can ignore this first onload
149                                        return;
150                                }
151                        }catch(e){
152                                // if we are in the target domain, frame.contentWindow.location will throw an ignorable error
153                        }
154                        if(!state){
155                                // we have loaded the target resource, now time to navigate back to our domain so we can read the frame name
156                                state=1;
157                                if(authTarget){
158                                        // call the callback so it can make it visible
159                                        if(onAuthLoad){
160                                                onAuthLoad();
161                                        }
162                                }else{
163                                        // we are doing a synchronous capture, go directly to our same domain URL and retrieve the resource
164                                        frame.contentWindow.location = sameDomainUrl;
165                                }
166                        }
167                        // back to our domain, we should be able to access the frame name now
168                        try{
169                                if(state<2){
170                                        getData();
171                                }
172                        }
173                        catch(e){
174                        }
175
176                };
177                frame.name = frameName;
178                if(method.match(/GET/i)){
179                        // if it is a GET we can just the iframe our src url
180                        dojo._ioAddQueryToUrl(ioArgs);
181                        frame.src = ioArgs.url;
182                        frameContainer.appendChild(frame);
183                        if(frame.contentWindow){
184                                frame.contentWindow.location.replace(ioArgs.url);
185                        }
186                }else if(method.match(/POST/i)){
187                        // if it is a POST we will build a form to post it
188                        frameContainer.appendChild(frame);
189                        var form = dojo.doc.createElement("form");
190                        dojo.body().appendChild(form);
191                        var query = dojo.queryToObject(ioArgs.query);
192                        for(var i in query){
193                                var values = query[i];
194                                values = values instanceof Array ? values : [values];
195                                for(var j = 0; j < values.length; j++){
196                                        // create hidden inputs for all the parameters
197                                        var input = doc.createElement("input");
198                                        input.type = 'hidden';
199                                        input.name = i;
200                                        input.value = values[j];
201                                        form.appendChild(input);
202                                }
203                        }
204                        form.method = 'POST';
205                        form.action = ioArgs.url;
206                        form.target = frameName;// connect the form to the iframe
207
208                        form.submit();
209                        form.parentNode.removeChild(form);
210                }else{
211                        throw new Error("Method " + method + " not supported with the windowName transport");
212                }
213                if(frame.contentWindow){
214                        frame.contentWindow.name = frameName; // IE likes it afterwards
215                }
216        },
217        _frameNum: 0
218
219};
220
221return dojox.io.windowName;
222
223});
Note: See TracBrowser for help on using the repository browser.