|
|
|
1 |
/* |
2 |
* Copyright 2011 Univention GmbH |
3 |
* |
4 |
* http://www.univention.de/ |
5 |
* |
6 |
* All rights reserved. |
7 |
* |
8 |
* The source code of this program is made available |
9 |
* under the terms of the GNU Affero General Public License version 3 |
10 |
* (GNU AGPL V3) as published by the Free Software Foundation. |
11 |
* |
12 |
* Binary versions of this program provided by Univention to you as |
13 |
* well as other copyrighted, protected or trademarked materials like |
14 |
* Logos, graphics, fonts, specific documentations and configurations, |
15 |
* cryptographic keys etc. are subject to a license agreement between |
16 |
* you and Univention and not subject to the GNU AGPL V3. |
17 |
* |
18 |
* In the case you use this program under the terms of the GNU AGPL V3, |
19 |
* the program is provided in the hope that it will be useful, |
20 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 |
* GNU Affero General Public License for more details. |
23 |
* |
24 |
* You should have received a copy of the GNU Affero General Public |
25 |
* License with the Debian GNU/Linux or Univention distribution in file |
26 |
* /usr/share/common-licenses/AGPL-3; if not, see |
27 |
* <http://www.gnu.org/licenses/>. |
28 |
*/ |
29 |
/*global dojo dijit dojox umc console */ |
30 |
|
31 |
dojo.provide("umc.widgets.MultiUploader"); |
32 |
|
33 |
dojo.require("umc.widgets.ContainerWidget"); |
34 |
dojo.require("umc.i18n"); |
35 |
dojo.require("umc.widgets.Button"); |
36 |
dojo.require("umc.widgets.Uploader"); |
37 |
dojo.require("umc.widgets.MultiSelect"); |
38 |
dojo.require("umc.widgets.ProgressInfo"); |
39 |
dojo.require("umc.tools"); |
40 |
dojo.require("umc.dialog"); |
41 |
|
42 |
dojo.declare("umc.widgets.MultiUploader", [ umc.widgets.ContainerWidget, umc.widgets._FormWidgetMixin, umc.i18n.Mixin ], { |
43 |
'class': 'umcMultiUploader', |
44 |
|
45 |
i18nClass: 'umc.app', |
46 |
|
47 |
// command: String |
48 |
// The UMCP command to which the data shall be uploaded. |
49 |
// If not given, the data is sent to umcp/upload which will return the |
50 |
// file content encoded as base64. |
51 |
command: '', |
52 |
|
53 |
// buttonLabel: String |
54 |
// The label that is displayed on the upload button. |
55 |
buttonLabel: 'Upload', |
56 |
|
57 |
// value: String[] |
58 |
// 'value' contains an array of the uploaded file names. |
59 |
value: [], |
60 |
|
61 |
// maxSize: Number |
62 |
// A size limit for the uploaded file. |
63 |
maxSize: 524288, |
64 |
|
65 |
// make sure that no sizeClass is being set |
66 |
sizeClass: null, |
67 |
|
68 |
// this form element should always be valid |
69 |
valid: true, |
70 |
|
71 |
/*===== |
72 |
// state: String |
73 |
// Specifies in which state the widget is: |
74 |
// 'Complete' -> default, |
75 |
// 'Incomplete' -> uploads are not completed yet |
76 |
state: 'Complete', |
77 |
=====*/ |
78 |
|
79 |
// internal reference to the MultiSelect widget containing all filenames |
80 |
_files: null, |
81 |
|
82 |
// internal reference to the current Uploader widget |
83 |
_uploader: null, |
84 |
|
85 |
// internal reference to the progress bar |
86 |
_progressBar: null, |
87 |
|
88 |
// button for removing entries |
89 |
_removeButton: null, |
90 |
|
91 |
// container for the upload and remove buttons |
92 |
_container: null, |
93 |
|
94 |
// internal reference to the currently uploading files |
95 |
_uploadingFiles: [], |
96 |
|
97 |
constructor: function() { |
98 |
this.buttonLabel = this._('Upload'); |
99 |
this._uploadingFiles = []; |
100 |
}, |
101 |
|
102 |
buildRendering: function() { |
103 |
this.inherited(arguments); |
104 |
|
105 |
// MultiSelect widget for displaying the file list |
106 |
this._files = new umc.widgets.MultiSelect({ |
107 |
style: 'width: 50em' |
108 |
}); |
109 |
this.addChild(this._files); |
110 |
|
111 |
this._createProgressBar(); |
112 |
|
113 |
// prepare remove button and container for upload/remove buttons |
114 |
this._container = new umc.widgets.ContainerWidget({}); |
115 |
this._container.addChild(new umc.widgets.Button({ |
116 |
label: this._('Remove'), |
117 |
iconClass: 'umcIconDelete', |
118 |
onClick: dojo.hitch(this, '_removeFiles'), |
119 |
style: 'float: right;' |
120 |
})); |
121 |
this.addChild(this._container); |
122 |
|
123 |
// add the uploader button |
124 |
this._addUploader(); |
125 |
}, |
126 |
|
127 |
destroy: function() { |
128 |
this.inherited(arguments); |
129 |
|
130 |
if (this._progressBar) { |
131 |
// destroy the old progress bar |
132 |
this._progressBar.destroyRecursive(); |
133 |
} |
134 |
}, |
135 |
|
136 |
_getStateAttr: function() { |
137 |
return this._uploadingFiles.length ? 'Incomplete' : 'Complete'; |
138 |
}, |
139 |
|
140 |
_setValueAttr: function(newVal) { |
141 |
this._files.set('staticValues', newVal); |
142 |
}, |
143 |
|
144 |
_getValueAttr: function() { |
145 |
return this._files.get('staticValues'); |
146 |
}, |
147 |
|
148 |
_setButtonLabelAttr: function(newVal) { |
149 |
this.buttonLabel = newVal; |
150 |
this._uploader.set('buttonLabel', newVal); |
151 |
}, |
152 |
|
153 |
_setDisabledAttr: function(newVal) { |
154 |
this._files.set('disabled', newVal); |
155 |
this._uploader.set('disabled', newVal); |
156 |
}, |
157 |
|
158 |
_getDisabledAttr: function() { |
159 |
return this._files.get('disabled'); |
160 |
}, |
161 |
|
162 |
_removeFiles: function() { |
163 |
var selectedFiles = this._files.get('value'); |
164 |
if (!selectedFiles.length) { |
165 |
return; |
166 |
} |
167 |
|
168 |
// make sure we may remove the selected items |
169 |
dojo.when(this.canRemove(selectedFiles), dojo.hitch(this, function(doUpload) { |
170 |
if (!doUpload) { |
171 |
// removal canceled |
172 |
return; |
173 |
} |
174 |
|
175 |
// remove items |
176 |
var files = this.get('value'); |
177 |
files = dojo.filter(files, function(ifile) { |
178 |
return dojo.indexOf(selectedFiles, ifile) < 0; |
179 |
}); |
180 |
this.set('value', files); |
181 |
})); |
182 |
}, |
183 |
|
184 |
_createProgressBar: function() { |
185 |
if (this._progressBar) { |
186 |
// destroy the old progress bar |
187 |
this._progressBar.destroyRecursive(); |
188 |
} |
189 |
|
190 |
// create progress bar for displaying the upload information |
191 |
this._progressBar = new umc.widgets.ProgressInfo({ |
192 |
maximum: 1 |
193 |
}); |
194 |
this._progressBar._progressBar.set('style', 'min-width: 30em;'); |
195 |
this._progressBar.updateTitle(this._('No upload in progress')); |
196 |
}, |
197 |
|
198 |
_updateProgress: function() { |
199 |
if (!this._progressBar) { |
200 |
return; |
201 |
} |
202 |
|
203 |
var currentVal = 0; |
204 |
var nDone = 0; |
205 |
dojo.forEach(this._uploadingFiles, function(ifile) { |
206 |
nDone += ifile.done || 0; |
207 |
currentVal += ifile.done ? 1.0 : ifile.decimal || 0; |
208 |
}); |
209 |
currentVal = Math.min(currentVal / this._uploadingFiles.length, 0.99); |
210 |
if (!this._uploadingFiles.length || nDone == this._uploadingFiles.length) { |
211 |
// all uploads are finished |
212 |
this._progressBar.update(1, '', this._('Uploads finished')); |
213 |
} |
214 |
else { |
215 |
this._progressBar.update(currentVal, '', this._('Uploading... %d of %d files remaining.', this._uploadingFiles.length - nDone, this._uploadingFiles.length)); |
216 |
} |
217 |
}, |
218 |
|
219 |
_addUploader: function() { |
220 |
// create a new Uploader widget |
221 |
this._uploader = new umc.widgets.Uploader({ |
222 |
showClearButton: false, |
223 |
buttonLabel: this.buttonLabel, |
224 |
command: this.command, |
225 |
maxSize: this.maxSize, |
226 |
canUpload: this.canUpload, |
227 |
style: 'float: left;' |
228 |
}); |
229 |
this._container.addChild(this._uploader); |
230 |
|
231 |
// register events |
232 |
var uploader = this._uploader; |
233 |
var startedSignal = this.connect(uploader, 'onUploadStarted', function(file) { |
234 |
//console.log('### onUploadStarted:', dojo.toJson(file)); |
235 |
this.disconnect(startedSignal); |
236 |
|
237 |
// add current file to the list of uploading items |
238 |
if (!this._uploadingFiles.length) { |
239 |
// first file being uploaded -> show the standby animation |
240 |
//this._createProgressBar(); |
241 |
this._files.standby(true, this._progressBar); |
242 |
} |
243 |
this._uploadingFiles.push(file); |
244 |
this._updateProgress(); |
245 |
|
246 |
var progressSignal = this.connect(uploader, 'onProgress', function(info) { |
247 |
// update progress information |
248 |
//console.log('### onProgress:', dojo.toJson(info)); |
249 |
dojo.mixin(file, info); |
250 |
this._updateProgress(); |
251 |
}); |
252 |
var uploadSignal = this.connect(uploader, 'onUploaded', function() { |
253 |
// disconnect events |
254 |
//console.log('### onUploaded'); |
255 |
this.disconnect(progressSignal); |
256 |
this.disconnect(uploadSignal); |
257 |
|
258 |
// update progress information |
259 |
file.done = true; |
260 |
this._updateProgress(); |
261 |
|
262 |
// remove Uploader widget from container |
263 |
this.removeChild(uploader); |
264 |
uploader.destroyRecursive(); |
265 |
|
266 |
// when all files are uploaded, update the internal list of files |
267 |
var allDone = true; |
268 |
dojo.forEach(this._uploadingFiles, function(ifile) { |
269 |
allDone = allDone && ifile.done; |
270 |
}); |
271 |
if (allDone) { |
272 |
// add files to internal list of files |
273 |
this._files.standby(false); |
274 |
var vals = this.get('value'); |
275 |
dojo.forEach(this._uploadingFiles, function(ifile) { |
276 |
//console.log('### adding:', ifile.name); |
277 |
vals.unshift(ifile.name); |
278 |
}); |
279 |
this.set('value', vals); |
280 |
|
281 |
// clear the list of uploading files |
282 |
this._uploadingFiles = []; |
283 |
} |
284 |
}); |
285 |
|
286 |
// hide uploader widget and add a new one |
287 |
dojo.style(uploader.domNode, { |
288 |
width: '0', |
289 |
overflow: 'hidden' |
290 |
}); |
291 |
this._addUploader(); |
292 |
}); |
293 |
}, |
294 |
|
295 |
canUpload: function(fileInfo) { |
296 |
// summary: |
297 |
// Before uploading a file, this function is called to make sure |
298 |
// that the given filename is valid. Return boolean or dojo.Deferred. |
299 |
// fileInfo: Object |
300 |
// Info object for the requested file, contains properties 'name', |
301 |
// 'size', 'type'. |
302 |
return true; |
303 |
}, |
304 |
|
305 |
canRemove: function(filenames) { |
306 |
// summary: |
307 |
// Before removing a files from the current list, this function |
308 |
// is called to make sure that the given file may be removed. |
309 |
// Return boolean or dojo.Deferred. |
310 |
// filenames: String[] |
311 |
// List of filenames. |
312 |
return true; |
313 |
}, |
314 |
|
315 |
onUploaded: function(data) { |
316 |
// event stub |
317 |
}, |
318 |
|
319 |
onChange: function(data) { |
320 |
// event stub |
321 |
} |
322 |
}); |
323 |
|
324 |
|
325 |
|