NOBUG: Fixed file access permissions
[moodle.git] / lib / yuilib / 3.13.0 / io-upload-iframe / io-upload-iframe.js
blob51aa4bb4d223be385e3bf6ac93daf758b7753004
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));
57 Y.mix(Y.IO.prototype, {
58    /**
59     * Parses the POST data object and creates hidden form elements
60     * for each key-value, and appends them to the HTML form object.
61     * @method _addData
62     * @private
63     * @static
64     * @param {Object} f HTML form object.
65     * @param {String} s The key-value POST data.
66     * @return {Array} o Array of created fields.
67     */
68     _addData: function(f, s) {
69         // Serialize an object into a key-value string using
70         // querystring-stringify-simple.
71         if (Y.Lang.isObject(s)) {
72             s = Y.QueryString.stringify(s);
73         }
75         var o = [],
76             m = s.split('='),
77             i, l;
79         for (i = 0, l = m.length - 1; i < l; i++) {
80             o[i] = d.createElement('input');
81             o[i].type = 'hidden';
82             o[i].name = _d(m[i].substring(m[i].lastIndexOf('&') + 1));
83             o[i].value = (i + 1 === l) ? _d(m[i + 1]) : _d(m[i + 1].substring(0, (m[i + 1].lastIndexOf('&'))));
84             f.appendChild(o[i]);
85         }
87         return o;
88     },
90    /**
91     * Removes the custom fields created to pass additional POST
92     * data, along with the HTML form fields.
93     * @method _removeData
94     * @private
95     * @static
96     * @param {Object} f HTML form object.
97     * @param {Object} o HTML form fields created from configuration.data.
98     */
99     _removeData: function(f, o) {
100         var i, l;
102         for (i = 0, l = o.length; i < l; i++) {
103             f.removeChild(o[i]);
104         }
105     },
107    /**
108     * Sets the appropriate attributes and values to the HTML
109     * form, in preparation of a file upload transaction.
110     * @method _setAttrs
111     * @private
112     * @static
113     * @param {Object} f HTML form object.
114     * @param {Object} id The Transaction ID.
115     * @param {Object} uri Qualified path to transaction resource.
116     */
117     _setAttrs: function(f, id, uri) {
118         // Track original HTML form attribute values.
119         this._originalFormAttrs = {
120             action: f.getAttribute('action'),
121             target: f.getAttribute('target')
122         };
124         f.setAttribute('action', uri);
125         f.setAttribute('method', 'POST');
126         f.setAttribute('target', 'io_iframe' + id );
127         f.setAttribute(Y.UA.ie && !_std ? 'encoding' : 'enctype', 'multipart/form-data');
128     },
130    /**
131     * Reset the HTML form attributes to their original values.
132     * @method _resetAttrs
133     * @private
134     * @static
135     * @param {Object} f HTML form object.
136     * @param {Object} a Object of original attributes.
137     */
138     _resetAttrs: function(f, a) {
139         Y.Object.each(a, function(v, p) {
140             if (v) {
141                 f.setAttribute(p, v);
142             }
143             else {
144                 f.removeAttribute(p);
145             }
146         });
147     },
149    /**
150     * Starts timeout count if the configuration object
151     * has a defined timeout property.
152     *
153     * @method _startUploadTimeout
154     * @private
155     * @static
156     * @param {Object} o Transaction object generated by _create().
157     * @param {Object} c Configuration object passed to YUI.io().
158     */
159     _startUploadTimeout: function(o, c) {
160         var io = this;
162         io._timeout[o.id] = w.setTimeout(
163             function() {
164                 o.status = 0;
165                 o.statusText = 'timeout';
166                 io.complete(o, c);
167                 io.end(o, c);
168             }, c.timeout);
169     },
171    /**
172     * Clears the timeout interval started by _startUploadTimeout().
173     * @method _clearUploadTimeout
174     * @private
175     * @static
176     * @param {Number} id - Transaction ID.
177     */
178     _clearUploadTimeout: function(id) {
179         var io = this;
181         w.clearTimeout(io._timeout[id]);
182         delete io._timeout[id];
183     },
185    /**
186     * Bound to the iframe's Load event and processes
187     * the response data.
188     * @method _uploadComplete
189     * @private
190     * @static
191     * @param {Object} o The transaction object
192     * @param {Object} c Configuration object for the transaction.
193     */
194     _uploadComplete: function(o, c) {
195         var io = this,
196             d = Y.one('#io_iframe' + o.id).get('contentWindow.document'),
197             b = d.one('body'),
198             p;
200         if (c.timeout) {
201             io._clearUploadTimeout(o.id);
202         }
204                 try {
205                         if (b) {
206                                 // When a response Content-Type of "text/plain" is used, Firefox and Safari
207                                 // will wrap the response string with <pre></pre>.
208                                 p = b.one('pre:first-child');
209                                 o.c.responseText = p ? p.get('text') : b.get('text');
210                         }
211                         else {
212                                 o.c.responseXML = d._node;
213                         }
214                 }
215                 catch (e) {
216                         o.e = "upload failure";
217                 }
219         io.complete(o, c);
220         io.end(o, c);
221         // The transaction is complete, so call _dFrame to remove
222         // the event listener bound to the iframe transport, and then
223         // destroy the iframe.
224         w.setTimeout( function() { _dFrame(o.id); }, 0);
225     },
227    /**
228     * Uploads HTML form data, inclusive of files/attachments,
229     * using the iframe created in _create to facilitate the transaction.
230     * @method _upload
231     * @private
232     * @static
233     * @param {Object} o The transaction object
234     * @param {Object} uri Qualified path to transaction resource.
235     * @param {Object} c Configuration object for the transaction.
236     */
237     _upload: function(o, uri, c) {
238         var io = this,
239             f = (typeof c.form.id === 'string') ? d.getElementById(c.form.id) : c.form.id,
240             fields;
242         // Initialize the HTML form properties in case they are
243         // not defined in the HTML form.
244         io._setAttrs(f, o.id, uri);
245         if (c.data) {
246             fields = io._addData(f, c.data);
247         }
249         // Start polling if a callback is present and the timeout
250         // property has been defined.
251         if (c.timeout) {
252             io._startUploadTimeout(o, c);
253         }
255         // Start file upload.
256         f.submit();
257         io.start(o, c);
258         if (c.data) {
259             io._removeData(f, fields);
260         }
262         return {
263             id: o.id,
264             abort: function() {
265                 o.status = 0;
266                 o.statusText = 'abort';
267                 if (Y.one('#io_iframe' + o.id)) {
268                     _dFrame(o.id);
269                     io.complete(o, c);
270                     io.end(o, c);
271                 }
272                 else {
273                     return false;
274                 }
275             },
276             isInProgress: function() {
277                 return Y.one('#io_iframe' + o.id) ? true : false;
278             },
279             io: io
280         };
281     },
283     upload: function(o, uri, c) {
284         _cFrame(o, c, this);
285         return this._upload(o, uri, c);
286     },
288     end: function(transaction, config) {
289         var form, io;
291         if (config) {
292             form = config.form;
294             if (form && form.upload) {
295                 io = this;
297                 // Restore HTML form attributes to their original values.
298                 form = (typeof form.id === 'string') ? d.getElementById(form.id) : form.id;
300                 io._resetAttrs(form, this._originalFormAttrs);
301             }
302         }
304         return _end.call(this, transaction, config);
305     }
306 }, true);
309 }, '3.13.0', {"requires": ["io-base", "node-base"]});