04fde673a95c1ab3baa34d4ad342e0bcbaf61cff
[Plinn.git] / skins / fileupload.js
1 // © 2013 Benoît Pin MINES ParisTech
2 var DDFileUploader;
3
4 (function(){
5
6 DDFileUploader = function(dropbox, uploadUrl) {
7 this.dropbox = dropbox;
8 this.uploadUrl = uploadUrl;
9 this.slideSize = 222;
10 this.progressBarMaxSize = 200; // pixels
11 this.thumbnailSize = 180;
12 this.previewQueue = [];
13 this._previewQueueRunning = false;
14 this.uploadQueue = [];
15 this._uploadQueueRunning = false;
16 var self = this;
17 addListener(dropbox, 'dragenter', function(evt){self.dragenter(evt);});
18 addListener(dropbox, 'dragover', function(evt){self.dragover(evt);});
19 addListener(dropbox, 'drop', function(evt){self.drop(evt);});
20 };
21
22 // Drag and drop
23 DDFileUploader.prototype.dragenter = function(evt) {
24 disableDefault(evt);
25 disablePropagation(evt);
26 };
27
28 DDFileUploader.prototype.dragover = function(evt) {
29 disableDefault(evt);
30 disablePropagation(evt);
31 evt = getEventObject(evt);
32 var dt = evt.dataTransfer;
33 dt.dropEffect = 'copy';
34 };
35
36 DDFileUploader.prototype.drop = function(evt) {
37 disableDefault(evt);
38 disablePropagation(evt);
39 getEventObject(evt);
40 var dt = evt.dataTransfer;
41 dt.dropEffect = 'copy';
42 this.handleFiles(dt.files);
43 };
44
45 // Methods about upload
46 DDFileUploader.prototype.handleFiles = function(files) {
47 var file, i, slide;
48 for (i = 0; i < files.length; i++) {
49 file = files[i];
50 slide = this.createSlide(file);
51 // this.previewQueuePush(slide);
52 this.uploadQueuePush(slide);
53 }
54 };
55
56 DDFileUploader.prototype.upload = function(slide) {
57 var reader = new FileReader();
58 var req = new XMLHttpRequest();
59 var file = slide.file;
60 this.uploadedSlide = slide;
61 this.previewImg = slide.img;
62 this.progressBar = slide.progressBar;
63 var self = this;
64
65 addListener(req.upload, 'progress', function(evt){self.progressHandler(evt);});
66 // addListener(req.upload, 'load', function(evt){self.uploadCompleteHandler(evt, req);});
67 addListener(req, 'readystatechange',
68 function(evt) {
69 if (req.readyState == 4) {
70 self.uploadCompleteHandler(req);
71 }
72 });
73
74 req.open("PUT", this.uploadUrl);
75 req.setRequestHeader("Content-Type", file.type);
76 req.setRequestHeader("X-File-Name", file.name);
77 addListener(reader, 'load',
78 function(evt){
79 try {
80 req.sendAsBinary(evt.target.result);
81 }
82 catch(e){}
83 });
84 reader.readAsBinaryString(file);
85 };
86
87 DDFileUploader.prototype.uploadCompleteHandler = function(req) {
88 var slide = this.uploadedSlide;
89 this.uploadedSlide.removeChild(slide.label);
90 this.uploadedSlide.removeChild(slide.progressBar);
91 slide.innerHTML = req.responseXML.documentElement.firstChild.data;
92 this.uploadQueueLoadNext();
93 };
94
95 DDFileUploader.prototype.progressHandler = function(evt) {
96 if (evt.lengthComputable) {
97 var progress = evt.loaded / evt.total;
98 this.updateProgressBar(progress);
99 var currentOpacity = this.previewImg.style.opacity;
100 this.previewImg.style.opacity = Math.max(currentOpacity, progress);
101 }
102 };
103
104 // Method about queues
105
106 DDFileUploader.prototype.previewQueuePush = function(slide) {
107 this.previewQueue.push(slide);
108 if (!this._previewQueueRunning) {
109 this.startPreviewQueue();
110 }
111 };
112
113 DDFileUploader.prototype.startPreviewQueue = function() {
114 this._previewQueueRunning = true;
115 this.previewQueueLoadNext();
116 };
117
118 DDFileUploader.prototype.previewQueueLoadNext = function() {
119 var slide = this.previewQueue.shift();
120 if (slide) {
121 this.previewUploadedImage(slide);
122 }
123 else {
124 this._previewQueueRunning = false;
125 }
126 };
127
128 DDFileUploader.prototype.uploadQueuePush = function(slide) {
129 this.uploadQueue.push(slide);
130 if (!this._uploadQueueRunning) {
131 this.startUploadQueue();
132 }
133 };
134
135 DDFileUploader.prototype.startUploadQueue = function() {
136 this._uploadQueueRunning = true;
137 this.uploadQueueLoadNext();
138 };
139
140
141 DDFileUploader.prototype.uploadQueueLoadNext = function() {
142 var slide = this.uploadQueue.shift();
143 if (slide) {
144 this.upload(slide);
145 }
146 else {
147 this._uploadQueueRunning = false;
148 }
149 };
150
151
152 // User interface
153 DDFileUploader.prototype.createSlide = function(file) {
154 var slide = document.createElement('span');
155 slide.file = file;
156
157 var a = document.createElement('a');
158 a.href = '#';
159 a.className = 'slide';
160
161 var img = document.createElement('img');
162 img.className = 'hidden';
163 var size = this.thumbnailSize;
164 var self = this;
165 img.onload = function(evt) {
166 if (img.width > img.height) { // landscape
167 img.height = Math.round(size * img.height / img.width);
168 img.width = size;
169 }
170 else {
171 img.width = Math.round(size * img.width / img.height);
172 img.height = size;
173 }
174 img.style.marginLeft = Math.round((self.slideSize - img.width) / 2) + 'px';
175 img.style.marginTop = Math.round((self.slideSize - img.height) / 2) + 'px';
176 img.style.opacity = 0.2;
177 img.className = undefined;
178 };
179 a.appendChild(img);
180 slide.img = img;
181
182 var label = document.createElement('span');
183 slide.label = label;
184 label.className = 'label';
185 label.innerHTML = file.name;
186
187 var progressBar = document.createElement('span');
188 progressBar.className = 'upload-progress';
189 slide.progressBar = progressBar;
190
191 slide.appendChild(a);
192 slide.appendChild(progressBar);
193 slide.appendChild(label);
194 this.dropbox.appendChild(slide);
195
196 return slide;
197 };
198
199 DDFileUploader.prototype.updateProgressBar = function(progress) {
200 // 0 <= progress <= 1
201 var size = this.progressBarMaxSize * progress;
202 size = Math.round(size);
203 this.progressBar.style.width = size + 'px';
204 };
205
206 DDFileUploader.prototype.previewUploadedImage = function(slide) {
207 var reader = new FileReader();
208 var size = this.thumbnailSize;
209 var self = this;
210
211 reader.onload = function(evt) {
212 slide.img.src = evt.target.result;
213 setTimeout(function(){self.previewQueueLoadNext();}, 500);
214 };
215 reader.readAsDataURL(slide.file);
216 };
217
218 }());