r64060 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r64059‎ | r64060 | r64061 >
Date:05:54, 23 March 2010
Author:neilk
Status:deferred
Tags:
Comment:
refactor to use jquery events -- not only much simpler, this makes step 2 -> step 3 much easier
Modified paths:
  • /branches/js2-work/phase3/js/mwEmbed/modules/UploadWizard/mw.ApiUploadHandler.js (modified) (history)
  • /branches/js2-work/phase3/js/mwEmbed/modules/UploadWizard/mw.MockUploadHandler.js (modified) (history)
  • /branches/js2-work/phase3/js/mwEmbed/modules/UploadWizard/mw.UploadWizard.js (modified) (history)

Diff [purge]

Index: branches/js2-work/phase3/js/mwEmbed/modules/UploadWizard/mw.UploadWizard.js
@@ -60,6 +60,7 @@
6161 } );
6262
6363
 64+//mw.setConfig('uploadHandlerClass', mw.MockUploadHandler); // ApiUploadHandler?
6465
6566 // available licenses should be a configuration of the MediaWiki instance,
6667 // not hardcoded here.
@@ -129,17 +130,109 @@
130131 /**
131132 * Represents the upload -- in its local and remote state. (Possibly those could be separate objects too...)
132133 * This is our 'model' object if we are thinking MVC. Needs to be better factored, lots of feature envy with the UploadWizard
 134+ * states:
 135+ * 'new' 'transporting' 'transported' 'details' 'submitting-details' 'complete'
 136+ * should fork this into two -- local and remote, e.g. filename
133137 */
134138 mw.UploadWizardUpload = function() {
135139 var _this = this;
 140+ _this.state = 'new';
 141+ _this.transportWeight = 1; // default
 142+ _this.detailsWeight = 1; // default
136143 _this._thumbnails = {};
137144 _this.imageinfo = {};
138145 _this.title = undefined;
139146 _this.filename = undefined;
140147 _this.originalFilename = undefined;
 148+ _this.mimetype = undefined;
 149+
 150+ // details
 151+ _this.details = new mw.UploadWizardDetails( _this, $j( '#mwe-upwiz-macro-files' ));
 152+ _this.ui = new mw.UploadWizardUploadInterface( _this );
 153+
 154+ // handler -- usually ApiUploadHandler
 155+ // _this.handler = new ( mw.getConfig( 'uploadHandlerClass' ) )( _this );
 156+ // _this.handler = new mw.MockUploadHandler( _this );
 157+ _this.handler = new mw.ApiUploadHandler( _this );
141158 };
142159
143160 mw.UploadWizardUpload.prototype = {
 161+
 162+ /**
 163+ * start
 164+ */
 165+ start: function() {
 166+ var _this = this;
 167+ _this.setTransportProgress(0.0);
 168+ _this.handler.start();
 169+ _this.ui.start();
 170+ },
 171+
 172+
 173+ /**
 174+ * remove
 175+ */
 176+ remove: function() {
 177+ var _this = this;
 178+ $j( _this.ui.div ).remove();
 179+ $j( _this.details.div ).remove();
 180+ $j( _this ).trigger( 'removeUpload' );
 181+ },
 182+
 183+ /**
 184+ * Wear our current progress, for observing processes to see
 185+ * @param fraction
 186+ */
 187+ setTransportProgress: function ( fraction ) {
 188+ var _this = this;
 189+ _this.state = 'transporting';
 190+ _this.transportProgress = fraction;
 191+ $j( _this ).trigger( 'transportProgress' );
 192+ },
 193+
 194+ /**
 195+ * To be executed when an individual upload finishes. Processes the result and updates step 2's details
 196+ * @param result the API result in parsed JSON form
 197+ */
 198+ setTransported: function( result ) {
 199+ var _this = this;
 200+ _this.state = 'transported';
 201+ _this.transportProgress = 1;
 202+ $j( _this ).trigger( 'transported' );
 203+
 204+ if ( result.upload && result.upload.imageinfo && result.upload.imageinfo.descriptionurl ) {
 205+ // success
 206+ _this.extractImageInfo( result );
 207+ _this.details.populate();
 208+
 209+ } else if ( result.upload && result.upload.sessionkey ) {
 210+ // there was a warning - type error which prevented it from adding the result to the db
 211+ if ( result.upload.warnings.duplicate ) {
 212+ var duplicates = result.upload.warnings.duplicate;
 213+ _this.details.errorDuplicate( result.upload.sessionkey, duplicates );
 214+ }
 215+
 216+ // and other errors that result in a stash
 217+ } else if ( 0 /* actual failure */ ) {
 218+ // we may want to tag or otherwise queue it as an upload to retry
 219+ }
 220+
 221+
 222+ },
 223+
 224+
 225+ /**
 226+ * call when the file is entered into the file input
 227+ * get as much data as possible -- maybe exif, even thumbnail maybe
 228+ */
 229+ initializeLocalFile: function() {
 230+ if (false) { // FileAPI, one day
 231+ _this.transportWeight = getFileSize();
 232+ }
 233+ // XXX add filename, original filename, extension, whatever else is interesting.
 234+ },
 235+
 236+
144237 /**
145238 * Accept the result from a successful API upload transport, and fill our own info
146239 *
@@ -227,13 +320,12 @@
228321
229322 /**
230323 * Create an interface fragment corresponding to a file input, suitable for Upload Wizard.
231 - * @param filenameAcceptedCb Execute if good filename entered into this interface; useful for knowing if we're ready to upload
 324+ * @param upload
232325 */
233 -mw.UploadWizardUploadInterface = function( upload, filenameAcceptedCb ) {
 326+mw.UploadWizardUploadInterface = function( upload ) {
234327 var _this = this;
235328
236329 _this.upload = upload;
237 - _this.filenameAcceptedCb = filenameAcceptedCb;
238330
239331 // may need to collaborate with the particular upload type sometimes
240332 // for the interface, as well as the uploadwizard. OY.
@@ -260,15 +352,26 @@
261353
262354 _this.errorDiv = $j('<div class="mwe-upwiz-upload-error" style="display: none;"></div>').get(0);
263355
 356+ _this.removeCtrl = $j( '<a title="' + gM( 'mwe-upwiz-remove-upload' )
 357+ + '" href="#" class="mwe-upwiz-remove">x</a>' )
 358+ .click( function() { _this.upload.remove() } )
 359+ .get( 0 );
264360
 361+
 362+
265363 $j( _this.div ).append( _this.form )
266364 .append( _this.progressMessage )
267 - .append( _this.errorDiv );
 365+ .append( _this.errorDiv )
 366+ .append( _this.removeCtrl );
268367
269368 // _this.progressBar = ( no progress bar for individual uploads yet )
270369 // add a details thing to details
 370+ // this should bind only to the FIRST transportProgress
 371+ $j( upload ).bind( 'transportProgress', function(e) { _this.showTransportProgress(); e.stopPropagation() } );
 372+ $j( upload ).bind( 'transported', function(e) { _this.showTransported(); e.stopPropagation(); } );
271373 };
272374
 375+
273376 mw.UploadWizardUploadInterface.prototype = {
274377 /**
275378 * Things to do to this interface once we start uploading
@@ -286,18 +389,26 @@
287390 var _this = this;
288391 // for now we implement this as looking like "100% progress"
289392 // e.g. an animated bar that takes up all the space
290 - _this.progress( 1.0 );
 393+ _this.showTransportProgress( 1.0 );
291394 },
292395
293396 /**
294397 * Show progress by a fraction
295398 * @param fraction The fraction of progress. Float between 0 and 1
296399 */
297 - progress: function( fraction ) {
 400+ showTransportProgress: function() {
298401 var _this = this;
299402 $j( _this.progressMessage ).addClass('mwe-upwiz-status-progress')
300403 .html(gM( 'mwe-upwiz-uploading' ))
301404 .show();
 405+ // since, in this iteration of the interface, we never need to know
 406+ // about progress again, let's unbind
 407+
 408+ // unbind is broken in jquery 1.4.1 -- raises exception but it still works
 409+ try {
 410+ $j( _this.upload ).unbind( 'transportProgress' );
 411+ } catch (ex) { }
 412+
302413 // update individual progress bar with fraction?
303414 },
304415
@@ -305,7 +416,7 @@
306417 * Execute when this upload is transported; cleans up interface.
307418 * @param result AJAx result object
308419 */
309 - transported: function( result ) {
 420+ showTransported: function() {
310421 var _this = this;
311422 $j( _this.progressMessage ).removeClass( 'mwe-upwiz-status-progress' )
312423 .addClass( 'mwe-upwiz-status-transported' )
@@ -350,8 +461,8 @@
351462 _this.upload.originalFilename = filename;
352463 // this is a hack to get a filename guaranteed unique.
353464 uniqueFilename = mw.getConfig( 'userName' ) + "_" + ( new Date() ).getTime() + "_" + filename;
354 - $j(_this.filenameCtrl).attr( 'value', uniqueFilename );
355 - _this.filenameAcceptedCb();
 465+ $j( _this.filenameCtrl ).attr( 'value', uniqueFilename );
 466+ $j( _this.upload ).trigger( 'filenameAccepted' );
356467 },
357468
358469 /**
@@ -489,6 +600,8 @@
490601 * on the page which we clone and slice up with selectors. Inputs can still be members of the object
491602 * but they'll be found by selectors, not by creating them as members and then adding them to a DOM structure.
492603 *
 604+ * XXX this should have styles for what mode we're in
 605+ *
493606 * @param UploadWizardUpload
494607 * @param containerDiv The div to put the interface into
495608 */
@@ -501,6 +614,9 @@
502615
503616 _this.div = $j( '<div class="mwe-upwiz-details-file"></div>' );
504617
 618+ _this.macroDiv = $j( '<div class="mwe-upwiz-macro"></div>' )
 619+ .append( $j( '<input type="submit" value="test edit"/>' ).click( function( ) { _this.submit( ) } ));
 620+
505621 _this.thumbnailDiv = $j( '<div class="mwe-upwiz-thumbnail"></div>' );
506622
507623 _this.errorDiv = $j( '<div class="mwe-upwiz-details-error"></div>' );
@@ -612,6 +728,7 @@
613729 _this.filenameInput = $j('<input type="text" class="mwe-filename" size="30" />' )
614730 .keyup( function() {
615731 $j( _this.titleInput ).val( mw.UploadWizardUtil.titleToPath( $j( _this.filenameInput ).val() ) )
 732+ .keyup(); // simulate keyup to trigger destination check
616733 });
617734
618735 var aboutTheFileDiv = $j('<div></div>')
@@ -633,6 +750,7 @@
634751
635752
636753 $j( _this.div )
 754+ .append( _this.macroDiv ) // XXX this is wrong; it's not part of a file's details
637755 .append( _this.thumbnailDiv )
638756 .append( _this.errorDiv )
639757 .append( $j( _this.dataDiv )
@@ -823,36 +941,6 @@
824942 },
825943
826944 /**
827 - * Display an error but check before proceeding -- useful for cases where user can override a failed upload due to
828 - * hash collision
829 - * just like error but with ok / cancel
830 - * @param sessionKey
831 - * @param duplicates
832 - */
833 - errorDuplicate: function( sessionKey, duplicates ) {
834 - var _this = this;
835 - /*
836 - TODO - do something clever to get page URLs and image URLs
837 - var duplicatePageTitles = result.upload.warnings.duplicate;
838 - var duplicates = [];
839 - for ( var i = 0; i < duplicates.length; i++ ) {
840 - imageInfo = mw.getJSON( undefined,
841 - {'titles' : duplicatePageTitles[i], 'prop' : 'imageinfo'})
842 - function() { _this.renderUploads() } );
843 - duplicates.push( {
844 - // ?? async, so we should insert later...
845 - } )
846 - }
847 - */
848 - _this.error( 'duplicate' );
849 - // add placeholder spinners to div, and then fetch the thumbnails and so on async
850 - // meanwhile...
851 - //$j( _this.errorDiv ).append(
852 - // $j('<form></form>');
853 - // same as normal error but you get to ok / cancel, which resubmits with ignore warnings
854 - },
855 -
856 - /**
857945 * Given the API result pull some info into the form ( for instance, extracted from EXIF, desired filename )
858946 * @param result Upload API result object
859947 */
@@ -880,8 +968,7 @@
881969 // side effect: will replace thumbnail's loadingSpinner
882970 _this.thumbnailDiv.html(
883971 $j('<a>')
884 - .attr( { 'href': _this.upload.imageinfo.descriptionurl,
885 - 'target': '_new' } )
 972+ .attr( 'href', _this.upload.imageinfo.descriptionurl )
886973 .append(
887974 $j( '<img/>' )
888975 .addClass( "mwe-upwiz-thumbnail" )
@@ -939,8 +1026,7 @@
9401027 */
9411028 prefillTitle: function() {
9421029 var _this = this;
943 - $j( _this.titleInput ).val( mw.UploadWizardUtil.titleToPath( _this.upload.originalFilename ) )
944 - .change(); // trigger file destination check
 1030+ $j( _this.titleInput ).val( mw.UploadWizardUtil.titleToPath( _this.upload.originalFilename ) );
9451031 },
9461032
9471033 /**
@@ -1126,9 +1212,8 @@
11271213
11281214 /**
11291215 * Post wikitext as edited here, to the file
1130 - * @param success callback to be executed upon success
11311216 */
1132 - submit: function(success) {
 1217+ submit: function() {
11331218 var _this = this;
11341219
11351220
@@ -1166,9 +1251,7 @@
11671252 mw.log(result);
11681253 mw.log("successful edit");
11691254 if ( shouldRename ) {
1170 - _this.rename( desiredFilename, success );
1171 - } else {
1172 - success();
 1255+ _this.rename( desiredFilename );
11731256 }
11741257
11751258 }
@@ -1187,7 +1270,7 @@
11881271 *
11891272 * @param filename to rename this file to
11901273 */
1191 - rename: function( title, success ) {
 1274+ rename: function( title ) {
11921275 var _this = this;
11931276 mw.log("renaming!");
11941277 params = {
@@ -1210,12 +1293,10 @@
12111294 if (data !== undefined && data.move !== undefined && data.move.to !== undefined) {
12121295 _this.upload.title = data.move.to;
12131296 }
1214 -
12151297 // { move = { from : ..., reason : ..., redirectcreated : ..., to : .... }
12161298 // which should match our request.
12171299 // we should update the current upload filename
12181300 // then call the uploadwizard with our progress
1219 - success();
12201301 } );
12211302 }
12221303
@@ -1230,25 +1311,15 @@
12311312 */
12321313 mw.UploadWizard = function() {
12331314
1234 - this.uploadHandlerClass = mw.getConfig('uploadHandlerClass') || this.getUploadHandlerClass();
1235 - this.isTransported = false;
1236 -
 1315+ this.state = 'new';
12371316 this.uploads = [];
1238 - // leading underline for privacy. DO NOT TAMPER.
1239 - this._uploadsQueued = [];
1240 - this._uploadsInProgress = [];
1241 - this._uploadsTransported = [];
1242 - this._uploadsEditingDetails = [];
1243 - this._uploadsCompleted = [];
12441317
1245 - this.uploadsBeginTime = null;
1246 -
12471318 };
12481319
 1320+
12491321 mw.UploadWizard.userAgent = "UploadWizard (alpha) on " + $j.browser.name + " " + $j.browser.version;
12501322
12511323
1252 -
12531324 mw.UploadWizard.prototype = {
12541325 maxUploads: 10, // XXX get this from config
12551326 maxSimultaneousUploads: 2, // XXX get this from config
@@ -1272,7 +1343,6 @@
12731344 * For example, the ApiUploadHandler should work just about everywhere, but XhrUploadHandler
12741345 * allows for more fine-grained upload progress
12751346 * @return valid JS upload handler class constructor function
1276 - */
12771347 getUploadHandlerClass: function() {
12781348 // return mw.MockUploadHandler;
12791349 return mw.ApiUploadHandler;
@@ -1286,16 +1356,16 @@
12871357 }
12881358 // this should never happen; NullUploadHandler should always work
12891359 return null;
1290 - */
12911360 },
 1361+ */
12921362
12931363 /**
12941364 * create the basic interface to make an upload in this div
12951365 * @param div The div in the DOM to put all of this into.
12961366 */
12971367 createInterface: function( selector ) {
1298 - var div = $j( selector ).get(0);
12991368 var _this = this;
 1369+ var div = $j( selector ).get(0);
13001370 div.innerHTML =
13011371
13021372 '<div id="mwe-upwiz-tabs">'
@@ -1325,8 +1395,13 @@
13261396 + '</div>'
13271397 + '</div>'
13281398 + '<div id="mwe-upwiz-tabdiv-details">'
1329 - + '<div id="mwe-upwiz-macro"></div>'
1330 - + '<div id="mwe-upwiz-details-files"></div>'
 1399+ + '<div id="mwe-upwiz-macro">'
 1400+ + '<div id="mwe-upwiz-macro-choice"></div>'
 1401+ + '<div id="mwe-upwiz-macro-edit"></div>'
 1402+ + '<div id="mwe-upwiz-macro-macro"></div>'
 1403+ + '<div id="mwe-upwiz-macro-files"></div>'
 1404+ + '</div>'
 1405+ + '</div>'
13311406 + '</div>'
13321407 + '<div id="mwe-upwiz-tabdiv-thanks">'
13331408 + '<div id="mwe-upwiz-thanks"></div>'
@@ -1335,9 +1410,6 @@
13361411
13371412 + '<div id="mwe-upwiz-clearing"></div>';
13381413
1339 - // add macro interface
1340 - _this.addMacroHtml('#mwe-upwiz-macro');
1341 -
13421414 // within FILE tab div
13431415 // select files:
13441416 // place for file interfaces
@@ -1357,19 +1429,6 @@
13581430 },
13591431
13601432 /**
1361 - * Attach interface for selecting case, license, etc.
1362 - * Called "macro" because it affects many at once. Also set the mode of UW details -- may rewrite individual details objects to
1363 - * use a common license input, for instance.
1364 - */
1365 - addMacroHtml: function( selector ) {
1366 - var _this = this;
1367 - $j( selector )
1368 - .append( $j( '<input type="submit" value="submit"/>' )
1369 - .click( function() { _this.startMacroSubmit() } ) );
1370 - },
1371 -
1372 -
1373 - /**
13741433 * Advance one "step" in the wizard interface.
13751434 * @param selectedTabName
13761435 */
@@ -1399,58 +1458,23 @@
14001459 */
14011460 addUpload: function() {
14021461 var _this = this;
1403 - var idx = _this.uploads.length; // or?
1404 - if ( idx == _this.maxUploads ) {
 1462+ if ( _this.uploads.length == _this.maxUploads ) {
14051463 return false;
14061464 }
14071465
14081466 var upload = new mw.UploadWizardUpload();
1409 -
1410 - // XXX much of the following should be moved to UploadWizardUpload constructor.
1411 -
1412 - // UI
1413 - // originalFilename is the basename of the file on our file system. This is what we really wanted ( probably ).
1414 - // the system will upload with a temporary filename and we'll get that back from the API return when we upload
1415 - var filenameAcceptedCb = function() {
1416 - _this.updateFileCounts();
1417 - };
1418 - var ui = new mw.UploadWizardUploadInterface( upload, filenameAcceptedCb );
1419 - ui.removeCtrl = $j( '<a title="' + gM( 'mwe-upwiz-remove-upload' )
1420 - + '" href="#" class="mwe-upwiz-remove">x</a>' )
1421 - .click( function() { _this.removeUpload( upload ) } )
1422 - .get( 0 );
1423 - $j( ui.div ).append( ui.removeCtrl );
1424 -
1425 - upload.ui = ui;
1426 - // handler -- usually ApiUploadHandler
1427 - upload.handler = new _this.uploadHandlerClass( upload.ui );
1428 -
1429 - // this is for UI only...
1430 - upload.handler.addProgressCb( function( fraction ) { _this.uploadProgress( upload, fraction ) } );
1431 -
 1467+ $j( upload ).bind( 'filenameAccepted', function(e) { _this.updateFileCounts(); e.stopPropagation(); } );
 1468+ $j( upload ).bind( 'removeUpload', function(e) { _this.removeUpload( upload ); e.stopPropagation(); } );
14321469 // this is only the UI one, so is the result even going to be there?
1433 - upload.handler.addTransportedCb( function( result ) { _this.uploadTransported( upload, result ) } );
14341470
1435 - // not sure about this...UI only?
1436 - // this will tell us that at least one of our uploads has had an error -- may change messaging,
1437 - // like, please fix below
1438 - upload.handler.addErrorCb( function( error ) { _this.uploadError( upload, error ) } );
 1471+ // bind to some error state
14391472
1440 - // details
1441 - upload.details = new mw.UploadWizardDetails( upload, $j( '#mwe-upwiz-details-files' ));
1442 -
1443 -
14441473 _this.uploads.push( upload );
14451474
14461475 $j( "#mwe-upwiz-files" ).append( upload.ui.div );
14471476
1448 -
1449 -
1450 -
1451 - //$j("#testac").languageMenu();
1452 -
1453 - // update the uploadUi to add files - we may be over limit
14541477 _this.updateFileCounts();
 1478+
14551479 return true;
14561480 },
14571481
@@ -1463,8 +1487,6 @@
14641488 */
14651489 removeUpload: function( upload ) {
14661490 var _this = this;
1467 - $j( upload.ui.div ).remove();
1468 - $j( upload.details.div ).remove();
14691491 mw.UploadWizardUtil.removeItem( _this.uploads, upload );
14701492 _this.updateFileCounts();
14711493 },
@@ -1482,11 +1504,60 @@
14831505 }
14841506 };
14851507 for ( var i = 0; i < toRemove.length; i++ ) {
1486 - _this.removeUpload( toRemove[i] );
 1508+ toRemove[i].remove();
14871509 }
14881510 },
14891511
14901512 /**
 1513+ * monitor progress
 1514+ */
 1515+ makeMonitor: function( beginState, progressState, endState, progressProperty, weightProperty,
 1516+ progressCallback, countCallback, endCallback ) {
 1517+
 1518+ var wizard = this;
 1519+
 1520+ var totalWeight = 0.0;
 1521+ $j.each( wizard.uploads, function( i, upload ) {
 1522+ totalWeight += upload[weightProperty];
 1523+ } );
 1524+ var totalCount = wizard.uploads.length;
 1525+
 1526+ var monitorBeginTime = ( new Date() ).getTime();
 1527+
 1528+ monitor = function() {
 1529+ var fraction = 0.0;
 1530+ var uploadsToStart = wizard.maxSimultaneousUploads;
 1531+ var endStateCount = 0;
 1532+ $j.each( wizard.uploads, function(i, upload) {
 1533+ if ( upload.state == endState ) {
 1534+ endStateCount++;
 1535+ } else if ( upload.state == progressState ) {
 1536+ uploadsToStart--;
 1537+ } else if ( ( upload.state == beginState ) && ( uploadsToStart > 0 ) ) {
 1538+ upload.start();
 1539+ uploadsToStart--;
 1540+ }
 1541+ if (upload[progressProperty] !== undefined) {
 1542+ fraction += upload[progressProperty] * ( upload[weightProperty] / totalWeight );
 1543+ }
 1544+ } );
 1545+ progressCallback( fraction, monitorBeginTime );
 1546+ countCallback( endStateCount, totalCount );
 1547+ if (endStateCount == totalCount) {
 1548+ endCallback();
 1549+ } else {
 1550+ setTimeout( monitor, wizard.monitorDelay );
 1551+ }
 1552+ }
 1553+
 1554+ monitor();
 1555+ },
 1556+
 1557+ monitorDelay: 300, // milliseconds
 1558+
 1559+
 1560+
 1561+ /**
14911562 * Kick off the upload processes.
14921563 * Does some precalculations, changes the interface to be less mutable, moves the uploads to a queue,
14931564 * and kicks off a thread which will take from the queue.
@@ -1501,112 +1572,48 @@
15021573 // remove ability to change files
15031574 // ideally also hide the "button"... but then we require styleable file input CSS trickery
15041575 // although, we COULD do this just for files already in progress...
1505 -
1506 - // XXX we just want to VISUALLY lock it in -- disabling this seems to remove it from form post
1507 - // $j( '.mwe-upwiz-file' ).attr( 'disabled', 'disabled' );
15081576
15091577 // add the upload progress bar, with ETA
15101578 // add in the upload count
15111579 $j( '#mwe-upwiz-progress' ).show();
1512 -
1513 - _this.uploadsBeginTime = ( new Date() ).getTime();
1514 -
1515 - var canGetFileSize = ( _this.uploadHandlerClass.prototype.getFileSize !== undefined );
15161580
1517 - // queue the uploads
1518 - _this.totalWeight = 0;
1519 - for ( var i = 0; i < _this.uploads.length; i++ ) {
1520 - var upload = _this.uploads[i];
1521 -
1522 - // we may want to do something clever here to detect
1523 - // whether this is a real or dummy weight
1524 - if ( canGetFileSize ) {
1525 - upload.weight = upload.getFileSize();
1526 - } else {
1527 - upload.weight = 1;
1528 - }
1529 - _this.totalWeight += upload.weight;
1530 -
1531 - _this._uploadsQueued.push( upload );
1532 - }
1533 - setTimeout( function () { _this._startUploadsQueued(); }, 0 );
 1581+ // it might be interesting to just make this creational -- attach it to the dom element representing
 1582+ // the progress bar and elapsed time
 1583+ _this.makeMonitor('new', 'transporting', 'transported',
 1584+ 'transportProgress', 'transportWeight',
 1585+ function( fraction, beginTime) {
 1586+ _this.showProgress( fraction, beginTime );
 1587+ },
 1588+ function ( endStateCount, totalCount) {
 1589+ _this.showCount( endStateCount, totalCount );
 1590+ },
 1591+ function() { _this.moveToTab('details') } );
15341592 },
15351593
15361594 /**
1537 - * Uploads must be 'queued' to be considered for uploading / details submission
1538 - * making this another thread of execution, because we want to avoid any race condition
1539 - * this way, this is the only "thread" that can start uploads
1540 - * it may miss a newly transported upload but it will get it eventually
1541 - * it is the responsibility of upload.handler.start() or upload.details.submit() to move items
1542 - * out of the queues.
1543 - *
1544 - * @param mode 'transport' or 'details'
1545 - */
1546 - _startUploadsQueued: function( mode ) {
1547 - var _this = this;
1548 - var uploadsToStart = Math.min( _this.maxSimultaneousUploads - _this._uploadsInProgress.length,
1549 - _this._uploadsQueued.length );
1550 - mw.log( "_startUploadsQueued: should start " + uploadsToStart + " uploads" );
1551 - while ( uploadsToStart-- ) {
1552 - var upload = _this._uploadsQueued.shift();
1553 - _this._uploadsInProgress.push( upload );
1554 - if ( mode == 'transport' ) {
1555 - upload.handler.start();
1556 - } else if ( mode == 'details' ) {
1557 - upload.details.submit();
1558 - }
1559 - }
1560 - if ( _this._uploadsQueued.length ) {
1561 - setTimeout( function () { _this._startUploadsQueued(); }, 1000 );
1562 - }
1563 - },
1564 -
1565 -
1566 - /**
15671595 * Show overall progress for the entire UploadWizard
15681596 * The current design doesn't have individual progress bars, just one giant one.
15691597 * We did some tricky calculations in startUploads to try to weight each individual file's progress against
15701598 * the overall progress.
15711599 */
1572 - showProgress: function() {
 1600+ showProgress: function( fraction, beginTime ) {
15731601 var _this = this;
1574 - if ( _this.isTransported ) {
1575 - return;
1576 - }
15771602
1578 - var fraction = 0;
1579 - for ( var i = 0; i < _this.uploads.length; i++ ) {
1580 - var upload = _this.uploads[i];
1581 - mw.log( "progress of " + upload.ui.fileInputCtrl.value + " = " + upload.progress );
1582 - fraction += upload.progress * ( upload.weight / _this.totalWeight );
 1603+ $j( '#mwe-upwiz-progress-bar' ).progressbar( 'value', parseInt( fraction * 100 ) );
 1604+
 1605+ var remainingTime;
 1606+ if (beginTime == null) {
 1607+ remainingTime = 0;
 1608+ } else {
 1609+ remainingTime = _this.getRemainingTime( beginTime, fraction );
15831610 }
1584 - _this.showProgressBar( fraction );
1585 -
1586 - var remainingTime = _this.getRemainingTime( _this.uploadsBeginTime, fraction );
 1611+
15871612 if ( remainingTime !== null ) {
1588 - _this.showRemainingTime( remainingTime );
 1613+ $j( '#mwe-upwiz-etr' ).html( gM( 'mwe-upwiz-remaining', mw.seconds2npt(parseInt(remainingTime / 1000)) ) );
15891614 }
15901615 },
1591 -
1592 - /**
1593 - * Show the progress bar for the entire Upload Wizard.
1594 - * @param fraction fraction transported (float between 0 and 1)
1595 - */
1596 - showProgressBar: function( fraction ) {
1597 - $j( '#mwe-upwiz-progress-bar' ).progressbar( 'value', parseInt( fraction * 100 ) );
1598 - },
15991616
16001617 /**
1601 - * Show remaining time for all the uploads
1602 - * XXX should be localized - x hours, x minutes, x seconds
1603 - * @param remainingTime estimated time remaining in milliseconds
1604 - */
1605 - showRemainingTime: function( remainingTime ) {
1606 - $j( '#mwe-upwiz-etr' ).html( gM( 'mwe-upwiz-remaining', mw.seconds2npt(parseInt(remainingTime / 1000)) ) );
1607 - },
1608 -
1609 -
1610 - /**
16111618 * Calculate remaining time for all uploads to complete.
16121619 *
16131620 * @param beginTime time in whatever unit getTime returns, presume epoch milliseconds
@@ -1625,64 +1632,21 @@
16261633 },
16271634
16281635 /**
1629 - * Record the progress of an individual upload
1630 - * okay we are in a confusing state here -- are we asking for progress to be stored in the uploadhandler for our perusal or
1631 - * to be explicitly forwarded to us
1632 - * @param upload an Upload object
1633 - * @param progress fraction of progress (float between 0 and 1)
 1636+ * Show the overall count as we upload
16341637 */
1635 - uploadProgress: function( upload, progress ) {
1636 - mw.log("upload progress is " + progress);
1637 - var _this = this;
1638 - upload.progress = progress;
1639 - _this.showProgress();
 1638+ showCount: function( endStateCount, totalCount ) {
 1639+ $j( '#mwe-upwiz-count' ).html( gM( 'mwe-upwiz-upload-count', [ endStateCount, totalCount ] ) );
16401640 },
16411641
1642 - /**
1643 - * To be executed when an individual upload finishes. Processes the result and updates step 2's details
1644 - * @param upload an Upload object
1645 - * @param result the API result in parsed JSON form
1646 - */
1647 - uploadTransported: function( upload, result ) {
1648 - var _this = this;
1649 - _this._uploadsTransported.push( upload );
1650 - mw.UploadWizardUtil.removeItem( _this._uploadsInProgress, upload );
16511642
1652 - if ( result.upload && result.upload.imageinfo && result.upload.imageinfo.descriptionurl ) {
1653 - // success
1654 - mw.log("detailing");
1655 - mw.UploadWizardUtil.removeItem( _this._uploadsQueued, upload );
1656 - _this._uploadsQueued.push( upload );
1657 - _this._uploadsEditingDetails.push( upload );
1658 - mw.log("extract info");
1659 - upload.extractImageInfo( result );
1660 - mw.log("populate");
1661 - upload.details.populate();
1662 -
1663 - } else if ( result.upload && result.upload.sessionkey ) {
1664 - // there was a warning - type error which prevented it from adding the result to the db
1665 - if ( result.upload.warnings.duplicate ) {
1666 - var duplicates = result.upload.warnings.duplicate;
1667 - _this.details.errorDuplicate( result.upload.sessionkey, duplicates );
1668 - }
1669 -
1670 - // XXX namespace collision
1671 - // and other errors that result in a stash
1672 - } else if ( 0 /* actual failure */ ) {
1673 - // we may want to tag or otherwise queue it as an upload to retry
1674 - }
1675 -
1676 - _this.updateFileCounts();
1677 - },
1678 -
1679 -
16801643 /**
16811644 * Occurs whenever we need to update the interface based on how many files are there or have transported
16821645 * Also detects if all uploads have transported and kicks off the process that eventually gets us to Step 2.
16831646 */
16841647 updateFileCounts: function() {
1685 - mw.log( "update counts" );
16861648 var _this = this;
 1649+
 1650+ // Can we enable the "add an upload" button, and what should the text on the button show?
16871651 $j( '#mwe-upwiz-add-file' ).html( gM( 'mwe-upwiz-add-file-' + ( _this.uploads.length === 0 ? '0' : 'n' )) );
16881652 if ( _this.uploads.length < _this.maxUploads ) {
16891653 $j( '#mwe-upwiz-add-file' ).removeAttr( 'disabled' );
@@ -1690,40 +1654,59 @@
16911655 $j( '#mwe-upwiz-add-file' ).attr( 'disabled', true );
16921656 }
16931657
 1658+
 1659+ // Can we enable the "start uploads" button?
16941660 var hasFile;
1695 - for ( var i = 0; i < _this.uploads.length; i++ ) {
1696 - var upload = _this.uploads[i];
1697 - if ( upload.ui.fileInputCtrl.value != "" ) {
 1661+ $j.each( _this.uploads, function (i, upload) {
 1662+ if ( upload.originalFilename ) {
16981663 hasFile = true;
 1664+ return false; // break $j.each
16991665 }
1700 - }
 1666+ } );
 1667+
17011668 if ( hasFile ) {
17021669 $j( '#mwe-upwiz-upload-ctrl' ).removeAttr( 'disabled' );
17031670 } else {
17041671 $j( '#mwe-upwiz-upload-ctrl' ).attr( 'disabled', 'disabled' );
17051672 }
17061673
1707 -
1708 - $j( '#mwe-upwiz-count' ).html( gM( 'mwe-upwiz-upload-count', [ _this._uploadsTransported.length, _this.uploads.length ] ) );
1709 -
 1674+ /*
 1675+ // done
17101676 if ( _this.uploads.length > 0 && _this._uploadsTransported.length == _this.uploads.length ) {
17111677 // is this enough to stop the progress monitor?
17121678 _this.isTransported = true;
17131679 // set progress to 100%
1714 - _this.showProgressBar( 1 );
1715 - _this.showRemainingTime( 0 );
1716 -
1717 - // XXX then should make the progress bar not have the animated lines when done. Solid blue, or fade away or something.
1718 - // likewise, the remaining time should disappear, fadeout maybe.
 1680+ _this.showProgress(1, null);
17191681
1720 - // do some sort of "all done" thing for the UI - advance to next tab maybe.
1721 - _this.moveToTab( 'details' );
17221682 }
 1683+ */
17231684
17241685 },
17251686
17261687
17271688 /**
 1689+ * in details mode, reconfigure all the uploads, for various copyright modes
 1690+ */
 1691+ configureCopyrightDetails: function( mode ) {
 1692+ $j.each( _this._uploadsEditingDetails, function (i, upload) {
 1693+ if (mode == 'ownwork') {
 1694+ // disable inputs
 1695+ // link source to macro input
 1696+ } else if (mode == 'permission') {
 1697+ alert( 'unimplemented' );
 1698+
 1699+ } else if (mode == 'found') {
 1700+ // disable inputs
 1701+ // link source to macro input
 1702+
 1703+ } else {
 1704+ alert( 'unknown mode = ' + mode);
 1705+ }
 1706+ } );
 1707+ },
 1708+
 1709+
 1710+ /**
17281711 *
17291712 */
17301713 pause: function() {
Index: branches/js2-work/phase3/js/mwEmbed/modules/UploadWizard/mw.ApiUploadHandler.js
@@ -10,58 +10,24 @@
1111 * Represents an object which configures a form to upload its files via an iframe talking to the MediaWiki API.
1212 * @param an UploadInterface object, which contains a .form property which points to a real HTML form in the DOM
1313 */
14 -mw.ApiUploadHandler = function( ui ) {
 14+mw.ApiUploadHandler = function( upload ) {
1515 var _this = this;
 16+ _this.upload = upload;
1617
17 - _this.ui = ui;
18 -
19 - var form = _this.ui.form;
20 -
21 - _this.transportedCallbacks = [];
22 - _this.progressCallbacks = [];
23 - _this.errorCallbacks = [];
24 -
2518 _this.configureForm();
2619
2720 // hardcoded for now
2821 // can also use Xhr Binary depending on config
2922 _this.transport = new mw.IframeTransport(
30 - _this.ui.form,
31 - function( fraction ){ _this.progress( fraction ) },
32 - function( result ) { _this.transported( result ) }
 23+ _this.upload.ui.form,
 24+ function( fraction ){ _this.upload.setTransportProgress( fraction ) },
 25+ function( result ) { _this.upload.setTransported( result ) }
3326 );
3427
3528 };
3629
3730 mw.ApiUploadHandler.prototype = {
3831 /**
39 - * Allow other parties to register interest in how we are progressing
40 - * @param callback which accepts a float between 0 and 1 as our current progress
41 - */
42 - addProgressCb: function( fn ) {
43 - var _this = this;
44 - _this.progressCallbacks.push( function( progress ) { fn( progress ) } );
45 - },
46 -
47 - /**
48 - * Allow other parties to register interest in when we finish uploading
49 - * @param callback
50 - */
51 - addTransportedCb: function( f ) {
52 - var _this = this;
53 - _this.transportedCallbacks.push( f );
54 - },
55 -
56 - /**
57 - * Allow other parties to register interest in when we have an error
58 - * @param callback
59 - */
60 - addErrorCb: function( f ) {
61 - var _this = this;
62 - _this.errorCallbacks.push( f );
63 - },
64 -
65 - /**
6632 * Configure an HTML form so that it will submit its files to our transport (an iframe)
6733 * with proper params for the API
6834 * @param callback
@@ -77,7 +43,7 @@
7844
7945 // Set the form action
8046 try {
81 - $j( _this.ui.form )
 47+ $j( _this.upload.ui.form )
8248 .attr( 'action', apiUrl )
8349 .attr( 'method', 'POST' )
8450 .attr( 'enctype', 'multipart/form-data' );
@@ -105,7 +71,7 @@
10672 */
10773 addFormInputIfMissing: function( name, value ) {
10874 var _this = this;
109 - var $jForm = $j( _this.ui.form );
 75+ var $jForm = $j( _this.upload.ui.form );
11076 if ( $jForm.find( "[name='" + name + "']" ).length == 0 ) {
11177 $jForm.append(
11278 $j( '<input />' )
@@ -125,49 +91,9 @@
12692 var _this = this;
12793 mw.log( "api: upload start!" );
12894 _this.beginTime = ( new Date() ).getTime();
129 - _this.ui.start();
130 - _this.ui.busy();
131 - $j( this.ui.form ).submit();
 95+ _this.upload.ui.busy();
 96+ $j( this.upload.ui.form ).submit();
13297 },
133 -
134 - /**
135 - * Central dispatch function for every other object interested in our progress
136 - * @param fraction float between 0 and 1, representing progress
137 - */
138 - progress: function( fraction ) {
139 - mw.log( "api: upload progress!" );
140 - var _this = this;
141 - _this.ui.progress( fraction );
142 - for ( var i = 0; i < _this.progressCallbacks.length; i++ ) {
143 - _this.progressCallbacks[i]( fraction );
144 - }
145 - },
146 -
147 - /**
148 - * Central dispatch function for everyone else interested if we've transported
149 - * @param result javascript object representing MediaWiki API result.
150 - */
151 - transported: function( result ) {
152 - mw.log( "api: upload transported!" );
153 - var _this = this;
154 - _this.ui.transported();
155 - for ( var i = 0; i < _this.transportedCallbacks.length; i++ ) {
156 - _this.transportedCallbacks[i]( result );
157 - }
158 - },
159 -
160 - /**
161 - * Central dispatch function for everyone else interested if we've had an error
162 - * @param error the error
163 - */
164 - error: function( error ) {
165 - mw.log( "api: error!" );
166 - var _this = this;
167 - _this.ui.error( error );
168 - for ( var i = 0; i < _this.errorCallbacks.length; i++ ) {
169 - _this.errorCallbacks[i]( error );
170 - }
171 - }
17298 };
17399
174100
Index: branches/js2-work/phase3/js/mwEmbed/modules/UploadWizard/mw.MockUploadHandler.js
@@ -4,74 +4,34 @@
55 // will have to figure this out.
66
77 // this should be loaded with test suites when appropriate. separate file.
8 -mw.MockUploadHandler = function(ui) {
9 - this.ui = ui;
 8+mw.MockUploadHandler = function(upload) {
 9+ this.upload = upload;
1010 this.nextState = null;
1111 this.progress = 0.0;
12 - this.isCompleted = false;
1312
14 - _this.completedCallbacks = [];
15 - _this.progressCallbacks = [];
16 - _this.warningCallbacks = [];
17 -
18 - // if we ever get a pause control,
19 - // may need to turn this into an array of pairs, start & stops
20 - this.beginTime = null;
2113 };
2214
2315 mw.MockUploadHandler.prototype = {
24 - addProgressCb: function(fn) {
25 - var _this = this;
26 - _this.progressCallbacks.push(function(progress) { fn(_this, progress) });
27 - },
28 -
29 -
30 - addCompletedCb: function(fn) {
31 - var _this = this;
32 - _this.completedCallbacks.push(function() { fn(_this) });
33 - },
34 -
35 - addWarningCb: function(fn) {
36 - var _this = this;
37 - _this.warningCallbacks.push(function() { fn(_this, warning) });
38 - },
39 -
40 -
 16+
4117 start: function () {
4218 var _this = this;
4319 _this.beginTime = (new Date()).getTime();
4420 _this.nextState = _this.cont;
45 - _this.ui.start();
4621 _this.nextState();
47 - },
 22+ },
 23+
4824 cont: function () {
4925 var _this = this;
5026 var delta = 0.0001; // static?
51 - _this.progress += 0.1;
52 - _this.ui.progress(_this.progress);
53 - _this.progressCb(_this, _this.progress);
 27+ _this.progress += ( Math.random() * 0.1 );
 28+ _this.upload.setTransportProgress(_this.progress);
5429 if (1.0 - _this.progress < delta) {
55 - _this.completed();
 30+ _this.upload.setTransported();
5631 } else {
57 - setTimeout( function() { _this.nextState() }, 1000 );
 32+ setTimeout( function() { _this.nextState() }, 200 );
5833 }
5934 },
60 -
61 - completed: function() {
62 - var _this = this;
63 - _this.isCompleted = true;
64 - _this.ui.completed();
65 - _this.completedCb(_this);
66 - },
67 - stop: function () {
68 - // tell the interface that we're stopped
69 - },
70 -
71 - //pause: function () { // },
72 - //resume: function () { // this.nextState = this.stop(); },
73 - remove: function () {
74 - // ??
75 - }
 35+
7636 };
7737
7838

Status & tagging log