root/trunk/uploadr/MacUploadr.app/Contents/Resources/chrome/content/uploadr/photos.js

Revision 493, 24.8 kB (checked in by jdecq, 11 months ago)

add timestamps in log message

Line 
1 /*
2  * Flickr Uploadr
3  *
4  * Copyright (c) 2007-2008 Yahoo! Inc.  All rights reserved.  This library is
5  * free software; you can redistribute it and/or modify it under the terms of
6  * the GNU General Public License (GPL), version 2 only.  This library is
7  * distributed WITHOUT ANY WARRANTY, whether express or implied. See the GNU
8  * GPL for more details (http://www.gnu.org/licenses/gpl.html)
9  */
10
11 var photos = {
12
13         // Storage
14         list: [],
15         count: 0,
16         errors: 0,
17         selected: [],
18         last: null,
19         sort: true,
20         batch_size: 0,
21         thumb_cancel: false,
22
23         // Upload tracking
24         uploading: [],
25         uploaded: [],
26         add_to_set: [],
27         failed: [],
28         sets: {},
29         ok: 0,
30         fail: 0,
31         sets_fail: false,
32         sets_out: 0,
33         kb: {
34                 sent: 0,
35                 total: 0
36         },
37
38         // Queue batches of photos
39         ready: [],
40         ready_size: [],
41
42         // Let the user select some files, thumbnail them and track them
43         //   Patch for saving our place in the directory structure from
44         //   Zoolcar9 at http://pastebin.mozilla.org/279359
45         add_dialog: function() {
46                 buttons.upload.disable();
47
48                 // Find a good default directory for the file picker
49                 var path = nsPreferences.getLocalizedUnicharPref(
50                         'flickr.add_directory', '');
51                 if ('' == path) {
52                         path = Cc['@mozilla.org/file/directory_service;1']
53                                 .getService(Ci.nsIProperties).get('ProfD', Ci.nsIFile).path;
54                         if (path.match(/^\//)) {
55                                 path += '/../../../../../Pictures';
56                         } else {
57                                 path += '\\..\\..\\..\\..\\..\\My Documents\\My Pictures';
58                         }
59                 }
60                 var def = Cc['@mozilla.org/file/local;1']
61                         .createInstance(Ci.nsILocalFile);
62                 def.initWithPath(path);
63
64                 // Open the file picker
65                 var fp = Cc['@mozilla.org/filepicker;1']
66                         .createInstance(Ci.nsIFilePicker);
67                 fp.init(window, locale.getString('dialog.add'),
68                         Ci.nsIFilePicker.modeOpenMultiple);
69                 var can_has_video = 'object' == typeof users.is_pro || users.is_pro;
70                 if (can_has_video) {
71                         fp.appendFilter('Photos and Videos', '*.jpeg; *.JPEG; *.jpg; ' +
72                                 '*.JPG; *.gif; *.GIF; *.png; *.PNG; *.tiff; *.TIFF; *.tif; ' +
73                                 '*.TIF; *.bmp; *.BMP; *.mp4; *.MP4; *.mpeg; *.MPEG; *.mpg; ' +
74                                 '*.MPG; *.avi; *.AVI; *.wmv; *.WMV; *.mov; *.MOV; *.dv; ' +
75                                 '*.DV; *.3gp; *.3GP; *.3g2; *.m4v; *.M4V');
76                 }
77                 fp.appendFilter('Photos', '*.jpeg; *.JPEG; *.jpg; *.JPG; *.gif; ' +
78                         '*.GIF; *.png; *.PNG; *.tiff; *.TIFF; *.tif; *.TIF; *.bmp; *.BMP');
79                 if (can_has_video) {
80                         fp.appendFilter('Videos', '*.mp4; *.MP4; *.mpeg; *.MPEG; ' +
81                                 '*.mpg; *.MPG; *.avi; *.AVI; *.wmv; *.WMV; *.mov; *.MOV; ' +
82                                 '*.dv; *.DV; *.3gp; *.3GP; *3g2; *.m4v; *.M4V');
83                 }
84                 fp.displayDirectory = def;
85                 var res = fp.show();
86                 if (Ci.nsIFilePicker.returnOK == res) {
87                         var files = fp.files;
88                         var paths = [];
89                         while (files.hasMoreElements()) {
90                                 var arg = files.getNext().QueryInterface(Ci.nsILocalFile).path;
91                                 paths.push(arg);
92                         }
93                         photos.add(paths);
94
95                         // Save our place in the filesystem
96                         if (arg.match(/^\//)) {
97                                 path = arg.replace(/\/[^\/]+$/, '').toString();
98                         } else {
99                                 path = arg.replace(/\\[^\\]+$/, '').toString();
100                         }
101                         nsPreferences.setUnicharPref('flickr.add_directory', path);
102
103                 } else if (photos.count) {
104                         buttons.upload.enable();
105                 }
106         },
107
108         // Add a list of photos
109         add: function(paths, silent) {
110                 if (null == silent) { silent = false; }
111                 buttons.upload.disable();
112
113                 // Tally up photos and videos and remove large videos
114                 var p_count = 0;
115                 var v_count = 0;
116                 var big_videos = [];
117                 var new_paths = [];
118                 var bad = [];
119                 for each (var p in paths) {
120                         var path = 'object' == typeof p ? p.path : p;
121
122                         // Photos are always allowed
123                         if (photos.is_photo(path)) {
124                                 ++p_count;
125                                 new_paths.push(p);
126                         }
127
128                         // Videos are allowed for now as long as they aren't too big
129                         else if (photos.is_video(path)) {
130                                 ++v_count;
131                                 if (file.size(path) > (null == users.videosize
132                                         ? conf.videosize : users.videosize)) {
133                                         var filename = path.match(/([^\/\\]*)$/);
134                                         big_videos.push(null == filename ? path : filename[1]);
135                                 } else {
136                                         new_paths.push(p);
137                                 }
138                         }
139
140                         // Warn about files that are being dropped
141                         else if (path.length) {
142                                 var filename = path.match(/([^\/\\]*)$/);
143                                 bad.push(null == filename ? path : filename[1]);
144                         }
145
146                 }
147                 paths = new_paths;
148
149                 // Yell about anything added that wasn't a photo or video
150                 if (bad.length) {
151                         var pl = (1 == bad.length ? 's' : 'p') +
152                                 (0 == paths.length ? 'z' : 'p');
153                         var text;
154                         if (1 == bad.length) {
155                                 text = locale.getFormattedString('bad.' + pl + '.text',
156                                         [bad[0]]);
157                         } else {
158                                 text = [locale.getFormattedString('bad.' + pl + '.text',
159                                         [bad.length]), bad.join(', ')];
160                         }
161                         alert(text, locale.getString('bad.' + pl + '.title'),
162                                 locale.getString('bad.' + pl + '.ok'));
163                 }
164
165                 // If we're allowed to bother the user
166                 if (!silent) {
167
168                         // Plurality strings are decided as follows
169                         //   Each dialog has identical strings but they're coded
170                         //   as follows for varied pluralities:
171                         //     XXX.sz.XXX: singular video, zero photos
172                         //     XXX.sz.XXX: plural videos, zero photos
173                         //     XXX.pp.XXX: singular video, plural photos
174                         //     XXX.pp.XXX: plural videos, plural photos
175
176                         // Warn if a video is larger than ? MB and remove offending
177                         // videos from the list
178                         if (big_videos.length) {
179
180                                 // Plurality, see above
181                                 var pl = (1 == v_count ? 's' : 'p') +
182                                         (0 == p_count ? 'z' : 'p');
183
184                                 window.openDialog(
185                                         'chrome://uploadr/content/video_big.xul',
186                                         'dialog_video_big', 'chrome,modal',
187                                         locale.getString('video.add.big.' + pl + '.title'),
188                                         locale.getFormattedString(
189                                                 'video.add.big.' + pl + '.explain',
190                                                 [(null == users.videosize
191                                                 ? conf.videosize : users.videosize) >> 10]
192                                         ),
193                                         1 == v_count ? '' : big_videos.join(', '),
194                                         locale.getString('video.add.big.' + pl + '.ok'));
195                                 v_count -= big_videos.length;
196                         }
197
198                         // If there are videos then there may be questions to ask
199                         if (v_count) {
200                                 var result = {};
201
202                                 // Redo plurality, see above
203                                 var pl = (1 == v_count ? 's' : 'p') +
204                                         (0 == p_count ? 'z' : 'p');
205
206                                 // Offline users can have video but we should warn them that
207                                 // we'll remove them without warning if they turn out to be
208                                 // a free user at upload time
209                                 if ('object' == typeof users.is_pro) {
210                                         window.openDialog(
211                                                 'chrome://uploadr/content/video_offline.xul',
212                                                 'dialog_video_offline', 'chrome,modal',
213                                                 locale.getString('video.add.offline.' + pl + '.title'),
214                                                 locale.getString('video.add.offline.' + pl + '.explain'),
215                                                 locale.getString('video.add.offline.' + pl + '.ok'),
216                                                 locale.getString('video.add.offline.' + pl + '.cancel'),
217                                                 locale.getString('video.add.offline.' + pl + '.extra1'),
218                                                 result);
219                                 }
220
221                                 // Pro users can have videos but we still need to bother
222                                 // those that have their defaults set to restricted
223                                 else if (3 == settings.safety_level) {
224                                         window.openDialog(
225                                                 'chrome://uploadr/content/video_restricted.xul',
226                                                 'dialog_video_restricted', 'chrome,modal',
227                                                 locale.getString('video.add.restricted.' + pl + '.title'),
228                                                 locale.getString('video.add.restricted.' + pl + '.explain'),
229                                                 locale.getString('video.add.restricted.' + pl + '.action'),
230                                                 locale.getString('video.add.restricted.' + pl + '.note'),
231                                                 locale.getString('video.add.restricted.' + pl + '.guidelines'),
232                                                 locale.getString('video.add.restricted.' + pl + '.ok'),
233                                                 locale.getString('video.add.restricted.' + pl + '.cancel'),
234                                                 locale.getString('video.add.restricted.' + pl + '.extra1'),
235                                                 result);
236                                 }
237
238                                 // Quit immediately if we're forgetting the whole group
239                                 if ('extra1' == result.result) {
240                                         return;
241                                 }
242                                 // Remove videos from the path list if we're keeping photos
243                                 else if ('cancel' == result.result) {
244                                         var new_paths = [];
245                                         while (paths.length) {
246                                                 var p = paths.shift();
247                                                 var path = 'object' == typeof p ? p.path : p;
248                                                 if (!photos.is_video(path)) {
249                                                         new_paths.push(p);
250                                                 }
251                                         }
252                                         paths = new_paths;
253                                 }
254
255                                 // If we're adding videos, remember the safety level to set
256                                 else if ('ok' == result.result && result.safety_level) {
257                                         var ii = paths.length;
258                                         for (var i = 0; i < ii; ++i) {
259                                                 var p = 'object' == typeof paths[i] ?
260                                                         paths[i].path : paths[i];
261                                                 if (photos.is_video(p)) {
262                                                         paths[i] = 'object' == typeof paths[i] ?
263                                                                 paths[i] : {'path': p};
264                                                         paths[i].safety_level = result.safety_level;
265                                                 }
266                                         }
267                                 }
268
269                         }
270
271                 }
272 //videos to be rejected for non pro is beyond silence param
273         if (v_count && users.is_pro === false) {
274             if(confirm(locale.getString('dialog.no.video.text'),
275                 locale.getFormattedString('dialog.no.video.title', [users.username]),
276                     locale.getString('dialog.no.video.ok'),
277                     locale.getString('dialog.no.video.cancel'))) {
278                     launch_browser('http://' + SITE_HOST + '/upgrade/');
279                 }
280                 // anyway at that point too complicate to handle video
281                  var new_paths = [];
282                     while (paths.length) {
283                             var p = paths.shift();
284                             var path = 'object' == typeof p ? p.path : p;
285                             if (!photos.is_video(path)) {
286                                     new_paths.push(p);
287                             }
288                     }
289                     paths = new_paths;
290             }
291
292                 // Now add whatever's left
293                 var ii = paths.length;
294                 block_normalize();
295                 var ext_list = [];
296                 var currentPathsLists = photos.list.map(function(x) {return (x ? x.path : "");});
297                
298                 for (var i = 0; i < ii; ++i) {
299                         var p = 'object' == typeof paths[i] ? paths[i].path : paths[i];
300
301                         // Resolve the path and add the photo
302                         if (/^file:\/\//.test(p)) {
303                                 p = Cc['@mozilla.org/network/protocol;1?name=file']
304                                         .getService(Ci.nsIFileProtocolHandler)
305                                         .getFileFromURLSpec(p).path;
306                         }
307                         if(currentPathsLists.indexOf(p) === -1) {
308                             ext_list.push(photos._add(p));
309
310                             // Photos can be passed as an object which already has metadata
311                             if ('object' == typeof paths[i]) {
312                                     for (var k in paths[i]) {
313                                             if ('id' == k) { continue; }
314                                             photos.list[photos.list.length - 1][k] = paths[i][k];
315                                     }
316                             }
317             }
318                 }
319
320                 // Do extension stuff after we've added all of the photos but
321                 // before the list we've saved potentially becomes invalid
322                 extension.after_add.exec(ext_list);
323
324                 // Update the UI
325                 photos.normalize();
326                 if (photos.count + photos.errors) {
327                     document.getElementById('t_clear').className = 'button';
328                         if (photos.sort) {
329                                 threads.worker.dispatch(new Sort(),
330                                         threads.worker.DISPATCH_NORMAL);
331                                 document.getElementById('photos_sort_default')
332                                         .style.display = 'block';
333                                 document.getElementById('photos_sort_revert')
334                                         .style.display = 'none';
335                         } else {
336                                 threads.worker.dispatch(new EnableUpload(),
337                                         threads.worker.DISPATCH_NORMAL);
338                                 document.getElementById('photos_sort_default')
339                                         .style.display = 'none';
340                                 document.getElementById('photos_sort_revert')
341                                         .style.display = 'block';
342                         }
343                         document.getElementById('photos_init')
344                                 .style.display = 'none';
345                         document.getElementById('photos_new')
346                                 .style.display = 'none';
347                         document.getElementById('no_meta_prompt')
348                                 .style.visibility = 'visible';
349                         mouse.show_photos();
350                 } else {
351                         unblock_normalize();
352                         document.getElementById('t_clear').className = 'disabled_button';
353                         document.getElementById('photos_init').style.display = '-moz-box';
354                         document.getElementById('photos_new').style.display = 'none';
355                 }
356
357         },
358         _add: function(path) {
359                 block_remove();
360                 block_sort();
361
362                 // Add the original image to the list and set our status
363                 var id = photos.list.length;
364                 var p = new Photo(id, path);
365                 photos.list.push(p);
366                 ++photos.count;
367                 block_normalize();
368
369                 // Create a spot for the image, leaving a spinning placeholder
370                 //   Add images to the start of the list because this is our best
371                 //   guess for ordering newest to oldest
372                 var img = document.createElementNS(NS_HTML, 'img');
373                 img.className = 'loading';
374                 img.setAttribute('width', 16);
375                 img.setAttribute('height', 8);
376                 img.src = 'chrome://uploadr/skin/balls-16x8-trans.gif';
377                 var li = document.createElementNS(NS_HTML, 'li');
378                 li.id = 'photo' + id;
379                 li.appendChild(img);
380                 var list = document.getElementById('photos_list');
381                 list.insertBefore(li, list.firstChild);
382
383                 // Create and show the thumbnail
384         photos.thumb_cancel = false;
385                 threads.worker.dispatch(new Thumb(id, conf.thumb_size, path),
386                         threads.worker.DISPATCH_NORMAL);
387
388                 return p;
389         },
390
391         // Remove selected photos
392         remove: function() {
393
394                 // Respect the remove block
395                 if (0 < _block_remove) { return; }
396
397                 // Nothing to do if somehow there are no selected photos
398                 var ii = photos.selected.length;
399                 if (0 == ii) { return; }
400
401                 // Tell extensions which photos we're removing
402                 extension.before_remove.exec(photos.selected);
403
404                 // Remove selected photos
405                 for (var i = 0; i < ii; ++i) {
406                         var id = photos.selected[i];
407                         var li = document.getElementById('photo' + id);
408                         if(li) {
409                             li.parentNode.removeChild(li);
410                         }
411
412                         // Free the size of this file
413                         photos.batch_size -= photos.list[id].size;
414                         if (users.nsid && !users.is_pro && users.bandwidth &&
415                                 0 < users.bandwidth.remaining - photos.batch_size) {
416                                 status.clear();
417                         }
418
419                         photos.list[id] = null;
420                         --photos.count;
421                 }
422                 ui.bandwidth_updated();
423                 photos.normalize();
424                 meta.disable();
425
426                 // Clear the selection
427                 photos.selected = [];
428                 mouse.click({target: {}});
429
430                 photos._remove();
431         },
432
433         // Allow upload only if there are photos
434         _remove: function() {
435                 if (photos.count) {
436                         buttons.upload.enable();
437                 } else {
438                         photos.sort = true;
439                         buttons.upload.disable();
440                         document.getElementById('photos_sort_default')
441                                 .style.display = 'none';
442                         document.getElementById('photos_sort_revert')
443                                 .style.display = 'none';
444                         if (!photos.errors) {
445                                 document.getElementById('t_clear').className = 'disabled_button';
446                                 document.getElementById('photos_init')
447                                         .style.display = '-moz-box';
448                         }
449                         document.getElementById('no_meta_prompt')
450                                 .style.visibility = 'hidden';
451                 }
452         },
453
454         // Rotate selected files
455         rotate: function(degrees) {
456
457                 // Prevent silliness
458                 var s = photos.selected;
459                 var ii = s.length;
460                 if (0 == ii) { return; }
461                 photos.selected = [];
462                 mouse.click({target: {}});
463
464                 // For each selected image, show the loading spinner and dispatch
465                 // the rotate job
466                 buttons.upload.disable();
467                 for (var i = 0; i < ii; ++i) {
468                         block_normalize();
469                         var p = photos.list[s[i]];
470                         if (photos.is_photo(p.path)) {
471                                 block_sort();
472                                 photos.batch_size -= p.size;
473                                 var img = document.getElementById('photo' + p.id)
474                                         .getElementsByTagName('img')[0];
475                                 img.className = 'loading';
476                                 img.setAttribute('width', 16);
477                                 img.setAttribute('height', 8);
478                                 img.src = 'chrome://uploadr/skin/balls-16x8-trans.gif';
479                                 threads.worker.dispatch(new Rotate(p.id, degrees,
480                                         conf.thumb_size, p.path),
481                                         threads.worker.DISPATCH_NORMAL);
482                         }
483                 }
484                 threads.worker.dispatch(new EnableUpload(),
485                         threads.worker.DISPATCH_NORMAL);
486
487         },
488
489         // Upload photos
490         //   The arguments will either both be null or both be set
491         //   If they're both set, this is an automated call to upload by the
492         //   queue
493         upload: function(list, size) {
494                 var from_user = null == list;
495                 if (from_user) { list = photos.list; }
496
497                 // Don't upload if this is a user action and the button is disabled
498                 if (from_user && 'disabled_button' == document.getElementById(
499                         'button_upload').className) {
500                         return;
501                 }
502
503                 // Remove error indicators
504                 var li = document.getElementById('photos_list')
505                         .getElementsByTagName('li');
506                 var ii = li.length;
507                 for (var i = 0; i < ii; ++i) {
508                         var img = li[i].getElementsByTagName('img')[0];
509                         if ('error' == img.className) {
510                                 img.onclick();
511                         }
512                 }
513
514                 // Decide if we're already in the midst of an upload
515                 var not_started = 0 == photos.uploading.length;
516
517                 // Drop videos if we're a free user or they're over 100MB
518                 //   They will have been warned that this is coming
519                 if (from_user) {
520                         var new_list = [];
521                         for each (var p in list) {
522                                 if (null == p) {
523                                         continue;
524                                 }
525                                 if (photos.is_photo(p.path)) {
526                                         new_list.push(p);
527                                 } else if (!users.is_pro || (null == users.videosize
528                                         ? conf.videosize : users.videosize) < p.size) {
529                                         photos.batch_size -= p.size;
530                                 } else {
531                                         new_list.push(p);
532                                 }
533                         }
534                         list = new_list;
535                 }
536
537                 // If any photos need resizing to fit in the per-photo size limits,
538                 // dispatch the jobs and wait
539                 if (from_user && !upload.processing || !from_user) {
540                         var resizing = false;
541                         var ready = [];
542                         var ready_size = 0;
543                         for each (var p in list) {
544                                 if (null != p) {
545                                         if (photos.is_photo(p.path)) {
546
547                                                 // Resize because of user settings
548                                                 if (null != settings.resize &&
549                                                         -1 != settings.resize &&
550                                                         (p.width > settings.resize ||
551                                                         p.height > settings.resize)) {
552                                                         resizing = true;
553                                                         threads.worker.dispatch(new Resize(
554                                                                 p.id, settings.resize, p.path),
555                                                                 threads.worker.DISPATCH_NORMAL);
556                                                 }
557
558                                                 // Resize because of upload limits
559                                                 else if (p.size > users.filesize) {
560                                                         resizing = true;
561                                                         threads.worker.dispatch(new Resize(p.id, -1,
562                                                                 p.path), threads.worker.DISPATCH_NORMAL);
563                                                 }
564
565                                                 // Not resizing so record size now
566                                                 else {
567                                                         ready_size += p.size;
568                                                 }
569
570                                         }
571
572                                         // By this point there are no videos that break the rules
573                                         else {
574                                                 ready_size += p.size;
575                                         }
576
577                                         ready.push(p);
578                                 }
579                         }
580                         if (resizing) {
581
582                                 // Setup the batch to try again after the resizing
583                                 photos.ready.push(ready);
584                                 photos.ready_size.push(ready_size);
585                                 photos.batch_size = 0;
586                                 photos.list = [];
587                                 photos.count = 0;
588                                 photos.selected = [];
589                                 photos.last = null;
590                                 var list = document.getElementById('photos_list');
591                                 while (list.hasChildNodes()) {
592                                         list.removeChild(list.firstChild);
593                                 }
594                                 ui.bandwidth_updated();
595                                 threads.worker.dispatch(new RetryUpload(true),
596                                         threads.worker.DISPATCH_NORMAL);
597
598                                 // Give some meaningful feedback
599                                 if (not_started) {
600                                         document.getElementById('footer').style.display =
601                                                 '-moz-box';
602                                         upload.progress_bar = new ProgressBar('progress_bar');
603                                         var progress_text = document.getElementById(
604                                                 'progress_text');
605                                         progress_text.className = 'spinning';
606                                         progress_text.value = locale.getString(
607                                                 'upload.resizing.status');
608                                         status.set(locale.getString('status.uploading'));
609                                         buttons.upload.disable();
610                                         document.getElementById('photos_sort_default')
611                                                 .style.display = 'none';
612                                         document.getElementById('photos_sort_revert')
613                                                 .style.display = 'none';
614                                         document.getElementById('photos_init')
615                                                 .style.display = 'none';
616                                         document.getElementById('photos_new')
617                                                 .style.display = '-moz-box';
618                                         document.getElementById('no_meta_prompt')
619                                                 .style.visibility = 'hidden';
620                                         meta.disable();
621                                         photos.sets[users.nsid] = meta.sets;
622                                 }
623
624                                 return;
625                         }
626                 }
627
628                 // Update the UI
629                 if (from_user) {
630                         status.set(locale.getString('status.uploading'));
631                         document.getElementById('t_clear').className = 'disabled_button';
632                         buttons.upload.disable();
633                         document.getElementById('photos_sort_default')
634                                 .style.display = 'none';
635                         document.getElementById('photos_sort_revert')
636                                 .style.display = 'none';
637                         document.getElementById('photos_init')
638                                 .style.display = 'none';
639                         document.getElementById('photos_new')
640                                 .style.display = '-moz-box';
641                         document.getElementById('no_meta_prompt')
642                                 .style.visibility = 'hidden';
643                         meta.disable();
644                         photos.sets[users.nsid] = meta.sets;
645                 }
646
647                 // We're really going to start or queue a batch, so do extension stuff
648                 extension.before_upload.exec(list);
649
650                 // Take the list of photos into upload mode and reset the UI
651                 var ready = [];
652                 for each (var p in list) {
653
654                         // Keep the uploading user's NSID with each photo so to allow
655                         // people to change accounts from one batch to the next
656                         p.nsid = users.nsid;
657
658                         // If we have to queue this batch
659                         if (from_user && upload.processing) {
660                                 ready.push(p);
661                         }
662
663                         // If we can upload immediately
664                         else {
665                                 photos.uploading.push(p);
666
667                                 // Setup progress bar for this photo and show it in the queue
668                                 var img = document.createElementNS(NS_HTML, 'img');
669                                 img.src = 'file:///' + escape(p.thumb);
670                                 img.width = p.thumb_width;
671                                 img.height = p.thumb_height;
672                                 var stack = document.createElement('stack');
673                                 stack.appendChild(img);
674                                 p.progress_bar = new ProgressBar('queue' +
675                                         (photos.uploading.length - 1), img.width);
676                                 var bar = p.progress_bar.create();
677                                 bar.style.top = (img.height - 20) + 'px';
678                                 stack.appendChild(bar);
679                                 var li = document.createElementNS(NS_HTML, 'li');
680                                 li.appendChild(stack);
681                                 document.getElementById('queue_list').appendChild(li);
682
683                         }
684
685                 }
686                 if (from_user && upload.processing) {
687                         photos.ready.push(ready);
688                         photos.ready_size.push(photos.batch_size);
689                 } else {
690                         if (from_user) {
691                                 photos.kb.total += photos.batch_size;
692                         } else {
693                                 photos.kb.total += size;
694                         }
695                 }
696                 if (from_user) {
697                         photos.batch_size = 0;
698                         photos.list = [];
699                         photos.count = 0;
700                         photos.selected = [];
701                         photos.last = null;
702                         var ul = document.getElementById('photos_list');
703                         while (ul.hasChildNodes()) {
704                                 ul.removeChild(ul.firstChild);
705                         }
706                         ui.bandwidth_updated();
707                 }
708
709         upload.startTime = new Date().getTime();
710        
711                 // Kick off the first batch job if we haven't started
712                 if (not_started && !upload.processing) {
713                         ii = photos.uploading.length;
714                         for (var i = 0; i < ii; ++i) {
715                                 if (null != photos.uploading[i]) {
716                                         block_exit();
717                                         upload.start(i);
718                                         break;
719                                 }
720                         }
721                 }
722
723         },
724
725         // Normalize the photo list and selected list with the DOM
726         normalize: function() {
727
728                 // This action is blocked during loading but will always
729                 // happen at the end of loading
730                 if (_block_normalize) { return; }
731
732                 var list = document.getElementById('photos_list')
733                         .getElementsByTagName('li');
734                 var old_list = photos.list;
735                 photos.list = [];
736                 photos.selected = [];
737                 for (var i = list.length - 1; i >= 0; --i) {
738
739                         // Move the photo info
740                         var old_id = parseInt(list[i].id.replace('photo', ''));
741                         var new_id = photos.list.length;
742                         list[i].id = 'photo' + new_id;
743                         photos.list.push(old_list[old_id]);
744                         photos.list[new_id].id = new_id;
745
746                         // Update selection
747                         if ('selected' == list[i].getElementsByTagName('img')[0]
748                                 .className) {
749                                 photos.selected.push(new_id);
750                         }
751
752                 }
753         },
754
755         // Load saved metadata
756         load: function() {
757                 var obj = file.read('photos.json');
758
759                 // Don't bother if there are no photos
760                 if ('undefined' == typeof obj.list) { return; }
761
762                 // Add the previous batch of photos
763                 var list = obj.list;
764                 if (list.length) {
765                         photos.sort = obj.sort;
766                         document.getElementById('photos_init').style.display = 'none';
767                         document.getElementById('photos_new').style.display = 'none';
768                         document.getElementById('no_meta_prompt')
769                                 .style.visibility = 'visible';
770                 }
771                 photos.add(list, true);
772
773                 // Bring in last known sets configuration
774                 meta.sets = obj.sets;
775
776         },
777
778     // clear photos.json
779     // this is desperate move when the uploadr is in unusable state
780     removeAll: function() {
781         if (document.getElementById('t_clear').className == 'disabled_button')
782             return;
783         document.getElementById('t_clear').className = 'disabled_button';
784         photos.thumb_cancel = true;
785         if (conf.console.thumb) {
786                                 logStringMessage('clearing');
787                         }
788         photos.list = [];
789         photos.selected = [];
790         photos.count = 0;
791         photos.errors = 0;
792         photos.batch_size = 0;
793         _block_sort = _block_remove = _block_normalize = _block_exit = 0;
794         file.remove('photos.json');
795         // Remove photos from UI
796         var list = document.getElementById('photos_list');
797                 while (list.hasChildNodes()) {
798                     list.removeChild(list.firstChild);
799         }
800         document.getElementById('photos_init').style.display = '-moz-box';
801         ui.bandwidth_updated();
802         meta.disable();
803         buttons.upload.disable();
804     },
805    
806         // Save all metadata to disk
807         save: function() {
808                 if (0 != _block_exit) { return; }
809                 if (1 == photos.selected.length) {
810                         meta.save(photos.selected[0]);
811                 }
812                 file.write('photos.json', {
813                         sort: photos.sort,
814                         sets: meta.sets,
815                         list: photos.list
816                 });
817         },
818
819         // Decide if a given path is a photo
820         is_photo: function(path) {
821                 return /\.(jpe?g|tiff?|gif|png|bmp)$/i.test(path);
822         },
823
824         // Similarly, is it a video
825         is_video: function(path) {
826                 return /\.(mp4|mpe?g|avi|wmv|mov|dv|3gp|3g2|m4v)$/i.test(path);
827         }
828
829 };
830
831 // Setup auto-saving of metadata in case of crashes
832 //   See photos.save for problems related to the auto-save interval
833 window.setInterval(function() {
834         photos.save();
835 }, 1000 * conf.auto_save);
836
837 // Photo properties
838 var Photo = function(id, path) {
839         this.id = id;
840         this.path = path;
841         this.date_taken = '';
842         this.width = 0;
843         this.height = 0;
844         this.thumb = '';
845         this.thumb_width = 0;
846         this.thumb_height = 0;
847         var filename = path.match(/([^\/\\]*)$/);
848         this.filename = null == filename ? p : filename[1];
849         this.size = 0; // Kilobytes
850         this.title = '';
851         this.description = '';
852         this.tags = '';
853         this.duration = 0;
854         this.is_public = settings.is_public;
855         this.is_friend = settings.is_friend;
856         this.is_family = settings.is_family;
857         this.content_type = settings.content_type;
858         this.safety_level = settings.safety_level;
859         this.hidden = settings.hidden;
860         this.sets = [];
861         this.progress_bar = null;
862         this.nsid = null;
863         this.photo_id = null;
864 };
Note: See TracBrowser for help on using the browser.