xref: /dokuwiki/lib/scripts/fileuploaderextended.js (revision 2d6cc64fdb73879f54aa25b2122f36631c654e3c)
1qq.extend(qq.FileUploader.prototype, {
2    _createUploadHandler: function(){
3        var self = this,
4            handlerClass;
5
6        if(qq.UploadHandlerXhr.isSupported()){
7            handlerClass = 'UploadHandlerXhr';
8            //handlerClass = 'UploadHandlerForm';
9        } else {
10            handlerClass = 'UploadHandlerForm';
11        }
12
13        var handler = new qq[handlerClass]({
14            debug: this._options.debug,
15            action: this._options.action,
16            maxConnections: this._options.maxConnections,
17            onProgress: function(id, fileName, loaded, total){
18                self._onProgress(id, fileName, loaded, total);
19                self._options.onProgress(id, fileName, loaded, total);
20            },
21            onComplete: function(id, fileName, result){
22                self._onComplete(id, fileName, result);
23                self._options.onComplete(id, fileName, result);
24            },
25            onCancel: function(id, fileName){
26                self._onCancel(id, fileName);
27                self._options.onCancel(id, fileName);
28            },
29            onUpload: function(){
30                self._onUpload();
31            }
32        });
33
34        return handler;
35    },
36
37    _onUpload: function(){
38        this._handler.uploadAll(this._options.params);
39    },
40
41    _uploadFile: function(fileContainer){
42        var id = this._handler.add(fileContainer);
43        var fileName = this._handler.getName(id);
44
45        if (this._options.onSubmit(id, fileName) !== false){
46            this._onSubmit(id, fileName);
47        }
48    },
49
50    _addToList: function(id, fileName){
51        var item = qq.toElement(this._options.fileTemplate);
52        item.qqFileId = id;
53
54        var fileElement = this._find(item, 'file');
55        qq.setText(fileElement, this._formatFileName(fileName));
56        this._find(item, 'size').style.display = 'none';
57
58        var nameElement = this._find(item, 'nameInput');
59        nameElement.value = this._formatFileName(fileName);
60        nameElement.id = id;
61
62        this._listElement.appendChild(item);
63    }
64
65});
66
67qq.FileUploaderExtended = function(o){
68    // call parent constructor
69    qq.FileUploaderBasic.apply(this, arguments);
70
71    qq.extend(this._options, {
72        element: null,
73        // if set, will be used instead of qq-upload-list in template
74        listElement: null,
75
76        template: '<div class="qq-uploader">' +
77                '<div class="qq-upload-drop-area"><span>Drop files here to upload</span></div>' +
78                '<div class="qq-upload-button">Upload a file</div>' +
79                '<ul class="qq-upload-list"></ul>' +
80                '<label class="check" for="dw__ow"><input id="dw__ow" type="checkbox" value="1" name="ow"><span>Overwrite existing file</span></label>' +
81                '<div><input class="button" type="submit" value="Upload" id="mediamanager__upload_button"></div>' +
82             '</div>',
83
84        // template for one item in file list
85        fileTemplate: '<li>' +
86                '<span class="qq-upload-file"></span>' +
87                '<label>Upload as (optional): <input class="qq-upload-name-input" type="text"></label>' +
88                '<span class="qq-upload-spinner-hidden"></span>' +
89                '<span class="qq-upload-size"></span>' +
90                '<a class="qq-upload-cancel" href="#">Cancel</a>' +
91                '<span class="qq-upload-failed-text">Failed</span>' +
92            '</li>',
93
94        classes: {
95            // used to get elements from templates
96            button: 'qq-upload-button',
97            drop: 'qq-upload-drop-area',
98            dropActive: 'qq-upload-drop-area-active',
99            list: 'qq-upload-list',
100            nameInput: 'qq-upload-name-input',
101            file: 'qq-upload-file',
102
103            spinner: 'qq-upload-spinner',
104            size: 'qq-upload-size',
105            cancel: 'qq-upload-cancel',
106
107            // added to list item when upload completes
108            // used in css to hide progress spinner
109            success: 'qq-upload-success',
110            fail: 'qq-upload-fail',
111            failedText : 'qq-upload-failed-text'
112        }
113    });
114
115    qq.extend(this._options, o);
116
117    this._element = this._options.element;
118    this._element.innerHTML = this._options.template;
119    this._listElement = this._options.listElement || this._find(this._element, 'list');
120
121    this._classes = this._options.classes;
122
123    this._button = this._createUploadButton(this._find(this._element, 'button'));
124
125    this._bindCancelEvent();
126    this._bindUploadEvent();
127    this._setupDragDrop();
128};
129
130qq.extend(qq.FileUploaderExtended.prototype, qq.FileUploader.prototype);
131
132qq.extend(qq.FileUploaderExtended.prototype, {
133    _bindUploadEvent: function(){
134        var self = this,
135            list = this._listElement;
136
137        qq.attach(document.getElementById('mediamanager__upload_button'), 'click', function(e){
138            e = e || window.event;
139            var target = e.target || e.srcElement;
140            qq.preventDefault(e);
141            self._handler._options.onUpload();
142
143        });
144    },
145
146    _onComplete: function(id, fileName, result){
147        this._filesInProgress--;
148
149        // mark completed
150        var item = this._getItemByFileId(id);
151        qq.remove(this._find(item, 'cancel'));
152        qq.remove(this._find(item, 'spinner'));
153
154        var nameInput = this._find(item, 'nameInput');
155        var fileElement = this._find(item, 'file');
156        qq.setText(fileElement, nameInput.value);
157        qq.remove(nameInput.parentNode);
158
159        if (result.success){
160            qq.addClass(item, this._classes.success);
161        } else {
162            qq.addClass(item, this._classes.fail);
163            var fail = this._find(item, 'failedText');
164            qq.setText(fail, result.error);
165        }
166    }
167
168});
169
170qq.extend(qq.UploadHandlerForm.prototype, {
171    uploadAll: function(params){
172        this._uploadAll(params);
173    },
174
175    getName: function(id){
176        var file = this._inputs[id];
177        var name = document.getElementById(id);
178        if (name != null) {
179            return name.value;
180        } else {
181            if (file != null) {
182                // get input value and remove path to normalize
183                return file.value.replace(/.*(\/|\\)/, "");
184            } else {
185                return null;
186            }
187        }
188    },
189
190    _uploadAll: function(params){
191         jQuery(".qq-upload-spinner-hidden").each(function (i) {
192            jQuery(this).addClass('qq-upload-spinner');
193        });
194        for (key in this._inputs) {
195            this.upload(key, params);
196        }
197
198    },
199
200    _upload: function(id, params){
201        var input = this._inputs[id];
202
203        if (!input){
204            throw new Error('file with passed id was not added, or already uploaded or cancelled');
205        }
206
207        var fileName = this.getName(id);
208
209        var iframe = this._createIframe(id);
210        var form = this._createForm(iframe, params);
211        form.appendChild(input);
212
213        var nameInput = qq.toElement('<input name="mediaid" value="' + fileName + '" type="text">');
214        form.appendChild(nameInput);
215
216        var owCheckbox = document.getElementById('dw__ow').cloneNode(true);
217        form.appendChild(owCheckbox);
218
219        var self = this;
220        this._attachLoadEvent(iframe, function(){
221            self.log('iframe loaded');
222
223            var response = self._getIframeContentJSON(iframe);
224
225            self._options.onComplete(id, fileName, response);
226            self._dequeue(id);
227
228            delete self._inputs[id];
229            // timeout added to fix busy state in FF3.6
230            setTimeout(function(){
231                qq.remove(iframe);
232            }, 1);
233        });
234
235        form.submit();
236        qq.remove(form);
237
238        return id;
239    }
240});
241
242qq.extend(qq.UploadHandlerXhr.prototype, {
243    uploadAll: function(params){
244        this._uploadAll(params);
245    },
246
247    getName: function(id){
248        var file = this._files[id];
249        var name = document.getElementById(id);
250        if (name != null) {
251            return name.value;
252        } else {
253            if (file != null) {
254                // fix missing name in Safari 4
255                return file.fileName != null ? file.fileName : file.name;
256            } else {
257                return null;
258            }
259        }
260    },
261
262    getSize: function(id){
263        var file = this._files[id];
264        if (file == null) return null;
265        return file.fileSize != null ? file.fileSize : file.size;
266    },
267
268    _upload: function(id, params){
269        var file = this._files[id],
270            name = this.getName(id),
271            size = this.getSize(id);
272        if (name == null || size == null) return;
273
274        this._loaded[id] = 0;
275
276        var xhr = this._xhrs[id] = new XMLHttpRequest();
277        var self = this;
278
279        xhr.upload.onprogress = function(e){
280            if (e.lengthComputable){
281                self._loaded[id] = e.loaded;
282                self._options.onProgress(id, name, e.loaded, e.total);
283            }
284        };
285
286        xhr.onreadystatechange = function(){
287            if (xhr.readyState == 4){
288                self._onComplete(id, xhr);
289            }
290        };
291
292        // build query string
293        params = params || {};
294        params['qqfile'] = name;
295        params['ow'] = document.getElementById('dw__ow').checked;
296        var queryString = qq.obj2url(params, this._options.action);
297
298        xhr.open("POST", queryString, true);
299        xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
300        xhr.setRequestHeader("X-File-Name", encodeURIComponent(name));
301        xhr.setRequestHeader("Content-Type", "application/octet-stream");
302        xhr.send(file);
303    },
304
305    _uploadAll: function(params){
306        jQuery(".qq-upload-spinner-hidden").each(function (i) {
307            jQuery(this).addClass('qq-upload-spinner');
308        });
309        for (key in this._files) {
310            this.upload(key, params);
311        }
312
313    }
314});
315