xref: /dokuwiki/lib/scripts/fileuploaderextended.js (revision 10799f9c522a9847ebf5f2f7c91d4af7f160e4b8)
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, fileName);
56        this._find(item, 'size').style.display = 'none';
57
58        var nameElement = this._find(item, 'nameInput');
59        fileName = fileName.toLowerCase();
60        fileName = fileName.replace(/([^a-z0-9_\.\-]+)/g, '_');
61        nameElement.value = fileName;
62        nameElement.id = 'mediamanager__upload_item'+id;
63
64        this._listElement.appendChild(item);
65    }
66
67});
68
69qq.FileUploaderExtended = function(o){
70    // call parent constructor
71    qq.FileUploaderBasic.apply(this, arguments);
72
73    qq.extend(this._options, {
74        element: null,
75        // if set, will be used instead of qq-upload-list in template
76        listElement: null,
77
78        template: '<div class="qq-uploader">' +
79                '<div class="qq-upload-drop-area"><span>' + LANG.media_drop + '</span></div>' +
80                '<div class="qq-upload-button">' + LANG.media_select + '</div>' +
81                '<div class="qq-upload-list"></div>' +
82                '<div><input class="button" type="submit" value="' + LANG.media_upload_btn + '" id="mediamanager__upload_button">' +
83                '<label class="check" for="dw__ow"><input id="dw__ow" type="checkbox" value="1" name="ow"><span>' + LANG.media_overwrt + '</span></label>' +
84                '</div>' +
85             '</div>',
86
87        // template for one item in file list
88        fileTemplate: '<div class="li">' +
89                '<span class="qq-upload-file qq-upload-file-hidden"></span>' +
90                '<input class="qq-upload-name-input edit" type="text">' +
91                '<span class="qq-upload-spinner-hidden"></span>' +
92                '<span class="qq-upload-size"></span>' +
93                '<a class="qq-upload-cancel" href="#">' + LANG.media_cancel + '</a>' +
94                '<span class="qq-upload-failed-text">Failed</span>' +
95            '</div>',
96
97        classes: {
98            // used to get elements from templates
99            button: 'qq-upload-button',
100            drop: 'qq-upload-drop-area',
101            dropActive: 'qq-upload-drop-area-active',
102            list: 'qq-upload-list',
103            nameInput: 'qq-upload-name-input',
104            file: 'qq-upload-file',
105
106            spinner: 'qq-upload-spinner',
107            size: 'qq-upload-size',
108            cancel: 'qq-upload-cancel',
109
110            // added to list item when upload completes
111            // used in css to hide progress spinner
112            success: 'qq-upload-success',
113            fail: 'qq-upload-fail',
114            failedText : 'qq-upload-failed-text'
115        }
116    });
117
118    qq.extend(this._options, o);
119
120    this._element = this._options.element;
121    this._element.innerHTML = this._options.template;
122    this._listElement = this._options.listElement || this._find(this._element, 'list');
123
124    this._classes = this._options.classes;
125
126    this._button = this._createUploadButton(this._find(this._element, 'button'));
127
128    this._bindCancelEvent();
129    this._bindUploadEvent();
130    this._setupDragDrop();
131};
132
133qq.extend(qq.FileUploaderExtended.prototype, qq.FileUploader.prototype);
134
135qq.extend(qq.FileUploaderExtended.prototype, {
136    _bindUploadEvent: function(){
137        var self = this,
138            list = this._listElement;
139
140        qq.attach(document.getElementById('mediamanager__upload_button'), 'click', function(e){
141            e = e || window.event;
142            var target = e.target || e.srcElement;
143            qq.preventDefault(e);
144            self._handler._options.onUpload();
145
146            jQuery(".qq-upload-name-input").each(function (i) {
147                jQuery(this).attr('disabled', 'disabled');
148            });
149        });
150    },
151
152    _onComplete: function(id, fileName, result){
153        this._filesInProgress--;
154
155        // mark completed
156        var item = this._getItemByFileId(id);
157        qq.remove(this._find(item, 'cancel'));
158        qq.remove(this._find(item, 'spinner'));
159
160        var nameInput = this._find(item, 'nameInput');
161        var fileElement = this._find(item, 'file');
162        qq.setText(fileElement, nameInput.value);
163        qq.removeClass(fileElement, 'qq-upload-file-hidden');
164        qq.remove(nameInput);
165        jQuery('.qq-upload-button, #mediamanager__upload_button').remove();
166        jQuery('#dw__ow').parent().hide();
167        jQuery('.qq-upload-drop-area').remove();
168
169        if (result.success){
170            qq.addClass(item, this._classes.success);
171            $link = '<a href="' + result.link + '" name="h_:' + result.id + '" class="select">' + nameInput.value + '</a>';
172            jQuery(fileElement).html($link);
173
174        } else {
175            qq.addClass(item, this._classes.fail);
176            var fail = this._find(item, 'failedText');
177            if (result.error) qq.setText(fail, result.error);
178        }
179
180        if (document.getElementById('media__content') && !document.getElementById('mediamanager__done_form')) {
181            var button = '<form method="post" action="' + document.location +'" id="mediamanager__done_form"><div>';
182            button += '<input class="button" type="submit" value="' + LANG.media_done_btn + '"></div></form>'
183            jQuery('#mediamanager__uploader').append(button);
184        }
185    }
186
187});
188
189qq.extend(qq.UploadHandlerForm.prototype, {
190    uploadAll: function(params){
191        this._uploadAll(params);
192    },
193
194    getName: function(id){
195        var file = this._inputs[id];
196        var name = document.getElementById('mediamanager__upload_item'+id);
197        if (name != null) {
198            return name.value;
199        } else {
200            if (file != null) {
201                // get input value and remove path to normalize
202                return file.value.replace(/.*(\/|\\)/, "");
203            } else {
204                return null;
205            }
206        }
207    },
208
209    _uploadAll: function(params){
210         jQuery(".qq-upload-spinner-hidden").each(function (i) {
211            jQuery(this).addClass('qq-upload-spinner');
212        });
213        for (key in this._inputs) {
214            this.upload(key, params);
215        }
216
217    },
218
219    _upload: function(id, params){
220        var input = this._inputs[id];
221
222        if (!input){
223            throw new Error('file with passed id was not added, or already uploaded or cancelled');
224        }
225
226        var fileName = this.getName(id);
227
228        var iframe = this._createIframe(id);
229        var form = this._createForm(iframe, params);
230        form.appendChild(input);
231
232        var nameInput = qq.toElement('<input name="mediaid" value="' + fileName + '" type="text">');
233        form.appendChild(nameInput);
234
235        var owCheckbox = document.getElementById('dw__ow').cloneNode(true);
236        form.appendChild(owCheckbox);
237
238        var self = this;
239        this._attachLoadEvent(iframe, function(){
240            self.log('iframe loaded');
241
242            var response = self._getIframeContentJSON(iframe);
243
244            self._options.onComplete(id, fileName, response);
245            self._dequeue(id);
246
247            delete self._inputs[id];
248            // timeout added to fix busy state in FF3.6
249            setTimeout(function(){
250                qq.remove(iframe);
251            }, 1);
252        });
253
254        form.submit();
255        qq.remove(form);
256
257        return id;
258    }
259});
260
261qq.extend(qq.UploadHandlerXhr.prototype, {
262    uploadAll: function(params){
263        this._uploadAll(params);
264    },
265
266    getName: function(id){
267        var file = this._files[id];
268        var name = document.getElementById('mediamanager__upload_item'+id);
269        if (name != null) {
270            return name.value;
271        } else {
272            if (file != null) {
273                // fix missing name in Safari 4
274                return file.fileName != null ? file.fileName : file.name;
275            } else {
276                return null;
277            }
278        }
279    },
280
281    getSize: function(id){
282        var file = this._files[id];
283        if (file == null) return null;
284        return file.fileSize != null ? file.fileSize : file.size;
285    },
286
287    _upload: function(id, params){
288        var file = this._files[id],
289            name = this.getName(id),
290            size = this.getSize(id);
291        if (name == null || size == null) return;
292
293        this._loaded[id] = 0;
294
295        var xhr = this._xhrs[id] = new XMLHttpRequest();
296        var self = this;
297
298        xhr.upload.onprogress = function(e){
299            if (e.lengthComputable){
300                self._loaded[id] = e.loaded;
301                self._options.onProgress(id, name, e.loaded, e.total);
302            }
303        };
304
305        xhr.onreadystatechange = function(){
306            if (xhr.readyState == 4){
307                self._onComplete(id, xhr);
308            }
309        };
310
311        // build query string
312        params = params || {};
313        params['qqfile'] = name;
314        params['ow'] = document.getElementById('dw__ow').checked;
315        var queryString = qq.obj2url(params, this._options.action);
316
317        xhr.open("POST", queryString, true);
318        xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
319        xhr.setRequestHeader("X-File-Name", encodeURIComponent(name));
320        xhr.setRequestHeader("Content-Type", "application/octet-stream");
321        xhr.send(file);
322    },
323
324    _uploadAll: function(params){
325        jQuery(".qq-upload-spinner-hidden").each(function (i) {
326            jQuery(this).addClass('qq-upload-spinner');
327        });
328        for (key in this._files) {
329            this.upload(key, params);
330        }
331
332    }
333});
334