r74540 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r74539‎ | r74540 | r74541 >
Date:04:29, 9 October 2010
Author:neilk
Status:deferred
Tags:
Comment:
using new API and JS facilities -- upload wizard that works entirely with stashed files, without renaming kludge
Modified paths:
  • /branches/uploadwizard/extensions/UploadWizard/SpecialUploadWizard.php (modified) (history)
  • /branches/uploadwizard/extensions/UploadWizard/UploadWizard.php (modified) (history)
  • /branches/uploadwizard/extensions/UploadWizard/resources/mw.Api.edit.js (modified) (history)
  • /branches/uploadwizard/extensions/UploadWizard/resources/mw.ApiUploadHandler.js (modified) (history)
  • /branches/uploadwizard/extensions/UploadWizard/resources/mw.DestinationChecker.js (modified) (history)
  • /branches/uploadwizard/extensions/UploadWizard/resources/mw.UploadWizard.js (modified) (history)
  • /branches/uploadwizard/extensions/UploadWizard/resources/mw.UploadWizardUtil.js (modified) (history)

Diff [purge]

Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.UploadWizardUtil.js
@@ -43,7 +43,7 @@
4444
4545 /**
4646 * remove an item from an array. Tests for === identity to remove the item
47 - * XXX the entire rationale for this file may be wrong.
 47+ * XXX the entire rationale for this function may be wrong.
4848 * XXX The jQuery way would be to query the DOM for objects, not to keep a separate array hanging around
4949 * @param items the array where we want to remove an item
5050 * @param item the item to remove
@@ -57,11 +57,12 @@
5858 }
5959 },
6060
 61+/*
6162 /**
6263 * Capitalise first letter and replace spaces by underscores
6364 * @param filename (basename, without directories)
6465 * @return typical title as would appear on MediaWiki
65 - */
 66+ /
6667 pathToTitle: function ( filename ) {
6768 return mw.ucfirst( $j.trim( filename ).replace(/ /g, '_' ) );
6869 },
@@ -70,7 +71,7 @@
7172 * Capitalise first letter and replace underscores by spaces
7273 * @param title typical title as would appear on MediaWiki
7374 * @return plausible local filename
74 - */
 75+ /
7576 titleToPath: function ( title ) {
7677 return mw.ucfirst( $j.trim( title ).replace(/_/g, ' ' ) );
7778 },
@@ -80,7 +81,7 @@
8182 * Transform "File:title_with_spaces.jpg" into "title with spaces"
8283 * @param typical title that would appear on mediawiki, with File: and extension, may include underscores
8384 * @return human readable title
84 - */
 85+ /
8586 fileTitleToHumanTitle: function( title ) {
8687 var extension = mw.UploadWizardUtil.getExtension( title );
8788 if ( typeof extension !== 'undefined' ) {
@@ -95,22 +96,26 @@
9697 return mw.UploadWizardUtil.titleToPath( title );
9798 },
9899
99 -
100 - /**
101 - * Slice extension off a path
102 - * We assume that extensions are 1-4 characters in length
103 - * @param path to file, like "foo/bar/baz.jpg"
104 - * @return extension, like ".jpg" or undefined if it doesn't look lke an extension.
 100+*/
 101+ /**
 102+ * Get the basename of a path.
 103+ * For error conditions, returns the empty string.
 104+ *
 105+ * @param {String} path
 106+ * @return {String} basename
105107 */
106 - getExtension: function( path ) {
107 - var extension = undefined;
108 - var idx = path.lastIndexOf( '.' );
109 - if (idx > 0 && ( idx > ( path.length - 5 ) ) && ( idx < ( path.length - 1 ) ) ) {
110 - extension = path.substr( idx + 1 ).toLowerCase();
 108+ getBasename: function( path ) {
 109+ if ( !mw.isDefined( path ) || path === null ) {
 110+ return '';
111111 }
112 - return extension;
113 - },
 112+
 113+ // find index of last path separator in the path, add 1. (If no separator found, yields 0)
 114+ // then take the entire string after that.
 115+ return path.substr( Math.max( path.lastIndexOf( '/' ), path.lastIndexOf( '\\' ) ) + 1 );
 116+ },
114117
 118+
 119+
115120 /**
116121 * Last resort to guess a proper extension
117122 */
Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.DestinationChecker.js
@@ -23,15 +23,8 @@
2424 _this.selector = options.selector;
2525 _this.spinner = options.spinner;
2626 _this.processResult = options.processResult;
27 -
28 - // optional overrides
 27+ _this.api = options.api;
2928
30 - if (options.apiUrl) {
31 - _this.apiUrl = options.apiUrl;
32 - } else {
33 - _this.apiUrl = mw.UploadWizard.config[ 'apiUrl' ];
34 - }
35 -
3629 $j.each( ['preprocess', 'delay', 'events'], function( i, option ) {
3730 if ( options[option] ) {
3831 _this[option] = options[option];
@@ -101,9 +94,8 @@
10295 * Get the current value of the input, with optional preprocessing
10396 * @return the current input value, with optional processing
10497 */
105 - getName: function() {
106 - var _this = this;
107 - return _this.preprocess( $j( _this.selector ).val() );
 98+ getTitle: function() {
 99+ return this.preprocess( $j( this.selector ).val() );
108100 },
109101
110102 /**
@@ -114,7 +106,8 @@
115107 var _this = this;
116108
117109 var found = false;
118 - var name = _this.getName();
 110+ // XXX if input is empty don't bother? but preprocess gives us File:.png...
 111+ var title = _this.getTitle();
119112
120113 if ( _this.cachedResult[name] !== undefined ) {
121114 _this.processResult( _this.cachedResult[name] );
@@ -126,20 +119,20 @@
127120
128121 // Setup the request -- will return thumbnail data if it finds one
129122 // XXX do not use iiurlwidth as it will create a thumbnail
130 - var request = {
131 - 'titles': 'File:' + name,
 123+ var params = {
 124+ 'titles': title,
132125 'prop': 'imageinfo',
133126 'iiprop': 'url|mime|size',
134127 'iiurlwidth': 150
135128 };
136129
137 - // Do the destination check
138 - mw.getJSON( _this.apiUrl, request, function( data ) {
 130+ // Do the destination check
 131+ _this.api.get( params, function( data ) {
139132 // Remove spinner
140133 _this.spinner( false );
141134
142135 // if the name's changed in the meantime, our result is useless
143 - if ( name != _this.getName() ) {
 136+ if ( title != _this.getTitle() ) {
144137 return;
145138 }
146139
@@ -187,7 +180,7 @@
188181 }
189182
190183 if ( result !== undefined ) {
191 - _this.cachedResult[name] = result;
 184+ _this.cachedResult[title] = result;
192185 _this.processResult( result );
193186 }
194187
Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.Api.edit.js
@@ -3,7 +3,55 @@
44 // dependencies: [ mw.Api, jQuery ]
55
66 ( function( mw, $ ) {
 7+
 8+ // cached token so we don't have to keep fetching new ones for every single post
 9+ var cachedToken = null;
 10+
711 $.extend( mw.Api.prototype, {
 12+
 13+ /* Post to API with edit token. If we have no token, get one and try to post.
 14+ * If we have a cached token try using that, and if it fails, blank out the
 15+ * cached token and start over.
 16+ *
 17+ * @param params API parameters
 18+ * @param ok callback for success
 19+ * @param err (optional) error callback
 20+ */
 21+ postWithEditToken: function( params, ok, err ) {
 22+ var api = this;
 23+ mw.log( 'post with edit token' );
 24+ if ( cachedToken === null ) {
 25+ mw.log( 'no cached token' );
 26+ // We don't have a valid cached token, so get a fresh one and try posting.
 27+ // We do not trap any 'badtoken' or 'notoken' errors, because we don't want
 28+ // an infinite loop. If this fresh token is bad, something else is very wrong.
 29+ var useTokenToPost = function( token ) {
 30+ mw.log( 'posting with token = ' + token );
 31+ params.token = token;
 32+ this.post( params, ok, err );
 33+ };
 34+ mw.log( 'getting edit token' );
 35+ api.getEditToken( useTokenToPost, err );
 36+ } else {
 37+ // We do have a token, but it might be expired. So if it is 'bad' then
 38+ // start over with a new token.
 39+ params.token = cachedToken;
 40+ mw.log( 'we do have a token = ' + params.token );
 41+ var getTokenIfBad = function( code, result ) {
 42+ mw.log( "error with posting with token!" );
 43+ if ( code === 'badtoken' ) {
 44+ mw.log( "bad token; try again" );
 45+ cachedToken = null; // force a new token
 46+ api.postWidthEditToken( params, ok, err );
 47+ } else {
 48+ err( code, result );
 49+ }
 50+ };
 51+ mw.log ( "posting with the token that was cached " );
 52+ api.post( params, ok, getTokenIfBad );
 53+ }
 54+ },
 55+
856 /**
957 * Api helper to grab an edit token
1058 *
@@ -33,7 +81,8 @@
3482 return false;
3583 }
3684 } );
37 - if ( mw.isDefined( token ) ) {
 85+ if ( mw.isDefined( token ) ) {
 86+ cachedToken = token;
3887 tokenCallback( token );
3988 } else {
4089 err( 'token-missing', data );
@@ -44,7 +93,9 @@
4594
4695 this.get( parameters, ajaxOptions );
4796 }
 97+
4898
 99+
49100 } );
50101
51102 }) ( window.mw, jQuery );
Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.UploadWizard.js
@@ -10,27 +10,27 @@
1111 * should fork this into two -- local and remote, e.g. filename
1212 */
1313 mw.UploadWizardUpload = function( api, filesDiv ) {
14 - var _this = this;
15 - _this.api = api;
16 - _this.state = 'new';
17 - _this.transportWeight = 1; // default
18 - _this.detailsWeight = 1; // default
19 - _this._thumbnails = {};
20 - _this.imageinfo = {};
21 - _this.title = undefined;
22 - _this.filename = undefined;
23 - _this.originalFilename = undefined;
24 - _this.mimetype = undefined;
25 - _this.extension = undefined;
 14+ this.api = api;
 15+ this.state = 'new';
 16+ this.thumbnails = {};
 17+ this.imageinfo = {};
 18+ this.title = undefined;
 19+ this.mimetype = undefined;
 20+ this.extension = undefined;
2621
 22+ this.sessionKey = undefined;
2723
 24+ // this should be moved to the interface, if we even keep this
 25+ this.transportWeight = 1; // default
 26+ this.detailsWeight = 1; // default
 27+
2828 // details
29 - _this.ui = new mw.UploadWizardUploadInterface( _this, filesDiv );
 29+ this.ui = new mw.UploadWizardUploadInterface( this, filesDiv );
3030
3131 // handler -- usually ApiUploadHandler
32 - // _this.handler = new ( mw.UploadWizard.config[ 'uploadHandlerClass' ] )( _this );
33 - // _this.handler = new mw.MockUploadHandler( _this );
34 - _this.handler = new mw.ApiUploadHandler( _this, api );
 32+ // this.handler = new ( mw.UploadWizard.config[ 'uploadHandlerClass' ] )( this );
 33+ // this.handler = new mw.MockUploadHandler( this );
 34+ this.handler = new mw.ApiUploadHandler( this, api );
3535 };
3636
3737 mw.UploadWizardUpload.prototype = {
@@ -101,7 +101,7 @@
102102 _this.transportProgress = 1;
103103 $j( _this.ui.div ).trigger( 'transportedEvent' );
104104
105 - if ( result.upload && result.upload.imageinfo && result.upload.imageinfo.descriptionurl ) {
 105+ if ( result.upload && result.upload.imageinfo ) {
106106 // success
107107 _this.extractUploadInfo( result );
108108 _this.deedPreview.setup();
@@ -116,6 +116,7 @@
117117
118118 // and other errors that result in a stash
119119 } else {
 120+ // XXX handle errors better
120121 if ( result.error ) {
121122 alert( "error : " + result.error.code + " : " + result.error.info );
122123 }
@@ -129,33 +130,24 @@
130131
131132
132133 /**
133 - * call when the file is entered into the file input
134 - * get as much data as possible -- maybe exif, even thumbnail maybe
 134+ * Called when the file is entered into the file input
 135+ * Get as much data as possible -- maybe exif, even thumbnail maybe
135136 */
136137 extractLocalFileInfo: function( localFilename ) {
137 - var _this = this;
138 - if (false) { // FileAPI, one day
139 - _this.transportWeight = getFileSize();
 138+ if ( false ) { // FileAPI, one day
 139+ this.transportWeight = getFileSize();
140140 }
141 - _this.extension = mw.UploadWizardUtil.getExtension( localFilename );
142 - // XXX add filename, original filename, extension, whatever else is interesting.
 141+ this.title = new mw.Title( mw.UploadWizardUtil.getBasename( localFilename ), 'file' );
143142 },
144143
145 -
146144 /**
147145 * Accept the result from a successful API upload transport, and fill our own info
148146 *
149147 * @param result The JSON object from a successful API upload result.
150148 */
151149 extractUploadInfo: function( result ) {
152 - var _this = this;
153 -
154 - _this.filename = result.upload.filename;
155 - // XXX global?
156 - _this.title = wgFormattedNamespaces[wgNamespaceIds['file']] + ':' + _this.filename;
157 -
158 - _this.extractImageInfo( result.upload.imageinfo );
159 -
 150+ this.sessionKey = result.upload.sessionkey;
 151+ this.extractImageInfo( result.upload.imageinfo );
160152 },
161153
162154 /**
@@ -180,9 +172,11 @@
181173 _this.imageinfo[key] = imageinfo[key];
182174 }
183175 }
184 -
185 - // we should already have an extension, but if we don't...
186 - if ( _this.extension === undefined ) {
 176+
 177+ // TODO this needs to be rethought.
 178+ // we should already have an extension, but if we don't... ??
 179+ if ( _this.title.getExtension() === null ) {
 180+ /*
187181 var extension = mw.UploadWizardUtil.getExtension( _this.imageinfo.url );
188182 if ( !extension ) {
189183 if ( _this.imageinfo.mimetype ) {
@@ -191,6 +185,7 @@
192186 }
193187 }
194188 }
 189+ */
195190 }
196191 },
197192
@@ -198,36 +193,43 @@
199194 * Fetch a thumbnail for this upload of the desired width.
200195 * It is assumed you don't call this until it's been transported.
201196 *
202 - * The success message from the API should have included enough information to make thumbnails already.
203 - *
204 - * But, if we don't have the thumbnail, try to fetch it by invoking a thumbnail URL pattern.
205 - * We create the thumbnail by passing a special URL which creates the thumbnail on the fly and returns the image contents.
206 - * If the original image URL is http://foo.com/bar/baz/xyz.jpg, and the desired width is 120 pixels,
207 - * the thumbnail URL is http://foo.com/bar/baz/120px-xyz.jpg
208 - * N.B. in general thumbnails have the same mime-type as the original, but NOT ALWAYS. Getting a thumbnail in this way may
209 - * cause conflicts between extension & mime-type.
210 - *
211197 * @param width - desired width of thumbnail (height will scale to match)
212198 * @param callback - callback to execute once thumbnail has been obtained -- must accept Image object
213199 */
214200 getThumbnail: function( width, callback ) {
 201+ var _this = this;
215202 var key = "width" + width;
216 - if ( mw.isDefined( this._thumbnails[key] ) && typeof this._thumbnails[key] === 'Image' ) {
217 - callback( this._thumbnails[key] );
 203+ if ( mw.isDefined( _this.thumbnails[key] ) ) {
 204+ callback( _this.thumbnails[key] );
218205 } else {
219 - var thumbUrl = this.imageinfo.url.replace( /(.*)\/([^\/]+)$/, "$1/" + width + "px-$2" );
220 - this._thumbnails[key] = new Image();
221 - var _this = this;
222 - this._thumbnails[key].onload = function(){
223 - callback( _this._thumbnails[key] );
224 - }
225 - this._thumbnails[key].src = thumbUrl;
 206+ var params = {
 207+ 'prop': 'stashimageinfo',
 208+ 'siisessionkey': _this.sessionKey,
 209+ 'siiurlwidth': width,
 210+ 'siiprop': 'url'
 211+ };
 212+
 213+ this.api.get( params, function( data ) {
 214+ if ( !data || !data.query || !data.query.stashimageinfo ) {
 215+ mw.log(" No data? ");
 216+ // XXX do something about the thumbnail spinner, maybe call the callback with a broken image.
 217+ return;
 218+ }
 219+ var thumbnails = data.query.stashimageinfo;
 220+ for ( var i = 0; i < thumbnails.length; i++ ) {
 221+ _this.thumbnails[key] = {
 222+ src: thumbnails[i].thumburl,
 223+ width: thumbnails[i].thumbwidth,
 224+ height: thumbnails[i].thumbheight
 225+ };
 226+ callback( _this.thumbnails[key] );
 227+ }
 228+ } );
226229 }
227230 },
228231
229 -
230232 /**
231 - * look up thumbnail info and set it in HTML, with loading spinner
 233+ * Look up thumbnail info and set it in HTML, with loading spinner
232234 * it might be interesting to make this more of a publish/subscribe thing, since we have to do this 3x
233235 * the callbacks may pile up, getting unnecessary info
234236 *
@@ -245,7 +247,7 @@
246248 // side effect: will replace thumbnail's loadingSpinner
247249 $j( selector ).html(
248250 $j('<a/>')
249 - .attr( { 'href': _this.imageinfo.descriptionurl,
 251+ .attr( { 'href': _this.imageinfo.url,
250252 'target' : '_new' } )
251253 .append(
252254 $j( '<img/>' )
@@ -309,9 +311,6 @@
310312 */
311313
312314
313 - // XXX this is abit horrible as here we are anticipating what thumbnails we're going to need :(
314 - _this.thumbnailParam = $j('<input type="hidden" name="thumbwidth" value="120,80" />');
315 -
316315 // the css trickery (along with css)
317316 // here creates a giant size file input control which is contained within a div and then
318317 // clipped for overflow. The effect is that we have a div (ctrl-container) we can position anywhere
@@ -416,7 +415,7 @@
417416 var _this = this;
418417 _this.clearErrors();
419418 _this.upload.extractLocalFileInfo( $j( _this.fileInputCtrl ).val() );
420 - if ( _this.isGoodExtension( _this.upload.extension ) ) {
 419+ if ( _this.isGoodExtension( _this.upload.title.getExtension() ) ) {
421420 _this.updateFilename();
422421 } else {
423422 //_this.error( 'bad-filename-extension', ext );
@@ -480,32 +479,23 @@
481480 * 1 ) since the file input has been hidden with some clever CSS ( to avoid x-browser styling issues ),
482481 * update the visible filename
483482 *
484 - * 2 ) update the filename desired when added to MediaWiki. This should be RELATED to the filename on the filesystem,
485 - * but it should be silently fixed so that it does not trigger uniqueness conflicts. i.e. if server has cat.jpg we change ours to cat_2.jpg.
486 - * This is hard to do in a scalable fashion on the client; we don't want to do 12 api calls to get cat_12.jpg.
487 - * Ideally we should ask the SERVER for a decently unique filename related to our own.
488 - * So, at the moment, this is hacked with a guaranteed - unique filename instead.
 483+ * 2 ) update the underlying "title" which we are targeting to add to mediawiki.
 484+ * TODO silently fix to have unique filename? unnecessary at this point...
489485 */
490486 updateFilename: function() {
491487 var _this = this;
492 - var path = $j(_this.fileInputCtrl).attr('value');
 488+ var path = _this.fileInputCtrl.value;
493489
494 -
495 - // visible filename
 490+ // visible filenam.
496491 $j( _this.form ).find( '.mwe-upwiz-visible-file-filename-text' ).html( path );
497492
498 - // desired filename
499 - var filename = _this.convertPathToFilename( path );
500 - _this.upload.originalFilename = filename;
501 - // this is a hack to get a filename guaranteed unique.
502 - uniqueFilename = mw.UploadWizard.config[ 'userName' ] + "_" + ( new Date() ).getTime() + "_" + filename;
503 - $j( _this.filenameCtrl ).attr( 'value', uniqueFilename );
 493+ _this.upload.title = new mw.Title( mw.UploadWizardUtil.getBasename( path ), 'file' );
 494+ $j( _this.filenameCtrl ).val( _this.upload.title.getMain() );
504495
505496 if ( ! _this.isFilled ) {
506497 var $div = $j( _this.div );
507498 _this.isFilled = true;
508499 $div.addClass( 'filled' );
509 -
510500
511501 // cover the div with the file input.
512502 // we use the visible-file div because it has the same offsetParent as the file input
@@ -564,61 +554,12 @@
565555 },
566556
567557 /**
568 - * Get the extension of the path in fileInputCtrl
569 - * @return extension as string
570 - */
571 - getExtension: function() {
572 - var _this = this;
573 - var path = $j(_this.fileInputCtrl).attr('value');
574 - return mw.UploadWizardUtil.getExtension(path);
575 - },
576 -
577 - /**
578 - * XXX this is common utility code
579 - * used when converting contents of a file input and coming up with a suitable "filename" for mediawiki
580 - * test: what if path is length 0
581 - * what if path is all separators
582 - * what if path ends with a separator character
583 - * what if it ends with multiple separator characters
584 - *
585 - * @param path
586 - * @return filename suitable for mediawiki as string
587 - */
588 - convertPathToFilename: function( path ) {
589 - if (path === undefined || path === '') {
590 - return '';
591 - }
592 -
593 - var lastFileSeparatorIdx = Math.max(path.lastIndexOf( '/' ), path.lastIndexOf( '\\' ));
594 - // lastFileSeparatorIdx is now -1 if no separator found, or some index in the string.
595 - // so, +1, that is either 0 ( beginning of string ) or the character after last separator.
596 - // caution! could go past end of string... need to be more careful
597 - var filename = path.substr( lastFileSeparatorIdx + 1 );
598 - return mw.UploadWizardUtil.pathToTitle( filename );
599 -
600 -
601 -
602 - },
603 -
604 - /**
605 - * XXX this is common utility code
606 - * copied because we'll probably need it... stripped from old doDestinationFill
607 - * this is used when checking for "bad" extensions in a filename.
 558+ * This is used when checking for "bad" extensions in a filename.
608559 * @param ext
609560 * @return boolean if extension was acceptable
610561 */
611562 isGoodExtension: function( ext ) {
612 - var _this = this;
613 - var found = false;
614 - var extensions = mw.UploadWizard.config[ 'fileExtensions' ];
615 - if ( extensions ) {
616 - for ( var i = 0; i < extensions.length; i++ ) {
617 - if ( extensions[i].toLowerCase() == ext ) {
618 - found = true;
619 - }
620 - }
621 - }
622 - return found;
 563+ return $j.inArray( ext.toLowerCase(), mw.UploadWizard.config[ 'fileExtensions' ] ) !== -1;
623564 }
624565
625566 };
@@ -761,12 +702,17 @@
762703 .attr( 'title', gM( 'mwe-upwiz-tooltip-title' ) )
763704 .tipsyPlus()
764705 .keyup( function() {
765 - _this.setFilenameFromTitle();
 706+ _this.upload.title.setNameText( _this.titleInput.value );
 707+ // TODO update a display of filename
766708 } )
767709 .growTextArea()
768710 .destinationChecked( {
 711+ api: _this.upload.api,
769712 spinner: function(bool) { _this.toggleDestinationBusy(bool); },
770 - preprocess: function( name ) { return _this.getFilenameFromTitle(); }, // XXX this is no longer a pre-process
 713+ preprocess: function( name ) {
 714+ // turn the contents of the input into a MediaWiki title ("File:foo_bar.jpg") to look up
 715+ return _this.upload.title.setNameText( name ).toString();
 716+ },
771717 processResult: function( result ) { _this.processDestinationCheck( result ); }
772718 } );
773719
@@ -957,28 +903,6 @@
958904 },
959905
960906 /**
961 - * Sets the filename from the title plus this upload's extension.
962 - */
963 - setFilenameFromTitle: function() {
964 - var _this = this;
965 -
966 - _this.filename = wgFormattedNamespaces[wgNamespaceIds['file']] + ':' + _this.getFilenameFromTitle();
967 - $j( '#mwe-upwiz-details-filename' ).text( _this.filename );
968 -
969 - },
970 -
971 - /**
972 - * Gets a filename from the human readable title, using upload's extension.
973 - * @return Filename
974 - */
975 - getFilenameFromTitle: function() {
976 - var _this = this;
977 - var name = $j( _this.titleInput ).val();
978 - return mw.UploadWizardUtil.pathToTitle( name ) + '.' + _this.upload.extension;
979 - },
980 -
981 -
982 - /**
983907 * show file destination field as "busy" while checking
984908 * @param busy boolean true = show busy-ness, false = remove
985909 */
@@ -1012,7 +936,7 @@
1013937 $j( _this.titleInput ).data( 'valid', false );
1014938
1015939 // result is NOT unique
1016 - var title = mw.UploadWizardUtil.fileTitleToHumanTitle( result.title );
 940+ var title = new mw.Title( result.title ).setNamespace( 'file' ).getNameText();
1017941 /* var img = result.img;
1018942 var href = result.href; */
1019943
@@ -1179,7 +1103,6 @@
11801104 _this.prefillSource();
11811105 _this.prefillAuthor();
11821106 _this.prefillTitle();
1183 - _this.prefillFilename();
11841107 _this.prefillLocation();
11851108 },
11861109
@@ -1231,22 +1154,10 @@
12321155 * Note: the interface's notion of "filename" versus "title" is the opposite of MediaWiki
12331156 */
12341157 prefillTitle: function() {
1235 - var _this = this;
1236 - var titleExt = mw.UploadWizardUtil.titleToPath( _this.upload.originalFilename );
1237 - var title = titleExt.replace( /\.\w+$/, '' );
1238 - $j( _this.titleInput ).val( title );
 1158+ $j( this.titleInput ).val( this.upload.title.getNameText() );
12391159 },
12401160
12411161 /**
1242 - * Set the title of the thing we just uploaded, visibly
1243 - * Note: the interface's notion of "filename" versus "title" is the opposite of MediaWiki
1244 - */
1245 - prefillFilename: function() {
1246 - var _this = this;
1247 - _this.setFilenameFromTitle();
1248 - },
1249 -
1250 - /**
12511162 * Prefill location inputs (and/or scroll to position on map) from image info and metadata
12521163 *
12531164 * At least for my test images, the EXIF parser on MediaWiki is not giving back any data for
@@ -1345,19 +1256,9 @@
13461257 $j( _this.licenseInput ).val( copyright );
13471258 }
13481259 }
1349 - // if we still haven't set a copyright use the user's preferences
 1260+ // if we still haven't set a copyright use the user's preferences?
13501261 },
13511262
1352 -
1353 - /**
1354 - *
1355 - showErrors: function() {
1356 - var _this = this;
1357 - $j.each( _this.errors, function() {
1358 -
1359 - } );
1360 - },
1361 - */
13621263
13631264 /**
13641265 * Convert entire details for this file into wikiText, which will then be posted to the file
@@ -1438,18 +1339,6 @@
14391340 },
14401341
14411342 /**
1442 - * Check if we are ready to post wikitext
1443 - deedValid: function() {
1444 - var _this = this;
1445 - return _this.upload.deedChooser.deed.valid();
1446 -
1447 - // somehow, all the various issues discovered with this upload should be present in a single place
1448 - // where we can then check on
1449 - // perhaps as simple as _this.issues or _this.agenda
1450 - },
1451 - */
1452 -
1453 - /**
14541343 * Post wikitext as edited here, to the file
14551344 * XXX This should be split up -- one part should get wikitext from the interface here, and the ajax call
14561345 * should be be part of upload
@@ -1457,29 +1346,16 @@
14581347 submit: function( endCallback ) {
14591348 var _this = this;
14601349
1461 -
1462 - // are we okay to submit?
1463 - // all necessary fields are ready
1464 - // check descriptions
1465 - // the filename is in a sane state
1466 - var desiredFilename = _this.filename;
1467 - shouldRename = ( desiredFilename != _this.upload.title );
1468 -
14691350 // XXX check state of details for okayness ( license selected, at least one desc, sane filename )
14701351 var wikiText = _this.getWikiText();
14711352 mw.log( wikiText );
1472 -
 1353+
14731354 var params = {
1474 - action: 'edit',
1475 - // XXX this is problematic, if the upload wizard is idle for a long time the token expires.
1476 - // should obtain token just before uploading
1477 - title: _this.upload.title,
1478 - // section: 0, ?? causing issues?
 1355+ action: 'upload',
 1356+ sessionkey: _this.upload.sessionKey,
 1357+ filename: _this.upload.title.getMain(),
14791358 text: wikiText,
1480 - summary: "User edited page with " + mw.UploadWizard.userAgent,
1481 - // notminor: 1,
1482 - // basetimestamp: _this.upload.imageinfo.timestamp, ( conflicts? )
1483 - nocreate: 1
 1359+ summary: "User created page with " + mw.UploadWizard.userAgent
14841360 };
14851361
14861362 var finalCallback = function() {
@@ -1487,74 +1363,32 @@
14881364 _this.completeDetailsSubmission();
14891365 };
14901366
1491 - mw.log( "editing!" );
 1367+ mw.log( "uploading!" );
14921368 mw.log( params );
14931369 var callback = function( result ) {
14941370 mw.log( result );
1495 - mw.log( "successful edit" );
1496 - if ( shouldRename ) {
1497 - _this.rename( desiredFilename, finalCallback );
1498 - } else {
1499 - finalCallback();
1500 - }
 1371+ mw.log( "successful upload" );
 1372+ finalCallback();
15011373 };
15021374
15031375 _this.upload.state = 'submitting-details';
1504 - _this.api.post( params, callback );
 1376+ // XXX this can still fail with bad filename, or other 'warnings' -- capture these
 1377+ _this.upload.api.postWithEditToken( params, callback );
15051378 },
15061379
1507 - /**
1508 - * Rename the file
1509 - *
1510 - * THIS MAY NOT WORK ON ALL WIKIS. for instance, on Commons, it may be that only admins can move pages. This is another example of how
1511 - * we need an "incomplete" upload status
1512 - * we are presuming this File page is brand new, so let's not bother with the whole redirection deal. ('noredirect')
1513 - *
1514 - * use _this.ignoreWarningsInput (if it exists) to check if we can blithely move the file or if we have a problem if there
1515 - * is a file by that name already there
1516 - *
1517 - * @param filename to rename this file to
1518 - */
1519 - rename: function( title, endCallback ) {
1520 - var _this = this;
1521 - mw.log("renaming!");
1522 - params = {
1523 - action: 'move',
1524 - from: _this.upload.title,
1525 - to: title,
1526 - reason: "User edited page with " + mw.UploadWizard.userAgent,
1527 - movetalk: '',
1528 - noredirect: '', // presume it's too new
1529 - };
1530 - mw.log(params);
1531 - _this.api.post( params, function( data ) {
1532 - // handle errors later
1533 - // possible error data: { code = 'missingtitle' } -- orig filename not there
1534 - // and many more
1535 -
1536 - // which should match our request.
1537 - // we should update the current upload filename
1538 - // then call the uploadwizard with our progress
15391380
1540 - // success is
1541 - // move = from : ..., reason : ..., redirectcreated : ..., to : ....
1542 - if (data !== undefined && data.move !== undefined && data.move.to !== undefined) {
1543 - _this.upload.title = data.move.to;
1544 - _this.refreshImageInfo( _this.upload, _this.upload.title, endCallback );
1545 - }
1546 - } );
1547 - },
1548 -
15491381 /**
1550 - * Get new image info, for instance, after we renamed an image
 1382+ * Get new image info, for instance, after we renamed... or? published? an image
 1383+ * XXX deprecated?
 1384+ * XXX move to mw.API
15511385 *
15521386 * @param upload an UploadWizardUpload object
15531387 * @param title title to look up remotely
15541388 * @param endCallback execute upon completion
15551389 */
1556 - refreshImageInfo: function( upload, title, endCallback ) {
 1390+ getImageInfo: function( upload, callback ) {
15571391 var params = {
1558 - 'titles': title,
 1392+ 'titles': upload.title.toString(),
15591393 'prop': 'imageinfo',
15601394 'iiprop': 'timestamp|url|user|size|sha1|mime|metadata'
15611395 };
@@ -1573,7 +1407,7 @@
15741408 }
15751409 }
15761410 }
1577 - endCallback();
 1411+ callback();
15781412 } );
15791413 },
15801414
@@ -1820,6 +1654,7 @@
18211655 upload.details.div.css( 'border-bottom', '1px solid #e0e0e0' );
18221656 }
18231657
 1658+ // only necessary if (somehow) they have beaten the check-as-you-type
18241659 upload.details.titleInput.checkUnique();
18251660 } );
18261661
Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.ApiUploadHandler.js
@@ -55,21 +55,23 @@
5656 // from the outset?
5757 }
5858
59 - // XXX TODO - different action, like upload-stash-only or something
6059 _this.addFormInputIfMissing( 'action', 'upload' );
6160
 61+ // force stash
 62+ _this.addFormInputIfMissing( 'stash', 1 );
 63+
6264 // XXX TODO - remove; if we are uploading to stash only, a comment should not be required - yet.
6365 _this.addFormInputIfMissing( 'comment', 'DUMMY TEXT' );
64 -
65 - _this.addFormInputIfMissing( 'stash', 1 );
66 -
 66+
6767 // we use JSON in HTML because according to mdale, some browsers cannot handle just JSON
6868 _this.addFormInputIfMissing( 'format', 'jsonfm' );
6969
7070 // XXX only for testing, so it stops complaining about dupes
 71+ /*
7172 if ( mw.UploadWizard.DEBUG ) {
7273 _this.addFormInputIfMissing( 'ignorewarnings', '1' );
7374 }
 75+ */
7476 },
7577
7678 /**
@@ -96,7 +98,7 @@
9799 addFormInputIfMissing: function( name, value ) {
98100 if ( this.$form.find( "[name='" + name + "']" ).length === 0 ) {
99101 this.$form.append( $j( '<input />' ) .attr( { 'type': "hidden", 'name': name, 'value': value } ));
100 - }
 102+ }
101103 },
102104
103105 /**
Index: branches/uploadwizard/extensions/UploadWizard/UploadWizard.php
@@ -30,14 +30,18 @@
3131
3232
3333
34 -$dir = dirname(__FILE__) . '/';
 34+$dir = dirname(__FILE__);
3535
36 -$wgExtensionMessagesFiles['UploadWizard'] = $dir . 'UploadWizard.i18n.php';
37 -$wgExtensionAliasesFiles['UploadWizard'] = $dir . 'UploadWizard.alias.php';
 36+$wgExtensionMessagesFiles['UploadWizard'] = $dir . '/UploadWizard.i18n.php';
 37+$wgExtensionAliasesFiles['UploadWizard'] = $dir . '/UploadWizard.alias.php';
3838
3939 # Require modules, includeing the special page
40 -$wgAutoloadLocalClasses[ 'SpecialUploadWizard' ] = $dir . 'SpecialUploadWizard.php';
41 -$wgAutoloadLocalClasses[ 'UploadWizardMessages' ] = $dir . 'UploadWizardMessages.php';
 40+foreach ( array( 'SpecialUploadWizard',
 41+ 'UploadWizardMessages',
 42+ 'ApiQueryStashImageInfo' ) as $module ) {
 43+ $wgAutoloadLocalClasses[$module] = $dir . "/" . $module . ".php";
 44+}
 45+$wgAPIPropModules['stashimageinfo'] = 'ApiQueryStashImageInfo';
4246
4347 # Let the special page be a special center of unique specialness
4448 $wgSpecialPages['UploadWizard'] = 'SpecialUploadWizard';
Index: branches/uploadwizard/extensions/UploadWizard/SpecialUploadWizard.php
@@ -101,6 +101,7 @@
102102 "resources/mw.GroupProgressBar.js",
103103
104104 // upload concepts
 105+ "resources/mw.Title.js",
105106 "resources/mw.UploadWizardDeed.js",
106107 "resources/mw.UploadWizardLicenseInput.js",
107108 "resources/mw.UploadWizardUtil.js",

Status & tagging log