NOBUG: Fixed file access permissions
[moodle.git] / lib / yuilib / 3.13.0 / io-upload-iframe / io-upload-iframe-debug.js
blob23c45265f202ff2d33ae2100749b264e5e60d02d
1 /*
2 YUI 3.13.0 (build 508226d)
3 Copyright 2013 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
6 */
8 YUI.add('io-upload-iframe', function (Y, NAME) {
10 /**
11 Extends the IO  to enable file uploads, with HTML forms
12 using an iframe as the transport medium.
13 @module io
14 @submodule io-upload-iframe
15 @for IO
16 **/
18 var w = Y.config.win,
19     d = Y.config.doc,
20     _std = (d.documentMode && d.documentMode >= 8),
21     _d = decodeURIComponent,
22     _end = Y.IO.prototype.end;
24 /**
25  * Creates the iframe transported used in file upload
26  * transactions, and binds the response event handler.
27  *
28  * @method _cFrame
29  * @private
30  * @param {Object} o Transaction object generated by _create().
31  * @param {Object} c Configuration object passed to YUI.io().
32  * @param {Object} io
33  */
34 function _cFrame(o, c, io) {
35     var i = Y.Node.create('<iframe src="#" id="io_iframe' + o.id + '" name="io_iframe' + o.id + '" />');
36         i._node.style.position = 'absolute';
37         i._node.style.top = '-1000px';
38         i._node.style.left = '-1000px';
39         Y.one('body').appendChild(i);
40     // Bind the onload handler to the iframe to detect the file upload response.
41     Y.on("load", function() { io._uploadComplete(o, c); }, '#io_iframe' + o.id);
44 /**
45  * Removes the iframe transport used in the file upload
46  * transaction.
47  *
48  * @method _dFrame
49  * @private
50  * @param {Number} id The transaction ID used in the iframe's creation.
51  */
52 function _dFrame(id) {
53         Y.Event.purgeElement('#io_iframe' + id, false);
54         Y.one('body').removeChild(Y.one('#io_iframe' + id));
55         Y.log('The iframe transport for transaction ' + id + ' has been destroyed.', 'info', 'io');
58 Y.mix(Y.IO.prototype, {
59    /**
60     * Parses the POST data object and creates hidden form elements
61     * for each key-value, and appends them to the HTML form object.
62     * @method _addData
63     * @private
64     * @static
65     * @param {Object} f HTML form object.
66     * @param {String} s The key-value POST data.
67     * @return {Array} o Array of created fields.
68     */
69     _addData: function(f, s) {
70         // Serialize an object into a key-value string using
71         // querystring-stringify-simple.
72         if (Y.Lang.isObject(s)) {
73             s = Y.QueryString.stringify(s);
74         }
76         var o = [],
77             m = s.split('='),
78             i, l;
80         for (i = 0, l = m.length - 1; i < l; i++) {
81             o[i] = d.createElement('input');
82             o[i].type = 'hidden';
83             o[i].name = _d(m[i].substring(m[i].lastIndexOf('&') + 1));
84             o[i].value = (i + 1 === l) ? _d(m[i + 1]) : _d(m[i + 1].substring(0, (m[i + 1].lastIndexOf('&'))));
85             f.appendChild(o[i]);
86             Y.log('key: ' +  o[i].name + ' and value: ' + o[i].value + ' added as form data.', 'info', 'io');
87         }
89         return o;
90     },
92    /**
93     * Removes the custom fields created to pass additional POST
94     * data, along with the HTML form fields.
95     * @method _removeData
96     * @private
97     * @static
98     * @param {Object} f HTML form object.
99     * @param {Object} o HTML form fields created from configuration.data.
100     */
101     _removeData: function(f, o) {
102         var i, l;
104         for (i = 0, l = o.length; i < l; i++) {
105             f.removeChild(o[i]);
106         }
107     },
109    /**
110     * Sets the appropriate attributes and values to the HTML
111     * form, in preparation of a file upload transaction.
112     * @method _setAttrs
113     * @private
114     * @static
115     * @param {Object} f HTML form object.
116     * @param {Object} id The Transaction ID.
117     * @param {Object} uri Qualified path to transaction resource.
118     */
119     _setAttrs: function(f, id, uri) {
120         // Track original HTML form attribute values.
121         this._originalFormAttrs = {
122             action: f.getAttribute('action'),
123             target: f.getAttribute('target')
124         };
126         f.setAttribute('action', uri);
127         f.setAttribute('method', 'POST');
128         f.setAttribute('target', 'io_iframe' + id );
129         f.setAttribute(Y.UA.ie && !_std ? 'encoding' : 'enctype', 'multipart/form-data');
130     },
132    /**
133     * Reset the HTML form attributes to their original values.
134     * @method _resetAttrs
135     * @private
136     * @static
137     * @param {Object} f HTML form object.
138     * @param {Object} a Object of original attributes.
139     */
140     _resetAttrs: function(f, a) {
141         Y.Object.each(a, function(v, p) {
142             if (v) {
143                 f.setAttribute(p, v);
144             }
145             else {
146                 f.removeAttribute(p);
147             }
148         });
149     },
151    /**
152     * Starts timeout count if the configuration object
153     * has a defined timeout property.
154     *
155     * @method _startUploadTimeout
156     * @private
157     * @static
158     * @param {Object} o Transaction object generated by _create().
159     * @param {Object} c Configuration object passed to YUI.io().
160     */
161     _startUploadTimeout: function(o, c) {
162         var io = this;
164         io._timeout[o.id] = w.setTimeout(
165             function() {
166                 o.status = 0;
167                 o.statusText = 'timeout';
168                 io.complete(o, c);
169                 io.end(o, c);
170                 Y.log('Transaction ' + o.id + ' timeout.', 'info', 'io');
171             }, c.timeout);
172     },
174    /**
175     * Clears the timeout interval started by _startUploadTimeout().
176     * @method _clearUploadTimeout
177     * @private
178     * @static
179     * @param {Number} id - Transaction ID.
180     */
181     _clearUploadTimeout: function(id) {
182         var io = this;
184         w.clearTimeout(io._timeout[id]);
185         delete io._timeout[id];
186     },
188    /**
189     * Bound to the iframe's Load event and processes
190     * the response data.
191     * @method _uploadComplete
192     * @private
193     * @static
194     * @param {Object} o The transaction object
195     * @param {Object} c Configuration object for the transaction.
196     */
197     _uploadComplete: function(o, c) {
198         var io = this,
199             d = Y.one('#io_iframe' + o.id).get('contentWindow.document'),
200             b = d.one('body'),
201             p;
203         if (c.timeout) {
204             io._clearUploadTimeout(o.id);
205         }
207                 try {
208                         if (b) {
209                                 // When a response Content-Type of "text/plain" is used, Firefox and Safari
210                                 // will wrap the response string with <pre></pre>.
211                                 p = b.one('pre:first-child');
212                                 o.c.responseText = p ? p.get('text') : b.get('text');
213                                 Y.log('The responseText value for transaction ' + o.id + ' is: ' + o.c.responseText + '.', 'info', 'io');
214                         }
215                         else {
216                                 o.c.responseXML = d._node;
217                                 Y.log('The response for transaction ' + o.id + ' is an XML document.', 'info', 'io');
218                         }
219                 }
220                 catch (e) {
221                         o.e = "upload failure";
222                 }
224         io.complete(o, c);
225         io.end(o, c);
226         // The transaction is complete, so call _dFrame to remove
227         // the event listener bound to the iframe transport, and then
228         // destroy the iframe.
229         w.setTimeout( function() { _dFrame(o.id); }, 0);
230     },
232    /**
233     * Uploads HTML form data, inclusive of files/attachments,
234     * using the iframe created in _create to facilitate the transaction.
235     * @method _upload
236     * @private
237     * @static
238     * @param {Object} o The transaction object
239     * @param {Object} uri Qualified path to transaction resource.
240     * @param {Object} c Configuration object for the transaction.
241     */
242     _upload: function(o, uri, c) {
243         var io = this,
244             f = (typeof c.form.id === 'string') ? d.getElementById(c.form.id) : c.form.id,
245             fields;
247         // Initialize the HTML form properties in case they are
248         // not defined in the HTML form.
249         io._setAttrs(f, o.id, uri);
250         if (c.data) {
251             fields = io._addData(f, c.data);
252         }
254         // Start polling if a callback is present and the timeout
255         // property has been defined.
256         if (c.timeout) {
257             io._startUploadTimeout(o, c);
258             Y.log('Transaction timeout started for transaction ' + o.id + '.', 'info', 'io');
259         }
261         // Start file upload.
262         f.submit();
263         io.start(o, c);
264         if (c.data) {
265             io._removeData(f, fields);
266         }
268         return {
269             id: o.id,
270             abort: function() {
271                 o.status = 0;
272                 o.statusText = 'abort';
273                 if (Y.one('#io_iframe' + o.id)) {
274                     _dFrame(o.id);
275                     io.complete(o, c);
276                     io.end(o, c);
277                     Y.log('Transaction ' + o.id + ' aborted.', 'info', 'io');
278                 }
279                 else {
280                     Y.log('Attempted to abort transaction ' + o.id + ' but transaction has completed.', 'warn', 'io');
281                     return false;
282                 }
283             },
284             isInProgress: function() {
285                 return Y.one('#io_iframe' + o.id) ? true : false;
286             },
287             io: io
288         };
289     },
291     upload: function(o, uri, c) {
292         _cFrame(o, c, this);
293         return this._upload(o, uri, c);
294     },
296     end: function(transaction, config) {
297         var form, io;
299         if (config) {
300             form = config.form;
302             if (form && form.upload) {
303                 io = this;
305                 // Restore HTML form attributes to their original values.
306                 form = (typeof form.id === 'string') ? d.getElementById(form.id) : form.id;
308                 io._resetAttrs(form, this._originalFormAttrs);
309             }
310         }
312         return _end.call(this, transaction, config);
313     }
314 }, true);
317 }, '3.13.0', {"requires": ["io-base", "node-base"]});