1 // © 2013 Benoît Pin MINES ParisTech
5 // nombre maximun d'image chargées en local
7 var isThumbnail
= /.*\/getThumbnail$/;
9 DDFileUploader = function(dropbox
, uploadUrl
) {
10 this.dropbox
= dropbox
;
11 this.existingSlides
= this.indexExistingSlides();
12 this.uploadUrl
= uploadUrl
;
14 this.progressBarMaxSize
= 200; // pixels
15 this.thumbnailSize
= 180;
16 this.previewQueue
= [];
17 this._previewQueueRunning
= false;
18 this.previewsLoaded
= 0;
19 this.uploadQueue
= [];
20 this._uploadQueueRunning
= false;
22 addListener(dropbox
, 'dragenter', function(evt
){self
.dragenter(evt
);});
23 addListener(dropbox
, 'dragover', function(evt
){self
.dragover(evt
);});
24 addListener(dropbox
, 'drop', function(evt
){self
.drop(evt
);});
27 DDFileUploader
.prototype.indexExistingSlides = function() {
28 var images
= this.dropbox
.getElementsByTagName('img');
31 for (i
=0 ; i
< images
.length
; i
++) {
32 if (isThumbnail
.test(images
[i
].src
)) {
33 index
[images
[i
].src
] = images
[i
];
40 DDFileUploader
.prototype.dragenter = function(evt
) {
42 disablePropagation(evt
);
45 DDFileUploader
.prototype.dragover = function(evt
) {
47 disablePropagation(evt
);
48 evt
= getEventObject(evt
);
49 var dt
= evt
.dataTransfer
;
50 dt
.dropEffect
= 'copy';
53 DDFileUploader
.prototype.drop = function(evt
) {
55 disablePropagation(evt
);
57 var dt
= evt
.dataTransfer
;
58 dt
.dropEffect
= 'copy';
59 this.handleFiles(dt
.files
);
62 // Methods about upload
63 DDFileUploader
.prototype.handleFiles = function(files
) {
65 for (i
= 0; i
< files
.length
; i
++) {
67 slide
= this.createSlide(file
);
68 this.previewQueuePush(slide
);
69 this.uploadQueuePush(slide
);
73 DDFileUploader
.prototype.upload = function(slide
) {
74 var reader
= new FileReader();
75 var req
= new XMLHttpRequest();
76 var file
= slide
.file
;
77 this.uploadedSlide
= slide
;
78 this.previewImg
= slide
.img
;
79 this.progressBar
= slide
.progressBar
;
82 addListener(req
.upload
, 'progress', function(evt
){self
.progressHandler(evt
);});
83 addListener(req
, 'readystatechange',
85 if (req
.readyState
=== 4) {
86 self
.uploadCompleteHandler(req
);
90 req
.open("PUT", this.uploadUrl
);
91 req
.setRequestHeader("Content-Type", file
.type
);
92 req
.setRequestHeader("X-File-Name", file
.name
);
93 addListener(reader
, 'load',
96 req
.sendAsBinary(evt
.target
.result
);
100 reader
.readAsBinaryString(file
);
103 DDFileUploader
.prototype.uploadCompleteHandler = function(req
) {
104 var slide
= this.uploadedSlide
;
105 this.uploadedSlide
.removeChild(slide
.label
);
106 this.uploadedSlide
.removeChild(slide
.progressBar
);
107 var fragment
= getCopyOfNode(req
.responseXML
.documentElement
.firstChild
);
108 var img
= fragment
.getElementsByTagName('img')[0];
109 if (req
.status
=== 200) {
111 var existing
= this.existingSlides
[img
.src
];
113 existing
.src
= existing
.src
+ '?' + Math
.random().toString();
116 slide
.img
.parentNode
.removeChild(slide
.img
);
117 slide
.img
= undefined;
118 slide
.parentNode
.removeChild(slide
);
120 else if(req
.status
=== 201) {
122 img
.onload = function(evt
) {
123 // accelerate GC before replacing
125 slide
.img
.parentNode
.removeChild(slide
.img
);
126 slide
.img
= undefined;
127 slide
.parentNode
.replaceChild(fragment
, slide
);
130 this.previewsLoaded
--;
131 this.previewQueueLoadNext();
132 this.uploadQueueLoadNext();
135 DDFileUploader
.prototype.progressHandler = function(evt
) {
136 if (evt
.lengthComputable
) {
137 var progress
= evt
.loaded
/ evt
.total
;
138 this.updateProgressBar(progress
);
139 var currentOpacity
= this.previewImg
.style
.opacity
;
140 this.previewImg
.style
.opacity
= Math
.max(currentOpacity
, progress
);
144 // Method about queues
146 DDFileUploader
.prototype.previewQueuePush = function(slide
) {
147 this.previewQueue
.push(slide
);
148 if (!this._previewQueueRunning
) {
149 this.startPreviewQueue();
153 DDFileUploader
.prototype.startPreviewQueue = function() {
154 this._previewQueueRunning
= true;
155 this.previewQueueLoadNext();
158 DDFileUploader
.prototype.previewQueueLoadNext = function() {
159 if (this.previewQueue
.length
&& this.previewsLoaded
< MAX_PREVIEW
) {
160 var slide
= this.previewQueue
.shift();
161 this.previewUploadedImage(slide
);
162 this.previewsLoaded
++;
165 this._previewQueueRunning
= false;
169 DDFileUploader
.prototype.uploadQueuePush = function(slide
) {
170 this.uploadQueue
.push(slide
);
171 if (!this._uploadQueueRunning
) {
172 this.startUploadQueue();
176 DDFileUploader
.prototype.startUploadQueue = function() {
177 this._uploadQueueRunning
= true;
178 this.uploadQueueLoadNext();
182 DDFileUploader
.prototype.uploadQueueLoadNext = function() {
183 var slide
= this.uploadQueue
.shift();
188 this._uploadQueueRunning
= false;
194 DDFileUploader
.prototype.createSlide = function(file
) {
195 var slide
= document
.createElement('span');
198 var a
= document
.createElement('a');
200 a
.className
= 'slide';
202 var img
= document
.createElement('img');
203 img
.className
= 'hidden';
204 var size
= this.thumbnailSize
;
206 img
.onload = function(evt
) {
207 if (img
.width
> img
.height
) { // landscape
208 img
.height
= Math
.round(size
* img
.height
/ img
.width
);
212 img
.width
= Math
.round(size
* img
.width
/ img
.height
);
215 img
.style
.marginLeft
= Math
.floor((self
.slideSize
- img
.width
) / 2) + 'px';
216 img
.style
.marginTop
= Math
.floor((self
.slideSize
- img
.height
) / 2) + 'px';
217 img
.style
.opacity
= 0.2;
218 img
.className
= undefined;
223 var label
= document
.createElement('span');
225 label
.className
= 'label';
226 label
.innerHTML
= file
.name
;
228 var progressBar
= document
.createElement('span');
229 progressBar
.className
= 'upload-progress';
230 slide
.progressBar
= progressBar
;
232 slide
.appendChild(a
);
233 slide
.appendChild(progressBar
);
234 slide
.appendChild(label
);
235 this.dropbox
.appendChild(slide
);
240 DDFileUploader
.prototype.updateProgressBar = function(progress
) {
241 // 0 <= progress <= 1
242 var size
= this.progressBarMaxSize
* progress
;
243 size
= Math
.round(size
);
244 this.progressBar
.style
.width
= size
+ 'px';
247 DDFileUploader
.prototype.previewUploadedImage = function(slide
) {
248 var reader
= new FileReader();
249 var size
= this.thumbnailSize
;
252 reader
.onload = function(evt
) {
253 slide
.img
.src
= evt
.target
.result
;
254 setTimeout(function(){self
.previewQueueLoadNext();}, 500);
256 reader
.readAsDataURL(slide
.file
);