Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.UploadWizardUtil.js |
— | — | @@ -43,7 +43,7 @@ |
44 | 44 | |
45 | 45 | /** |
46 | 46 | * 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. |
48 | 48 | * XXX The jQuery way would be to query the DOM for objects, not to keep a separate array hanging around |
49 | 49 | * @param items the array where we want to remove an item |
50 | 50 | * @param item the item to remove |
— | — | @@ -57,11 +57,12 @@ |
58 | 58 | } |
59 | 59 | }, |
60 | 60 | |
| 61 | +/* |
61 | 62 | /** |
62 | 63 | * Capitalise first letter and replace spaces by underscores |
63 | 64 | * @param filename (basename, without directories) |
64 | 65 | * @return typical title as would appear on MediaWiki |
65 | | - */ |
| 66 | + / |
66 | 67 | pathToTitle: function ( filename ) { |
67 | 68 | return mw.ucfirst( $j.trim( filename ).replace(/ /g, '_' ) ); |
68 | 69 | }, |
— | — | @@ -70,7 +71,7 @@ |
71 | 72 | * Capitalise first letter and replace underscores by spaces |
72 | 73 | * @param title typical title as would appear on MediaWiki |
73 | 74 | * @return plausible local filename |
74 | | - */ |
| 75 | + / |
75 | 76 | titleToPath: function ( title ) { |
76 | 77 | return mw.ucfirst( $j.trim( title ).replace(/_/g, ' ' ) ); |
77 | 78 | }, |
— | — | @@ -80,7 +81,7 @@ |
81 | 82 | * Transform "File:title_with_spaces.jpg" into "title with spaces" |
82 | 83 | * @param typical title that would appear on mediawiki, with File: and extension, may include underscores |
83 | 84 | * @return human readable title |
84 | | - */ |
| 85 | + / |
85 | 86 | fileTitleToHumanTitle: function( title ) { |
86 | 87 | var extension = mw.UploadWizardUtil.getExtension( title ); |
87 | 88 | if ( typeof extension !== 'undefined' ) { |
— | — | @@ -95,22 +96,26 @@ |
96 | 97 | return mw.UploadWizardUtil.titleToPath( title ); |
97 | 98 | }, |
98 | 99 | |
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 |
105 | 107 | */ |
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 ''; |
111 | 111 | } |
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 | + }, |
114 | 117 | |
| 118 | + |
| 119 | + |
115 | 120 | /** |
116 | 121 | * Last resort to guess a proper extension |
117 | 122 | */ |
Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.DestinationChecker.js |
— | — | @@ -23,15 +23,8 @@ |
24 | 24 | _this.selector = options.selector; |
25 | 25 | _this.spinner = options.spinner; |
26 | 26 | _this.processResult = options.processResult; |
27 | | - |
28 | | - // optional overrides |
| 27 | + _this.api = options.api; |
29 | 28 | |
30 | | - if (options.apiUrl) { |
31 | | - _this.apiUrl = options.apiUrl; |
32 | | - } else { |
33 | | - _this.apiUrl = mw.UploadWizard.config[ 'apiUrl' ]; |
34 | | - } |
35 | | - |
36 | 29 | $j.each( ['preprocess', 'delay', 'events'], function( i, option ) { |
37 | 30 | if ( options[option] ) { |
38 | 31 | _this[option] = options[option]; |
— | — | @@ -101,9 +94,8 @@ |
102 | 95 | * Get the current value of the input, with optional preprocessing |
103 | 96 | * @return the current input value, with optional processing |
104 | 97 | */ |
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() ); |
108 | 100 | }, |
109 | 101 | |
110 | 102 | /** |
— | — | @@ -114,7 +106,8 @@ |
115 | 107 | var _this = this; |
116 | 108 | |
117 | 109 | 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(); |
119 | 112 | |
120 | 113 | if ( _this.cachedResult[name] !== undefined ) { |
121 | 114 | _this.processResult( _this.cachedResult[name] ); |
— | — | @@ -126,20 +119,20 @@ |
127 | 120 | |
128 | 121 | // Setup the request -- will return thumbnail data if it finds one |
129 | 122 | // XXX do not use iiurlwidth as it will create a thumbnail |
130 | | - var request = { |
131 | | - 'titles': 'File:' + name, |
| 123 | + var params = { |
| 124 | + 'titles': title, |
132 | 125 | 'prop': 'imageinfo', |
133 | 126 | 'iiprop': 'url|mime|size', |
134 | 127 | 'iiurlwidth': 150 |
135 | 128 | }; |
136 | 129 | |
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 ) { |
139 | 132 | // Remove spinner |
140 | 133 | _this.spinner( false ); |
141 | 134 | |
142 | 135 | // if the name's changed in the meantime, our result is useless |
143 | | - if ( name != _this.getName() ) { |
| 136 | + if ( title != _this.getTitle() ) { |
144 | 137 | return; |
145 | 138 | } |
146 | 139 | |
— | — | @@ -187,7 +180,7 @@ |
188 | 181 | } |
189 | 182 | |
190 | 183 | if ( result !== undefined ) { |
191 | | - _this.cachedResult[name] = result; |
| 184 | + _this.cachedResult[title] = result; |
192 | 185 | _this.processResult( result ); |
193 | 186 | } |
194 | 187 | |
Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.Api.edit.js |
— | — | @@ -3,7 +3,55 @@ |
4 | 4 | // dependencies: [ mw.Api, jQuery ] |
5 | 5 | |
6 | 6 | ( 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 | + |
7 | 11 | $.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 | + |
8 | 56 | /** |
9 | 57 | * Api helper to grab an edit token |
10 | 58 | * |
— | — | @@ -33,7 +81,8 @@ |
34 | 82 | return false; |
35 | 83 | } |
36 | 84 | } ); |
37 | | - if ( mw.isDefined( token ) ) { |
| 85 | + if ( mw.isDefined( token ) ) { |
| 86 | + cachedToken = token; |
38 | 87 | tokenCallback( token ); |
39 | 88 | } else { |
40 | 89 | err( 'token-missing', data ); |
— | — | @@ -44,7 +93,9 @@ |
45 | 94 | |
46 | 95 | this.get( parameters, ajaxOptions ); |
47 | 96 | } |
| 97 | + |
48 | 98 | |
| 99 | + |
49 | 100 | } ); |
50 | 101 | |
51 | 102 | }) ( window.mw, jQuery ); |
Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.UploadWizard.js |
— | — | @@ -10,27 +10,27 @@ |
11 | 11 | * should fork this into two -- local and remote, e.g. filename |
12 | 12 | */ |
13 | 13 | 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; |
26 | 21 | |
| 22 | + this.sessionKey = undefined; |
27 | 23 | |
| 24 | + // this should be moved to the interface, if we even keep this |
| 25 | + this.transportWeight = 1; // default |
| 26 | + this.detailsWeight = 1; // default |
| 27 | + |
28 | 28 | // details |
29 | | - _this.ui = new mw.UploadWizardUploadInterface( _this, filesDiv ); |
| 29 | + this.ui = new mw.UploadWizardUploadInterface( this, filesDiv ); |
30 | 30 | |
31 | 31 | // 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 ); |
35 | 35 | }; |
36 | 36 | |
37 | 37 | mw.UploadWizardUpload.prototype = { |
— | — | @@ -101,7 +101,7 @@ |
102 | 102 | _this.transportProgress = 1; |
103 | 103 | $j( _this.ui.div ).trigger( 'transportedEvent' ); |
104 | 104 | |
105 | | - if ( result.upload && result.upload.imageinfo && result.upload.imageinfo.descriptionurl ) { |
| 105 | + if ( result.upload && result.upload.imageinfo ) { |
106 | 106 | // success |
107 | 107 | _this.extractUploadInfo( result ); |
108 | 108 | _this.deedPreview.setup(); |
— | — | @@ -116,6 +116,7 @@ |
117 | 117 | |
118 | 118 | // and other errors that result in a stash |
119 | 119 | } else { |
| 120 | + // XXX handle errors better |
120 | 121 | if ( result.error ) { |
121 | 122 | alert( "error : " + result.error.code + " : " + result.error.info ); |
122 | 123 | } |
— | — | @@ -129,33 +130,24 @@ |
130 | 131 | |
131 | 132 | |
132 | 133 | /** |
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 |
135 | 136 | */ |
136 | 137 | 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(); |
140 | 140 | } |
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' ); |
143 | 142 | }, |
144 | 143 | |
145 | | - |
146 | 144 | /** |
147 | 145 | * Accept the result from a successful API upload transport, and fill our own info |
148 | 146 | * |
149 | 147 | * @param result The JSON object from a successful API upload result. |
150 | 148 | */ |
151 | 149 | 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 ); |
160 | 152 | }, |
161 | 153 | |
162 | 154 | /** |
— | — | @@ -180,9 +172,11 @@ |
181 | 173 | _this.imageinfo[key] = imageinfo[key]; |
182 | 174 | } |
183 | 175 | } |
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 | + /* |
187 | 181 | var extension = mw.UploadWizardUtil.getExtension( _this.imageinfo.url ); |
188 | 182 | if ( !extension ) { |
189 | 183 | if ( _this.imageinfo.mimetype ) { |
— | — | @@ -191,6 +185,7 @@ |
192 | 186 | } |
193 | 187 | } |
194 | 188 | } |
| 189 | + */ |
195 | 190 | } |
196 | 191 | }, |
197 | 192 | |
— | — | @@ -198,36 +193,43 @@ |
199 | 194 | * Fetch a thumbnail for this upload of the desired width. |
200 | 195 | * It is assumed you don't call this until it's been transported. |
201 | 196 | * |
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 | | - * |
211 | 197 | * @param width - desired width of thumbnail (height will scale to match) |
212 | 198 | * @param callback - callback to execute once thumbnail has been obtained -- must accept Image object |
213 | 199 | */ |
214 | 200 | getThumbnail: function( width, callback ) { |
| 201 | + var _this = this; |
215 | 202 | 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] ); |
218 | 205 | } 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 | + } ); |
226 | 229 | } |
227 | 230 | }, |
228 | 231 | |
229 | | - |
230 | 232 | /** |
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 |
232 | 234 | * it might be interesting to make this more of a publish/subscribe thing, since we have to do this 3x |
233 | 235 | * the callbacks may pile up, getting unnecessary info |
234 | 236 | * |
— | — | @@ -245,7 +247,7 @@ |
246 | 248 | // side effect: will replace thumbnail's loadingSpinner |
247 | 249 | $j( selector ).html( |
248 | 250 | $j('<a/>') |
249 | | - .attr( { 'href': _this.imageinfo.descriptionurl, |
| 251 | + .attr( { 'href': _this.imageinfo.url, |
250 | 252 | 'target' : '_new' } ) |
251 | 253 | .append( |
252 | 254 | $j( '<img/>' ) |
— | — | @@ -309,9 +311,6 @@ |
310 | 312 | */ |
311 | 313 | |
312 | 314 | |
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 | | - |
316 | 315 | // the css trickery (along with css) |
317 | 316 | // here creates a giant size file input control which is contained within a div and then |
318 | 317 | // clipped for overflow. The effect is that we have a div (ctrl-container) we can position anywhere |
— | — | @@ -416,7 +415,7 @@ |
417 | 416 | var _this = this; |
418 | 417 | _this.clearErrors(); |
419 | 418 | _this.upload.extractLocalFileInfo( $j( _this.fileInputCtrl ).val() ); |
420 | | - if ( _this.isGoodExtension( _this.upload.extension ) ) { |
| 419 | + if ( _this.isGoodExtension( _this.upload.title.getExtension() ) ) { |
421 | 420 | _this.updateFilename(); |
422 | 421 | } else { |
423 | 422 | //_this.error( 'bad-filename-extension', ext ); |
— | — | @@ -480,32 +479,23 @@ |
481 | 480 | * 1 ) since the file input has been hidden with some clever CSS ( to avoid x-browser styling issues ), |
482 | 481 | * update the visible filename |
483 | 482 | * |
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... |
489 | 485 | */ |
490 | 486 | updateFilename: function() { |
491 | 487 | var _this = this; |
492 | | - var path = $j(_this.fileInputCtrl).attr('value'); |
| 488 | + var path = _this.fileInputCtrl.value; |
493 | 489 | |
494 | | - |
495 | | - // visible filename |
| 490 | + // visible filenam. |
496 | 491 | $j( _this.form ).find( '.mwe-upwiz-visible-file-filename-text' ).html( path ); |
497 | 492 | |
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() ); |
504 | 495 | |
505 | 496 | if ( ! _this.isFilled ) { |
506 | 497 | var $div = $j( _this.div ); |
507 | 498 | _this.isFilled = true; |
508 | 499 | $div.addClass( 'filled' ); |
509 | | - |
510 | 500 | |
511 | 501 | // cover the div with the file input. |
512 | 502 | // we use the visible-file div because it has the same offsetParent as the file input |
— | — | @@ -564,61 +554,12 @@ |
565 | 555 | }, |
566 | 556 | |
567 | 557 | /** |
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. |
608 | 559 | * @param ext |
609 | 560 | * @return boolean if extension was acceptable |
610 | 561 | */ |
611 | 562 | 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; |
623 | 564 | } |
624 | 565 | |
625 | 566 | }; |
— | — | @@ -761,12 +702,17 @@ |
762 | 703 | .attr( 'title', gM( 'mwe-upwiz-tooltip-title' ) ) |
763 | 704 | .tipsyPlus() |
764 | 705 | .keyup( function() { |
765 | | - _this.setFilenameFromTitle(); |
| 706 | + _this.upload.title.setNameText( _this.titleInput.value ); |
| 707 | + // TODO update a display of filename |
766 | 708 | } ) |
767 | 709 | .growTextArea() |
768 | 710 | .destinationChecked( { |
| 711 | + api: _this.upload.api, |
769 | 712 | 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 | + }, |
771 | 717 | processResult: function( result ) { _this.processDestinationCheck( result ); } |
772 | 718 | } ); |
773 | 719 | |
— | — | @@ -957,28 +903,6 @@ |
958 | 904 | }, |
959 | 905 | |
960 | 906 | /** |
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 | | - /** |
983 | 907 | * show file destination field as "busy" while checking |
984 | 908 | * @param busy boolean true = show busy-ness, false = remove |
985 | 909 | */ |
— | — | @@ -1012,7 +936,7 @@ |
1013 | 937 | $j( _this.titleInput ).data( 'valid', false ); |
1014 | 938 | |
1015 | 939 | // result is NOT unique |
1016 | | - var title = mw.UploadWizardUtil.fileTitleToHumanTitle( result.title ); |
| 940 | + var title = new mw.Title( result.title ).setNamespace( 'file' ).getNameText(); |
1017 | 941 | /* var img = result.img; |
1018 | 942 | var href = result.href; */ |
1019 | 943 | |
— | — | @@ -1179,7 +1103,6 @@ |
1180 | 1104 | _this.prefillSource(); |
1181 | 1105 | _this.prefillAuthor(); |
1182 | 1106 | _this.prefillTitle(); |
1183 | | - _this.prefillFilename(); |
1184 | 1107 | _this.prefillLocation(); |
1185 | 1108 | }, |
1186 | 1109 | |
— | — | @@ -1231,22 +1154,10 @@ |
1232 | 1155 | * Note: the interface's notion of "filename" versus "title" is the opposite of MediaWiki |
1233 | 1156 | */ |
1234 | 1157 | 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() ); |
1239 | 1159 | }, |
1240 | 1160 | |
1241 | 1161 | /** |
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 | | - /** |
1251 | 1162 | * Prefill location inputs (and/or scroll to position on map) from image info and metadata |
1252 | 1163 | * |
1253 | 1164 | * At least for my test images, the EXIF parser on MediaWiki is not giving back any data for |
— | — | @@ -1345,19 +1256,9 @@ |
1346 | 1257 | $j( _this.licenseInput ).val( copyright ); |
1347 | 1258 | } |
1348 | 1259 | } |
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? |
1350 | 1261 | }, |
1351 | 1262 | |
1352 | | - |
1353 | | - /** |
1354 | | - * |
1355 | | - showErrors: function() { |
1356 | | - var _this = this; |
1357 | | - $j.each( _this.errors, function() { |
1358 | | - |
1359 | | - } ); |
1360 | | - }, |
1361 | | - */ |
1362 | 1263 | |
1363 | 1264 | /** |
1364 | 1265 | * Convert entire details for this file into wikiText, which will then be posted to the file |
— | — | @@ -1438,18 +1339,6 @@ |
1439 | 1340 | }, |
1440 | 1341 | |
1441 | 1342 | /** |
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 | | - /** |
1454 | 1343 | * Post wikitext as edited here, to the file |
1455 | 1344 | * XXX This should be split up -- one part should get wikitext from the interface here, and the ajax call |
1456 | 1345 | * should be be part of upload |
— | — | @@ -1457,29 +1346,16 @@ |
1458 | 1347 | submit: function( endCallback ) { |
1459 | 1348 | var _this = this; |
1460 | 1349 | |
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 | | - |
1469 | 1350 | // XXX check state of details for okayness ( license selected, at least one desc, sane filename ) |
1470 | 1351 | var wikiText = _this.getWikiText(); |
1471 | 1352 | mw.log( wikiText ); |
1472 | | - |
| 1353 | + |
1473 | 1354 | 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(), |
1479 | 1358 | 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 |
1484 | 1360 | }; |
1485 | 1361 | |
1486 | 1362 | var finalCallback = function() { |
— | — | @@ -1487,74 +1363,32 @@ |
1488 | 1364 | _this.completeDetailsSubmission(); |
1489 | 1365 | }; |
1490 | 1366 | |
1491 | | - mw.log( "editing!" ); |
| 1367 | + mw.log( "uploading!" ); |
1492 | 1368 | mw.log( params ); |
1493 | 1369 | var callback = function( result ) { |
1494 | 1370 | 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(); |
1501 | 1373 | }; |
1502 | 1374 | |
1503 | 1375 | _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 ); |
1505 | 1378 | }, |
1506 | 1379 | |
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 |
1539 | 1380 | |
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 | | - |
1549 | 1381 | /** |
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 |
1551 | 1385 | * |
1552 | 1386 | * @param upload an UploadWizardUpload object |
1553 | 1387 | * @param title title to look up remotely |
1554 | 1388 | * @param endCallback execute upon completion |
1555 | 1389 | */ |
1556 | | - refreshImageInfo: function( upload, title, endCallback ) { |
| 1390 | + getImageInfo: function( upload, callback ) { |
1557 | 1391 | var params = { |
1558 | | - 'titles': title, |
| 1392 | + 'titles': upload.title.toString(), |
1559 | 1393 | 'prop': 'imageinfo', |
1560 | 1394 | 'iiprop': 'timestamp|url|user|size|sha1|mime|metadata' |
1561 | 1395 | }; |
— | — | @@ -1573,7 +1407,7 @@ |
1574 | 1408 | } |
1575 | 1409 | } |
1576 | 1410 | } |
1577 | | - endCallback(); |
| 1411 | + callback(); |
1578 | 1412 | } ); |
1579 | 1413 | }, |
1580 | 1414 | |
— | — | @@ -1820,6 +1654,7 @@ |
1821 | 1655 | upload.details.div.css( 'border-bottom', '1px solid #e0e0e0' ); |
1822 | 1656 | } |
1823 | 1657 | |
| 1658 | + // only necessary if (somehow) they have beaten the check-as-you-type |
1824 | 1659 | upload.details.titleInput.checkUnique(); |
1825 | 1660 | } ); |
1826 | 1661 | |
Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.ApiUploadHandler.js |
— | — | @@ -55,21 +55,23 @@ |
56 | 56 | // from the outset? |
57 | 57 | } |
58 | 58 | |
59 | | - // XXX TODO - different action, like upload-stash-only or something |
60 | 59 | _this.addFormInputIfMissing( 'action', 'upload' ); |
61 | 60 | |
| 61 | + // force stash |
| 62 | + _this.addFormInputIfMissing( 'stash', 1 ); |
| 63 | + |
62 | 64 | // XXX TODO - remove; if we are uploading to stash only, a comment should not be required - yet. |
63 | 65 | _this.addFormInputIfMissing( 'comment', 'DUMMY TEXT' ); |
64 | | - |
65 | | - _this.addFormInputIfMissing( 'stash', 1 ); |
66 | | - |
| 66 | + |
67 | 67 | // we use JSON in HTML because according to mdale, some browsers cannot handle just JSON |
68 | 68 | _this.addFormInputIfMissing( 'format', 'jsonfm' ); |
69 | 69 | |
70 | 70 | // XXX only for testing, so it stops complaining about dupes |
| 71 | + /* |
71 | 72 | if ( mw.UploadWizard.DEBUG ) { |
72 | 73 | _this.addFormInputIfMissing( 'ignorewarnings', '1' ); |
73 | 74 | } |
| 75 | + */ |
74 | 76 | }, |
75 | 77 | |
76 | 78 | /** |
— | — | @@ -96,7 +98,7 @@ |
97 | 99 | addFormInputIfMissing: function( name, value ) { |
98 | 100 | if ( this.$form.find( "[name='" + name + "']" ).length === 0 ) { |
99 | 101 | this.$form.append( $j( '<input />' ) .attr( { 'type': "hidden", 'name': name, 'value': value } )); |
100 | | - } |
| 102 | + } |
101 | 103 | }, |
102 | 104 | |
103 | 105 | /** |
Index: branches/uploadwizard/extensions/UploadWizard/UploadWizard.php |
— | — | @@ -30,14 +30,18 @@ |
31 | 31 | |
32 | 32 | |
33 | 33 | |
34 | | -$dir = dirname(__FILE__) . '/'; |
| 34 | +$dir = dirname(__FILE__); |
35 | 35 | |
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'; |
38 | 38 | |
39 | 39 | # 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'; |
42 | 46 | |
43 | 47 | # Let the special page be a special center of unique specialness |
44 | 48 | $wgSpecialPages['UploadWizard'] = 'SpecialUploadWizard'; |
Index: branches/uploadwizard/extensions/UploadWizard/SpecialUploadWizard.php |
— | — | @@ -101,6 +101,7 @@ |
102 | 102 | "resources/mw.GroupProgressBar.js", |
103 | 103 | |
104 | 104 | // upload concepts |
| 105 | + "resources/mw.Title.js", |
105 | 106 | "resources/mw.UploadWizardDeed.js", |
106 | 107 | "resources/mw.UploadWizardLicenseInput.js", |
107 | 108 | "resources/mw.UploadWizardUtil.js", |