|
1 /* |
|
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved. |
|
3 Code licensed under the BSD License: |
|
4 http://developer.yahoo.net/yui/license.txt |
|
5 version: 3.0.0b1 |
|
6 build: 1163 |
|
7 */ |
|
8 YUI.add('io-upload-iframe', function(Y) { |
|
9 |
|
10 /** |
|
11 * Extends the IO base class to enable file uploads, with HTML forms, |
|
12 * using an iframe as the transport medium. |
|
13 * @module io |
|
14 * @submodule io-upload-iframe |
|
15 */ |
|
16 |
|
17 var w = Y.config.win; |
|
18 /** |
|
19 * @description Parses the POST data object and creates hidden form elements |
|
20 * for each key-value, and appends them to the HTML form object. |
|
21 * @method appendData |
|
22 * @private |
|
23 * @static |
|
24 * @param {object} d The key-value hash map. |
|
25 * @return {array} e Array of created fields. |
|
26 */ |
|
27 |
|
28 function _addData(f, d) { |
|
29 var e = [], |
|
30 p, i; |
|
31 |
|
32 for (p in d) { |
|
33 if (d.hasOwnProperty(d, p)) { |
|
34 e[i] = document.createElement('input'); |
|
35 e[i].type = 'hidden'; |
|
36 e[i].name = p; |
|
37 e[i].value = d[p]. |
|
38 f.appendChild(e[i]); |
|
39 } |
|
40 } |
|
41 |
|
42 return e; |
|
43 } |
|
44 |
|
45 function _removeData(f, e) { |
|
46 var i, l; |
|
47 if (e && e.length > 0) { |
|
48 for(i = 0, l = e.length; i < l; i++){ |
|
49 f.removeChild(e[i]); |
|
50 } |
|
51 } |
|
52 } |
|
53 |
|
54 function _create(o, c) { |
|
55 var i = Y.Node.create('<iframe id="ioupload' + o.id + '" name="ioupload' + o.id + '" />'), |
|
56 cfg = { |
|
57 position: 'absolute', |
|
58 top: '-1000px', |
|
59 left: '-1000px' |
|
60 }; |
|
61 |
|
62 i.setStyles(cfg); |
|
63 Y.get('body').appendChild(i); |
|
64 // Bind the onload handler to the iframe to detect the file upload response. |
|
65 Y.on("load", function() { _handle(o, c) }, '#ioupload' + o.id); |
|
66 } |
|
67 |
|
68 // Create the upload callback handler that fires when the iframe |
|
69 // receives the load event. Subsequently, the event handler is detached |
|
70 // and the iframe removed from the document. |
|
71 function _handle(o, c) { |
|
72 var p, |
|
73 b = Y.get('#ioupload' + o.id).get('contentWindow.document.body'); |
|
74 |
|
75 if (c.timeout) { |
|
76 _clearTimeout(o.id); |
|
77 } |
|
78 |
|
79 // When a response Content-Type of "text/plain" is used, Firefox and Safari |
|
80 // will wrap the response string with <pre></pre>. |
|
81 p = b.query('pre:first-child'); |
|
82 o.c.responseText = (p) ? p.get('innerHTML') : b.get('innerHTML'); |
|
83 Y.io.complete(o, c); |
|
84 // The transaction is complete, so call _destroy to remove |
|
85 // the event listener bound to the iframe transport, and then |
|
86 // destroy the iframe. |
|
87 setTimeout( function() { _destroy(o.id); }, 0); |
|
88 } |
|
89 |
|
90 /** |
|
91 * @description Starts timeout count if the configuration object |
|
92 * has a defined timeout property. |
|
93 * |
|
94 * @method _startTimeout |
|
95 * @private |
|
96 * @static |
|
97 * @param {object} o Transaction object generated by _create(). |
|
98 * @param {object} c Configuration object passed to YUI.io(). |
|
99 * @return void |
|
100 */ |
|
101 function _startTimeout(o, c) { |
|
102 Y.io._timeout[o.id] = w.setTimeout(function() { Y.io.abort(o, c); }, c.timeout); |
|
103 } |
|
104 |
|
105 /** |
|
106 * @description Clears the timeout interval started by _startTimeout(). |
|
107 * |
|
108 * @method _clearTimeout |
|
109 * @private |
|
110 * @static |
|
111 * @param {number} id - Transaction id. |
|
112 * @return void |
|
113 */ |
|
114 function _clearTimeout(id) { |
|
115 w.clearTimeout(Y.io._timeout[id]); |
|
116 delete Y.io._timeout[id]; |
|
117 } |
|
118 |
|
119 function _destroy(id) { |
|
120 Y.Event.purgeElement('#ioupload' + id, false); |
|
121 Y.get('body').removeChild(Y.get('#ioupload' + id)); |
|
122 Y.log('The iframe transport for transaction ' + id + 'has been destroyed.', 'info', 'io'); |
|
123 } |
|
124 |
|
125 Y.mix(Y.io, { |
|
126 |
|
127 /** |
|
128 * @description Uploads HTML form, inclusive of files/attachments, using the |
|
129 * iframe created in createFrame to facilitate the transaction. |
|
130 * @method _upload |
|
131 * @private |
|
132 * @static |
|
133 * @param {o} o The transaction object |
|
134 * @param {object} uri Qualified path to transaction resource. |
|
135 * @param {object} c Configuration object for the transaction. |
|
136 * @return {void} |
|
137 */ |
|
138 _upload: function(o, uri, c) { |
|
139 var f = (typeof c.form.id === 'string') ? document.getElementById(c.form.id) : c.form.id, |
|
140 e, fields, i, p, attr; |
|
141 |
|
142 _create(o, c); |
|
143 // Track original HTML form attribute values. |
|
144 attr = { |
|
145 action: f.getAttribute('action'), |
|
146 target: f.getAttribute('target') |
|
147 }; |
|
148 |
|
149 // Initialize the HTML form properties in case they are |
|
150 // not defined in the HTML form. |
|
151 f.setAttribute('action', uri); |
|
152 f.setAttribute('method', 'POST'); |
|
153 f.setAttribute('target', 'ioupload' + o.id ); |
|
154 f.setAttribute((Y.UA.ie && !document.documentMode) ? 'encoding' : 'enctype', 'multipart/form-data'); |
|
155 |
|
156 if (c.data) { |
|
157 fields = _addData(f, c.data); |
|
158 } |
|
159 |
|
160 // Start polling if a callback is present and the timeout |
|
161 // property has been defined. |
|
162 if (c.timeout) { |
|
163 _startTimeout(o, c); |
|
164 Y.log('Transaction timeout started for transaction ' + id + '.', 'info', 'io'); |
|
165 } |
|
166 |
|
167 // Start file upload. |
|
168 f.submit(); |
|
169 Y.io.start(o.id, c); |
|
170 |
|
171 if (c.data) { |
|
172 _removeData(f, fields); |
|
173 } |
|
174 |
|
175 // Restore HTML form attributes to their original |
|
176 // values prior to file upload. |
|
177 for (p in attr) { |
|
178 if (attr.hasOwnProperty(attr, p)) { |
|
179 if (attr[p]) { |
|
180 f.setAttribute(p, f[prop]); |
|
181 } |
|
182 else { |
|
183 f.removeAttribute(p); |
|
184 } |
|
185 } |
|
186 } |
|
187 } |
|
188 }); |
|
189 |
|
190 |
|
191 |
|
192 }, '3.0.0b1' ,{requires:['io-base']}); |