Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.UploadWizardDeed.js |
— | — | @@ -0,0 +1,460 @@ |
| 2 | +/** |
| 3 | + * Sort of an abstract class for deeds |
| 4 | + */ |
| 5 | +mw.UploadWizardDeed = function() { |
| 6 | + var _this = this; |
| 7 | + // prevent from instantiating directly? |
| 8 | + return false; |
| 9 | +}; |
| 10 | + |
| 11 | +mw.UploadWizardDeed.prototype = { |
| 12 | + valid: function() { |
| 13 | + return false; |
| 14 | + }, |
| 15 | + |
| 16 | + setFormFields: function() { }, |
| 17 | + |
| 18 | + getSourceWikiText: function() { |
| 19 | + return $j( this.sourceInput ).val(); |
| 20 | + }, |
| 21 | + |
| 22 | + getAuthorWikiText: function() { |
| 23 | + return $j( this.authorInput ).val(); |
| 24 | + }, |
| 25 | + |
| 26 | + /** |
| 27 | + * Get wikitext representing the licenses selected in the license object |
| 28 | + * @return wikitext of all applicable license templates. |
| 29 | + */ |
| 30 | + getLicenseWikiText: function() { |
| 31 | + var _this = this; |
| 32 | + var wikiText = ''; |
| 33 | + $j.each ( _this.licenseInput.getTemplates(), function( i, template ) { |
| 34 | + wikiText += "{{" + template + "}}\n"; |
| 35 | + } ); |
| 36 | + |
| 37 | + return wikiText; |
| 38 | + } |
| 39 | + |
| 40 | +}; |
| 41 | + |
| 42 | + |
| 43 | +mw.UploadWizardNullDeed = $j.extend( new mw.UploadWizardDeed(), { |
| 44 | + valid: function() { |
| 45 | + return false; |
| 46 | + } |
| 47 | +} ); |
| 48 | + |
| 49 | + |
| 50 | +/** |
| 51 | + * Set up the form and deed object for the deed option that says these uploads are all the user's own work. |
| 52 | + * XXX these deeds are starting to turn into jquery fns |
| 53 | + */ |
| 54 | +mw.UploadWizardDeedOwnWork = function( uploadCount ) { |
| 55 | + uploadCount = uploadCount ? uploadCount : 1; |
| 56 | + |
| 57 | + var _this = new mw.UploadWizardDeed(); |
| 58 | + |
| 59 | + _this.authorInput = $j( '<input />') |
| 60 | + .attr( { name: "author", type: "text" } ) |
| 61 | + .addClass( 'mwe-upwiz-sign' ); |
| 62 | + |
| 63 | + var licenseInputDiv = $j( '<div class="mwe-upwiz-deed-license"></div>' ); |
| 64 | + _this.licenseInput = new mw.UploadWizardLicenseInput( licenseInputDiv ); |
| 65 | + _this.licenseInput.setDefaultValues(); |
| 66 | + |
| 67 | + return $j.extend( _this, { |
| 68 | + |
| 69 | + name: 'ownwork', |
| 70 | + |
| 71 | + /** |
| 72 | + * Is this correctly set, with side effects of causing errors to show in interface. |
| 73 | + * @return boolean true if valid, false if not |
| 74 | + */ |
| 75 | + valid: function() { |
| 76 | + // n.b. valid() has side effects and both should be called every time the function is called. |
| 77 | + // do not short-circuit. |
| 78 | + var formValid = _this.$form.valid(); |
| 79 | + var licenseInputValid = _this.licenseInput.valid(); |
| 80 | + return formValid && licenseInputValid; |
| 81 | + }, |
| 82 | + |
| 83 | + getSourceWikiText: function() { |
| 84 | + return '{{own}}'; |
| 85 | + }, |
| 86 | + |
| 87 | + // XXX do we need to escape authorInput, or is wikitext a feature here? |
| 88 | + // what about scripts? |
| 89 | + getAuthorWikiText: function() { |
| 90 | + return "[[User:" + mw.UploadWizard.config[ 'userName' ] + '|' + $j( _this.authorInput ).val() + ']]'; |
| 91 | + }, |
| 92 | + |
| 93 | + |
| 94 | + getLicenseWikiText: function() { |
| 95 | + var wikiText = '{{self'; |
| 96 | + $j.each( _this.licenseInput.getTemplates(), function( i, template ) { |
| 97 | + wikiText += '|' + template; |
| 98 | + } ); |
| 99 | + wikiText += '}}'; |
| 100 | + return wikiText; |
| 101 | + }, |
| 102 | + |
| 103 | + setFormFields: function( $selector ) { |
| 104 | + _this.$selector = $selector; |
| 105 | + |
| 106 | + _this.$form = $j( '<form/>' ); |
| 107 | + |
| 108 | + var $standardDiv = $j( '<div />' ).append( |
| 109 | + $j( '<label for="author2" generated="true" class="mwe-validator-error" style="display:block;"/>' ), |
| 110 | + $j( '<p>' ) |
| 111 | + .html( gM( 'mwe-upwiz-source-ownwork-assert', |
| 112 | + uploadCount, |
| 113 | + '<span class="mwe-standard-author-input"></span>' ) |
| 114 | + ), |
| 115 | + $j( '<p class="mwe-small-print" />' ).append( gM( 'mwe-upwiz-source-ownwork-assert-note' ) ) |
| 116 | + ); |
| 117 | + $standardDiv.find( '.mwe-standard-author-input' ).append( $j( '<input name="author2" type="text" class="mwe-upwiz-sign" />' ) ); |
| 118 | + |
| 119 | + var $customDiv = $j('<div/>').append( |
| 120 | + $j( '<label for="author" generated="true" class="mwe-validator-error" style="display:block;"/>' ), |
| 121 | + $j( '<p>' ) |
| 122 | + .html( gM( 'mwe-upwiz-source-ownwork-assert-custom', |
| 123 | + uploadCount, |
| 124 | + '<span class="mwe-custom-author-input"></span>' ) ), |
| 125 | + licenseInputDiv |
| 126 | + ); |
| 127 | + // have to add the author input this way -- gM() will flatten it to a string and we'll lose it as a dom object |
| 128 | + $customDiv.find( '.mwe-custom-author-input' ).append( _this.authorInput ); |
| 129 | + |
| 130 | + |
| 131 | + var $crossfader = $j( '<div>' ).append( $standardDiv, $customDiv ); |
| 132 | + var $toggler = $j( '<p class="mwe-more-options" style="text-align: right" />' ) |
| 133 | + .append( $j( '<a />' ) |
| 134 | + .append( gM( 'mwe-upwiz-license-show-all' ) ) |
| 135 | + .click( function() { |
| 136 | + _this.formValidator.resetForm(); |
| 137 | + if ( $crossfader.data( 'crossfadeDisplay' ) === $customDiv ) { |
| 138 | + _this.licenseInput.setDefaultValues(); |
| 139 | + $crossfader.morphCrossfade( $standardDiv ); |
| 140 | + $j( this ).html( gM( 'mwe-upwiz-license-show-all' ) ); |
| 141 | + } else { |
| 142 | + $crossfader.morphCrossfade( $customDiv ); |
| 143 | + $j( this ).html( gM( 'mwe-upwiz-license-show-recommended' ) ); |
| 144 | + } |
| 145 | + } ) ); |
| 146 | + |
| 147 | + var $formFields = $j( '<div class="mwe-upwiz-deed-form-internal" />' ) |
| 148 | + .append( $crossfader, $toggler ); |
| 149 | + |
| 150 | + |
| 151 | + // synchronize both username signatures |
| 152 | + // set initial value to configured username |
| 153 | + // if one changes all the others change (keyup event) |
| 154 | + // |
| 155 | + // also set tooltips ( the title, tipsy() ) |
| 156 | + $formFields.find( '.mwe-upwiz-sign' ) |
| 157 | + .attr( { |
| 158 | + title: gM( 'mwe-upwiz-tooltip-sign' ), |
| 159 | + value: mw.UploadWizard.config[ 'userName' ] |
| 160 | + } ) |
| 161 | + .tipsyPlus() |
| 162 | + .keyup( function() { |
| 163 | + var thisInput = this; |
| 164 | + var thisVal = $j( thisInput ).val(); |
| 165 | + $j.each( $formFields.find( '.mwe-upwiz-sign' ), function( i, input ) { |
| 166 | + if (thisInput !== input) { |
| 167 | + $j( input ).val( thisVal ); |
| 168 | + } |
| 169 | + } ); |
| 170 | + } ); |
| 171 | + |
| 172 | + _this.$form.append( $formFields ); |
| 173 | + $selector.append( _this.$form ); |
| 174 | + |
| 175 | + // done after added to the DOM, so there are true heights |
| 176 | + $crossfader.morphCrossfader(); |
| 177 | + |
| 178 | + |
| 179 | + // and finally, make it validatable |
| 180 | + _this.formValidator = _this.$form.validate( { |
| 181 | + rules: { |
| 182 | + author2: { |
| 183 | + required: function( element ) { |
| 184 | + return $crossfader.data( 'crossfadeDisplay' ).get(0) === $standardDiv.get(0); |
| 185 | + }, |
| 186 | + minlength: mw.UploadWizard.config[ 'minAuthorLength' ], |
| 187 | + maxlength: mw.UploadWizard.config[ 'maxAuthorLength' ] |
| 188 | + }, |
| 189 | + author: { |
| 190 | + required: function( element ) { |
| 191 | + return $crossfader.data( 'crossfadeDisplay' ).get(0) === $customDiv.get(0); |
| 192 | + }, |
| 193 | + minlength: mw.UploadWizard.config[ 'minAuthorLength' ], |
| 194 | + maxlength: mw.UploadWizard.config[ 'maxAuthorLength' ] |
| 195 | + } |
| 196 | + }, |
| 197 | + messages: { |
| 198 | + author2: { |
| 199 | + required: gM( 'mwe-upwiz-error-signature-blank' ), |
| 200 | + minlength: gM( 'mwe-upwiz-error-signature-too-short', mw.UploadWizard.config[ 'minAuthorLength' ] ), |
| 201 | + maxlength: gM( 'mwe-upwiz-error-signature-too-long', mw.UploadWizard.config[ 'maxAuthorLength' ] ) |
| 202 | + }, |
| 203 | + author: { |
| 204 | + required: gM( 'mwe-upwiz-error-signature-blank' ), |
| 205 | + minlength: gM( 'mwe-upwiz-error-signature-too-short', mw.UploadWizard.config[ 'minAuthorLength' ] ), |
| 206 | + maxlength: gM( 'mwe-upwiz-error-signature-too-long', mw.UploadWizard.config[ 'maxAuthorLength' ] ) |
| 207 | + } |
| 208 | + } |
| 209 | + } ); |
| 210 | + } |
| 211 | + |
| 212 | + |
| 213 | + } ); |
| 214 | + |
| 215 | +}; |
| 216 | + |
| 217 | +// XXX these deeds are starting to turn into jquery fns |
| 218 | +mw.UploadWizardDeedThirdParty = function( uploadCount ) { |
| 219 | + var _this = new mw.UploadWizardDeed(); |
| 220 | + |
| 221 | + _this.uploadCount = uploadCount ? uploadCount : 1; |
| 222 | + _this.sourceInput = $j('<textarea class="mwe-source mwe-long-textarea" name="source" rows="1" cols="40"></textarea>' ) |
| 223 | + .growTextArea() |
| 224 | + .attr( 'title', gM( 'mwe-upwiz-tooltip-source' ) ) |
| 225 | + .tipsyPlus(); |
| 226 | + _this.authorInput = $j('<textarea class="mwe-author mwe-long-textarea" name="author" rows="1" cols="40"></textarea>' ) |
| 227 | + .growTextArea() |
| 228 | + .attr( 'title', gM( 'mwe-upwiz-tooltip-author' ) ) |
| 229 | + .tipsyPlus(); |
| 230 | + licenseInputDiv = $j( '<div class="mwe-upwiz-deed-license"></div>' ); |
| 231 | + _this.licenseInput = new mw.UploadWizardLicenseInput( licenseInputDiv ); |
| 232 | + |
| 233 | + |
| 234 | + return $j.extend( _this, mw.UploadWizardDeed.prototype, { |
| 235 | + name: 'thirdparty', |
| 236 | + |
| 237 | + setFormFields: function( $selector ) { |
| 238 | + var _this = this; |
| 239 | + _this.$form = $j( '<form/>' ); |
| 240 | + |
| 241 | + var $formFields = $j( '<div class="mwe-upwiz-deed-form-internal"/>' ); |
| 242 | + |
| 243 | + if ( uploadCount > 1 ) { |
| 244 | + $formFields.append( $j( '<div />' ).append( gM( 'mwe-upwiz-source-thirdparty-custom-multiple-intro' ) ) ); |
| 245 | + } |
| 246 | + |
| 247 | + $formFields.append ( |
| 248 | + $j( '<div class="mwe-upwiz-source-thirdparty-custom-multiple-intro" />' ), |
| 249 | + $j( '<label for="source" generated="true" class="mwe-validator-error" style="display:block;"/>' ), |
| 250 | + $j( '<div class="mwe-upwiz-thirdparty-fields" />' ) |
| 251 | + .append( $j( '<label for="source"/>' ).text( gM( 'mwe-upwiz-source' ) ), |
| 252 | + _this.sourceInput ), |
| 253 | + $j( '<label for="author" generated="true" class="mwe-validator-error" style="display:block;"/>' ), |
| 254 | + $j( '<div class="mwe-upwiz-thirdparty-fields" />' ) |
| 255 | + .append( $j( '<label for="author"/>' ).text( gM( 'mwe-upwiz-author' ) ), |
| 256 | + _this.authorInput ), |
| 257 | + $j( '<div class="mwe-upwiz-thirdparty-license" />' ) |
| 258 | + .append( gM( 'mwe-upwiz-source-thirdparty-license', uploadCount ) ), |
| 259 | + licenseInputDiv |
| 260 | + ); |
| 261 | + |
| 262 | + _this.$form.validate( { |
| 263 | + rules: { |
| 264 | + source: { required: true, |
| 265 | + minlength: mw.UploadWizard.config[ 'minSourceLength' ], |
| 266 | + maxlength: mw.UploadWizard.config[ 'maxSourceLength' ] }, |
| 267 | + author: { required: true, |
| 268 | + minlength: mw.UploadWizard.config[ 'minAuthorLength' ], |
| 269 | + maxlength: mw.UploadWizard.config[ 'maxAuthorLength' ] } |
| 270 | + }, |
| 271 | + messages: { |
| 272 | + source: { |
| 273 | + required: gM( 'mwe-upwiz-error-blank' ), |
| 274 | + minlength: gM( 'mwe-upwiz-error-too-short', mw.UploadWizard.config[ 'minSourceLength' ] ), |
| 275 | + maxlength: gM( 'mwe-upwiz-error-too-long', mw.UploadWizard.config[ 'maxSourceLength' ] ) |
| 276 | + }, |
| 277 | + author: { |
| 278 | + required: gM( 'mwe-upwiz-error-blank' ), |
| 279 | + minlength: gM( 'mwe-upwiz-error-too-short', mw.UploadWizard.config[ 'minAuthorLength' ] ), |
| 280 | + maxlength: gM( 'mwe-upwiz-error-too-long', mw.UploadWizard.config[ 'maxAuthorLength' ] ) |
| 281 | + } |
| 282 | + } |
| 283 | + } ); |
| 284 | + |
| 285 | + _this.$form.append( $formFields ); |
| 286 | + |
| 287 | + $selector.append( _this.$form ); |
| 288 | + }, |
| 289 | + |
| 290 | + /** |
| 291 | + * Is this correctly set, with side effects of causing errors to show in interface. |
| 292 | + * this is exactly the same as the ownwork valid() function... hopefully we can reduce these to nothing if we make |
| 293 | + * all validators work the same. |
| 294 | + * @return boolean true if valid, false if not |
| 295 | + */ |
| 296 | + valid: function() { |
| 297 | + // n.b. valid() has side effects and both should be called every time the function is called. |
| 298 | + // do not short-circuit. |
| 299 | + var formValid = _this.$form.valid(); |
| 300 | + var licenseInputValid = _this.licenseInput.valid(); |
| 301 | + return formValid && licenseInputValid; |
| 302 | + } |
| 303 | + } ); |
| 304 | +}; |
| 305 | + |
| 306 | + |
| 307 | + |
| 308 | + |
| 309 | +/** |
| 310 | + * @param selector where to put this deed chooser |
| 311 | + * @param isPlural whether this chooser applies to multiple files (changes messaging mostly) |
| 312 | + */ |
| 313 | +mw.UploadWizardDeedChooser = function( selector, deeds, uploadCount ) { |
| 314 | + var _this = this; |
| 315 | + _this.$selector = $j( selector ); |
| 316 | + _this.uploadCount = uploadCount ? uploadCount : 1; |
| 317 | + |
| 318 | + |
| 319 | + _this.$errorEl = $j( '<div class="mwe-error"></div>' ); |
| 320 | + _this.$selector.append( _this.$errorEl ); |
| 321 | + |
| 322 | + // name for radio button set |
| 323 | + mw.UploadWizardDeedChooser.prototype.widgetCount++; |
| 324 | + _this.name = 'deedChooser' + mw.UploadWizardDeedChooser.prototype.widgetCount.toString(); |
| 325 | + |
| 326 | + $j.each( deeds, function (i, deed) { |
| 327 | + var id = _this.name + '-' + deed.name; |
| 328 | + |
| 329 | + var $deedInterface = $j( |
| 330 | + '<div class="mwe-upwiz-deed mwe-upwiz-deed-' + deed.name + '">' |
| 331 | + + '<div class="mwe-upwiz-deed-option-title">' |
| 332 | + + '<span class="mwe-upwiz-deed-header">' |
| 333 | + + '<input id="' + id +'" name="' + _this.name + '" type="radio" value="' + deed.name + '">' |
| 334 | + + '<label for="' + id + '" class="mwe-upwiz-deed-name">' |
| 335 | + + gM( 'mwe-upwiz-source-' + deed.name, _this.uploadCount ) |
| 336 | + + '</label>' |
| 337 | + + '</input>' |
| 338 | + + '</span>' |
| 339 | + + '</div>' |
| 340 | + + '<div class="mwe-upwiz-deed-form">' |
| 341 | + + '</div>' |
| 342 | + ); |
| 343 | + |
| 344 | + var $deedSelector = _this.$selector.append( $deedInterface ); |
| 345 | + |
| 346 | + deed.setFormFields( $deedInterface.find( '.mwe-upwiz-deed-form' ) ); |
| 347 | + |
| 348 | + $deedInterface.find( 'span.mwe-upwiz-deed-header input' ).click( function() { |
| 349 | + if ( $j( this ).is(':checked' ) ) { |
| 350 | + _this.choose( deed ); |
| 351 | + _this.showDeed( $deedInterface ); |
| 352 | + } |
| 353 | + } ); |
| 354 | + |
| 355 | + } ); |
| 356 | + |
| 357 | + _this.choose( mw.UploadWizardNullDeed ); |
| 358 | + _this.showDeedChoice(); |
| 359 | + |
| 360 | + |
| 361 | +}; |
| 362 | + |
| 363 | + |
| 364 | +mw.UploadWizardDeedChooser.prototype = { |
| 365 | + |
| 366 | + /** |
| 367 | + * How many deed choosers there are (important for creating unique ids, element names) |
| 368 | + */ |
| 369 | + widgetCount: 0, |
| 370 | + |
| 371 | + /** |
| 372 | + * Check if this form is filled out correctly, with side effects of showing error messages if invalid |
| 373 | + * @return boolean; true if valid, false if not |
| 374 | + */ |
| 375 | + valid: function() { |
| 376 | + var _this = this; |
| 377 | + // we assume there is always a deed available, even if it's just the null deed. |
| 378 | + var valid = _this.deed.valid(); |
| 379 | + // the only time we need to set an error message is if the null deed is selected. |
| 380 | + // otherwise, we can assume that the widgets have already added error messages. |
| 381 | + if (valid) { |
| 382 | + _this.hideError(); |
| 383 | + } else { |
| 384 | + if ( _this.deed === mw.UploadWizardNullDeed ) { |
| 385 | + _this.showError( gM( 'mwe-upwiz-deeds-need-deed', _this.uploadCount ) ); |
| 386 | + $j( _this ).bind( 'chooseDeed', function() { |
| 387 | + _this.hideError(); |
| 388 | + } ); |
| 389 | + } |
| 390 | + } |
| 391 | + return valid; |
| 392 | + }, |
| 393 | + |
| 394 | + showError: function( error ) { |
| 395 | + this.$errorEl.html( error ); |
| 396 | + this.$errorEl.fadeIn(); |
| 397 | + }, |
| 398 | + |
| 399 | + hideError: function() { |
| 400 | + this.$errorEl.fadeOut(); |
| 401 | + this.$errorEl.empty(); |
| 402 | + }, |
| 403 | + |
| 404 | + /** |
| 405 | + * How many uploads this deed controls |
| 406 | + */ |
| 407 | + uploadCount: 0, |
| 408 | + |
| 409 | + |
| 410 | + // XXX it's impossible to choose the null deed if we stick with radio buttons, so that may be useless later |
| 411 | + choose: function( deed ) { |
| 412 | + var _this = this; |
| 413 | + _this.deed = deed; |
| 414 | + if ( deed === mw.UploadWizardNullDeed ) { |
| 415 | + $j( _this ).trigger( 'chooseNullDeed' ); |
| 416 | + //_this.trigger( 'isNotReady' ); |
| 417 | + _this.$selector |
| 418 | + .find( 'input.mwe-accept-deed' ) |
| 419 | + .attr( 'checked', false ); |
| 420 | + } else { |
| 421 | + $j( _this ).trigger( 'chooseDeed' ); |
| 422 | + } |
| 423 | + }, |
| 424 | + |
| 425 | + /** |
| 426 | + * Go back to original source choice. |
| 427 | + */ |
| 428 | + showDeedChoice: function() { |
| 429 | + var $allDeeds = this.$selector.find( '.mwe-upwiz-deed' ); |
| 430 | + this.deselectDeed( $allDeeds ); |
| 431 | + // $allDeeds.fadeTo( 'fast', 1.0 ); //maskSafeShow(); |
| 432 | + }, |
| 433 | + |
| 434 | + /** |
| 435 | + * From the deed choices, make a choice fade to the background a bit, hide the extended form |
| 436 | + */ |
| 437 | + deselectDeed: function( $deedSelector ) { |
| 438 | + $deedSelector.removeClass( 'selected' ); |
| 439 | + // $deedSelector.find( 'a.mwe-upwiz-macro-deeds-return' ).hide(); |
| 440 | + $deedSelector.find( '.mwe-upwiz-deed-form' ).slideUp( 500 ); //.maskSafeHide(); |
| 441 | + }, |
| 442 | + |
| 443 | + /** |
| 444 | + * From the deed choice page, show a particular deed |
| 445 | + */ |
| 446 | + showDeed: function( $deedSelector ) { |
| 447 | + var $otherDeeds = $deedSelector.siblings().filter( '.mwe-upwiz-deed' ); |
| 448 | + this.deselectDeed( $otherDeeds ); |
| 449 | + // $siblings.fadeTo( 'fast', 0.5 ) // maskSafeHide(); |
| 450 | + |
| 451 | + $deedSelector |
| 452 | + .addClass('selected') |
| 453 | + .fadeTo( 'fast', 1.0 ) |
| 454 | + .find( '.mwe-upwiz-deed-form' ).slideDown( 500 ); // maskSafeShow(); |
| 455 | + // $deedSelector.find( 'a.mwe-upwiz-macro-deeds-return' ).show(); |
| 456 | + } |
| 457 | + |
| 458 | +}; |
| 459 | + |
| 460 | + |
| 461 | + |
Property changes on: branches/uploadwizard/extensions/UploadWizard/resources/mw.UploadWizardDeed.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 462 | + native |
Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.UploadWizardLicenseInput.js |
— | — | @@ -0,0 +1,124 @@ |
| 2 | +/** |
| 3 | + * Create a group of checkboxes for licenses. N.b. the licenses are named after the templates they invoke. |
| 4 | + * @param div |
| 5 | + * @param values (optional) array of license key names to activate by default |
| 6 | + */ |
| 7 | +mw.UploadWizardLicenseInput = function( selector, values ) { |
| 8 | + var _this = this; |
| 9 | + |
| 10 | + var widgetCount = mw.UploadWizardLicenseInput.prototype.count++; |
| 11 | + |
| 12 | + _this.inputs = []; |
| 13 | + |
| 14 | + // TODO incompatibility check of this license versus others |
| 15 | + |
| 16 | + _this.$selector = $j( selector ); |
| 17 | + _this.$selector.append( $j( '<div class="mwe-error"></div>' ) ); |
| 18 | + |
| 19 | + $j.each( mw.UploadWizard.config[ 'licenses' ], function( i, licenseConfig ) { |
| 20 | + var template = licenseConfig.template; |
| 21 | + var messageKey = licenseConfig.messageKey; |
| 22 | + |
| 23 | + var name = 'license_' + template; |
| 24 | + var id = 'licenseInput' + widgetCount + '_' + name; |
| 25 | + var $input = $j( '<input />' ) |
| 26 | + .attr( { id: id, name: name, type: 'checkbox', value: template } ) |
| 27 | + // we use the selector because events can't be unbound unless they're in the DOM. |
| 28 | + .click( function() { _this.$selector.trigger( 'changeLicenses' ); } ); |
| 29 | + _this.inputs.push( $input ); |
| 30 | + _this.$selector.append( |
| 31 | + $input, |
| 32 | + $j( '<label />' ).attr( { 'for': id } ).html( gM( messageKey ) ), |
| 33 | + $j( '<br/>' ) |
| 34 | + ); |
| 35 | + } ); |
| 36 | + |
| 37 | + if ( values ) { |
| 38 | + _this.setValues( values ); |
| 39 | + } |
| 40 | + |
| 41 | + return _this; |
| 42 | +}; |
| 43 | + |
| 44 | +mw.UploadWizardLicenseInput.prototype = { |
| 45 | + count: 0, |
| 46 | + |
| 47 | + /** |
| 48 | + * Sets the value(s) of a license input. |
| 49 | + * @param object of license-key to boolean values, e.g. { cc_by_sa_30: true, gfdl: true } |
| 50 | + */ |
| 51 | + setValues: function( licenseValues ) { |
| 52 | + var _this = this; |
| 53 | + $j.each( _this.inputs, function( i, $input ) { |
| 54 | + var template = $input.val(); |
| 55 | + $input.attr( 'checked', ~~!!licenseValues[template] ); |
| 56 | + } ); |
| 57 | + // we use the selector because events can't be unbound unless they're in the DOM. |
| 58 | + _this.$selector.trigger( 'changeLicenses' ); |
| 59 | + }, |
| 60 | + |
| 61 | + /** |
| 62 | + * Set the default configured licenses |
| 63 | + */ |
| 64 | + setDefaultValues: function() { |
| 65 | + var _this = this; |
| 66 | + var values = {}; |
| 67 | + $j.each( mw.UploadWizard.config[ 'licenses' ], function( i, licenseConfig ) { |
| 68 | + values[ licenseConfig.template ] = licenseConfig['default']; |
| 69 | + } ); |
| 70 | + _this.setValues( values ); |
| 71 | + }, |
| 72 | + |
| 73 | + /** |
| 74 | + * Gets the templates associated with checked inputs |
| 75 | + * @return array of template names |
| 76 | + */ |
| 77 | + getTemplates: function() { |
| 78 | + return $j( this.inputs ) |
| 79 | + .filter( function() { return this.is( ':checked' ); } ) |
| 80 | + .map( function() { return this.val(); } ); |
| 81 | + }, |
| 82 | + |
| 83 | + /** |
| 84 | + * Check if a valid value is set, also look for incompatible choices. |
| 85 | + * Side effect: if no valid value, add notes to the interface. Add listeners to interface, to revalidate and remove notes. |
| 86 | + * @return boolean; true if a value set, false otherwise |
| 87 | + */ |
| 88 | + valid: function() { |
| 89 | + var _this = this; |
| 90 | + var isValid = true; |
| 91 | + |
| 92 | + if ( ! _this.isSet() ) { |
| 93 | + isValid = false; |
| 94 | + errorHtml = gM( 'mwe-upwiz-deeds-need-license' ); |
| 95 | + } |
| 96 | + |
| 97 | + // XXX something goes here for licenses incompatible with each other |
| 98 | + |
| 99 | + var $errorEl = this.$selector.find( '.mwe-error' ); |
| 100 | + if (isValid) { |
| 101 | + $errorEl.fadeOut(); |
| 102 | + } else { |
| 103 | + // we bind to $selector because unbind() doesn't work on non-DOM objects |
| 104 | + _this.$selector.bind( 'changeLicenses.valid', function() { |
| 105 | + _this.$selector.unbind( 'changeLicenses.valid' ); |
| 106 | + _this.valid(); |
| 107 | + } ); |
| 108 | + $errorEl.html( errorHtml ).show(); |
| 109 | + } |
| 110 | + |
| 111 | + return isValid; |
| 112 | + }, |
| 113 | + |
| 114 | + |
| 115 | + /** |
| 116 | + * Returns true if any license is set |
| 117 | + * @return boolean |
| 118 | + */ |
| 119 | + isSet: function() { |
| 120 | + return this.getTemplates().length > 0; |
| 121 | + } |
| 122 | + |
| 123 | +}; |
| 124 | + |
| 125 | + |
Property changes on: branches/uploadwizard/extensions/UploadWizard/resources/mw.UploadWizardLicenseInput.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 126 | + native |
Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.UploadWizardUtil.js |
— | — | @@ -0,0 +1,126 @@ |
| 2 | +/** |
| 3 | + * Miscellaneous utilities |
| 4 | + */ |
| 5 | +mw.UploadWizardUtil = { |
| 6 | + |
| 7 | + /** |
| 8 | + * Simple 'more options' toggle that opens more of a form. |
| 9 | + * |
| 10 | + * @param toggleDiv the div which has the control to open and shut custom options |
| 11 | + * @param moreDiv the div containing the custom options |
| 12 | + */ |
| 13 | + makeToggler: function ( toggleDiv, moreDiv ) { |
| 14 | + var $toggleLink = $j( '<a>' ) |
| 15 | + .addClass( 'mwe-upwiz-toggler mwe-upwiz-more-options' ) |
| 16 | + .append( gM( 'mwe-upwiz-more-options' ) ); |
| 17 | + $j( toggleDiv ).append( $toggleLink ); |
| 18 | + |
| 19 | + |
| 20 | + var toggle = function( open ) { |
| 21 | + if ( typeof open === 'undefined' ) { |
| 22 | + open = ! ( $j( this ).data( 'open' ) ) ; |
| 23 | + } |
| 24 | + $j( this ).data( 'open', open ); |
| 25 | + if ( open ) { |
| 26 | + moreDiv.maskSafeShow(); |
| 27 | + /* when open, show control to close */ |
| 28 | + $toggleLink.html( gM( 'mwe-upwiz-fewer-options' ) ); |
| 29 | + $toggleLink.addClass( "mwe-upwiz-toggler-open" ); |
| 30 | + } else { |
| 31 | + moreDiv.maskSafeHide(); |
| 32 | + /* when closed, show control to open */ |
| 33 | + $toggleLink.html( gM( 'mwe-upwiz-more-options' ) ); |
| 34 | + $toggleLink.removeClass( "mwe-upwiz-toggler-open" ); |
| 35 | + } |
| 36 | + }; |
| 37 | + |
| 38 | + toggle(false); |
| 39 | + |
| 40 | + $toggleLink.click( function( e ) { e.stopPropagation(); toggle(); } ); |
| 41 | + |
| 42 | + $j( moreDiv ).addClass( 'mwe-upwiz-toggled' ); |
| 43 | + }, |
| 44 | + |
| 45 | + /** |
| 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. |
| 48 | + * XXX The jQuery way would be to query the DOM for objects, not to keep a separate array hanging around |
| 49 | + * @param items the array where we want to remove an item |
| 50 | + * @param item the item to remove |
| 51 | + */ |
| 52 | + removeItem: function( items, item ) { |
| 53 | + for ( var i = 0; i < items.length; i++ ) { |
| 54 | + if ( items[i] === item ) { |
| 55 | + items.splice( i, 1 ); |
| 56 | + break; |
| 57 | + } |
| 58 | + } |
| 59 | + }, |
| 60 | + |
| 61 | + /** |
| 62 | + * Capitalise first letter and replace spaces by underscores |
| 63 | + * @param filename (basename, without directories) |
| 64 | + * @return typical title as would appear on MediaWiki |
| 65 | + */ |
| 66 | + pathToTitle: function ( filename ) { |
| 67 | + return mw.ucfirst( $j.trim( filename ).replace(/ /g, '_' ) ); |
| 68 | + }, |
| 69 | + |
| 70 | + /** |
| 71 | + * Capitalise first letter and replace underscores by spaces |
| 72 | + * @param title typical title as would appear on MediaWiki |
| 73 | + * @return plausible local filename |
| 74 | + */ |
| 75 | + titleToPath: function ( title ) { |
| 76 | + return mw.ucfirst( $j.trim( title ).replace(/_/g, ' ' ) ); |
| 77 | + }, |
| 78 | + |
| 79 | + |
| 80 | + /** |
| 81 | + * Transform "File:title_with_spaces.jpg" into "title with spaces" |
| 82 | + * @param typical title that would appear on mediawiki, with File: and extension, may include underscores |
| 83 | + * @return human readable title |
| 84 | + */ |
| 85 | + fileTitleToHumanTitle: function( title ) { |
| 86 | + var extension = mw.UploadWizardUtil.getExtension( title ); |
| 87 | + if ( typeof extension !== 'undefined' ) { |
| 88 | + // the -1 is to get the '.' |
| 89 | + title = title.substr( 0, title.length - extension.length - 1 ); |
| 90 | + } |
| 91 | + // usually File: |
| 92 | + var namespace = wgFormattedNamespaces[wgNamespaceIds['file']]; |
| 93 | + if ( title.indexOf( namespace + ':' ) === 0 ) { |
| 94 | + title = title.substr( namespace.length + 1 ); |
| 95 | + } |
| 96 | + return mw.UploadWizardUtil.titleToPath( title ); |
| 97 | + }, |
| 98 | + |
| 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. |
| 105 | + */ |
| 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(); |
| 111 | + } |
| 112 | + return extension; |
| 113 | + }, |
| 114 | + |
| 115 | + /** |
| 116 | + * Last resort to guess a proper extension |
| 117 | + */ |
| 118 | + mimetypeToExtension: { |
| 119 | + 'image/jpeg': 'jpg', |
| 120 | + 'image/gif': 'gif' |
| 121 | + // fill as needed |
| 122 | + } |
| 123 | + |
| 124 | + |
| 125 | +}; |
| 126 | + |
| 127 | + |
Property changes on: branches/uploadwizard/extensions/UploadWizard/resources/mw.UploadWizardUtil.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 128 | + native |
Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.UploadWizard.js |
— | — | @@ -1,355 +1,8 @@ |
2 | | - |
3 | | -/** |
4 | | - * Sort of an abstract class for deeds |
5 | | - */ |
6 | | -mw.UploadWizardDeed = function() { |
7 | | - var _this = this; |
8 | | - // prevent from instantiating directly? |
9 | | - return false; |
10 | | -}; |
11 | | - |
12 | | -mw.UploadWizardDeed.prototype = { |
13 | | - valid: function() { |
14 | | - return false; |
15 | | - }, |
16 | | - |
17 | | - setFormFields: function() { }, |
18 | | - |
19 | | - getSourceWikiText: function() { |
20 | | - return $j( this.sourceInput ).val(); |
21 | | - }, |
22 | | - |
23 | | - getAuthorWikiText: function() { |
24 | | - return $j( this.authorInput ).val(); |
25 | | - }, |
26 | | - |
27 | | - /** |
28 | | - * Get wikitext representing the licenses selected in the license object |
29 | | - * @return wikitext of all applicable license templates. |
30 | | - */ |
31 | | - getLicenseWikiText: function() { |
32 | | - var _this = this; |
33 | | - var wikiText = ''; |
34 | | - $j.each ( _this.licenseInput.getTemplates(), function( i, template ) { |
35 | | - wikiText += "{{" + template + "}}\n"; |
36 | | - } ); |
37 | | - |
38 | | - return wikiText; |
39 | | - } |
40 | | - |
41 | | -}; |
42 | | - |
43 | | - |
44 | | -/** |
45 | | - * this is a progress bar for monitoring multiple objects, giving summary view |
46 | | - */ |
47 | | -mw.GroupProgressBar = function( selector, text, uploads, endState, progressProperty, weightProperty ) { |
48 | | - var _this = this; |
49 | | - |
50 | | - // XXX need to figure out a way to put text inside bar |
51 | | - _this.$selector = $j( selector ); |
52 | | - _this.$selector.html( |
53 | | - '<div class="mwe-upwiz-progress">' |
54 | | - + '<div class="mwe-upwiz-progress-bar-etr-container">' |
55 | | - + '<div class="mwe-upwiz-progress-bar-etr" style="display: none">' |
56 | | - + '<div class="mwe-upwiz-progress-bar"></div>' |
57 | | - + '<div class="mwe-upwiz-etr"></div>' |
58 | | - + '</div>' |
59 | | - + '</div>' |
60 | | - + '<div class="mwe-upwiz-count"></div>' |
61 | | - + '</div>' |
62 | | - ); |
63 | | - |
64 | | - _this.$selector.find( '.mwe-upwiz-progress-bar' ).progressbar( { value : 0 } ); |
65 | | - |
66 | | - _this.uploads = uploads; |
67 | | - _this.endState = endState; |
68 | | - _this.progressProperty = progressProperty; |
69 | | - _this.weightProperty = weightProperty; |
70 | | - _this.beginTime = undefined; |
71 | | - |
72 | | -}; |
73 | | - |
74 | | -mw.GroupProgressBar.prototype = { |
75 | | - |
76 | | - /** |
77 | | - * Show the progress bar with a slideout motion |
78 | | - */ |
79 | | - showBar: function() { |
80 | | - this.$selector.find( '.mwe-upwiz-progress-bar-etr' ).fadeIn( 200 ); |
81 | | - }, |
82 | | - |
83 | | - /** |
84 | | - * loop around the uploads, summing certain properties for a weighted total fraction |
85 | | - */ |
86 | | - start: function() { |
87 | | - var _this = this; |
88 | | - |
89 | | - var totalWeight = 0.0; |
90 | | - $j.each( _this.uploads, function( i, upload ) { |
91 | | - totalWeight += upload[_this.weightProperty]; |
92 | | - } ); |
93 | | - |
94 | | - _this.setBeginTime(); |
95 | | - var shown = false; |
96 | | - |
97 | | - var displayer = function() { |
98 | | - var fraction = 0.0; |
99 | | - var endStateCount = 0; |
100 | | - var hasData = false; |
101 | | - $j.each( _this.uploads, function( i, upload ) { |
102 | | - if ( upload.state == _this.endState ) { |
103 | | - endStateCount++; |
104 | | - } |
105 | | - if (upload[_this.progressProperty] !== undefined) { |
106 | | - fraction += upload[_this.progressProperty] * ( upload[_this.weightProperty] / totalWeight ); |
107 | | - if (upload[_this.progressProperty] > 0 ) { |
108 | | - hasData = true; |
109 | | - } |
110 | | - } |
111 | | - } ); |
112 | | - //mw.log( 'hasdata:' + hasData + ' endstatecount:' + endStateCount ); |
113 | | - // sometimes, the first data we have just tells us that it's over. So only show the bar |
114 | | - // if we have good data AND the fraction is less than 1. |
115 | | - if ( hasData && fraction < 1.0 ) { |
116 | | - if ( ! shown ) { |
117 | | - _this.showBar(); |
118 | | - shown = true; |
119 | | - } |
120 | | - _this.showProgress( fraction ); |
121 | | - } |
122 | | - _this.showCount( endStateCount ); |
123 | | - |
124 | | - if ( endStateCount < _this.uploads.length ) { |
125 | | - setTimeout( displayer, 200 ); |
126 | | - } else { |
127 | | - _this.showProgress( 1.0 ); |
128 | | - // not necessary to hide bar since we're going to the next step. |
129 | | - /* setTimeout( function() { _this.hideBar(); }, 500 ); */ |
130 | | - } |
131 | | - }; |
132 | | - displayer(); |
133 | | - }, |
134 | | - |
135 | | - |
136 | | - /** |
137 | | - * Hide the progress bar with a slideup motion |
138 | | - */ |
139 | | - hideBar: function() { |
140 | | - this.$selector.find( '.mwe-upwiz-progress-bar-etr' ).fadeOut( 200 ); |
141 | | - }, |
142 | | - |
143 | | - /** |
144 | | - * sets the beginning time (useful for figuring out estimated time remaining) |
145 | | - * if time parameter omitted, will set beginning time to now |
146 | | - * |
147 | | - * @param time optional; the time this bar is presumed to have started (epoch milliseconds) |
148 | | - */ |
149 | | - setBeginTime: function( time ) { |
150 | | - this.beginTime = time ? time : ( new Date() ).getTime(); |
151 | | - }, |
152 | | - |
153 | | - |
154 | | - /** |
155 | | - * Show overall progress for the entire UploadWizard |
156 | | - * The current design doesn't have individual progress bars, just one giant one. |
157 | | - * We did some tricky calculations in startUploads to try to weight each individual file's progress against |
158 | | - * the overall progress. |
159 | | - * @param fraction the amount of whatever it is that's done whatever it's done |
160 | | - */ |
161 | | - showProgress: function( fraction ) { |
162 | | - var _this = this; |
163 | | - |
164 | | - _this.$selector.find( '.mwe-upwiz-progress-bar' ).progressbar( 'value', parseInt( fraction * 100, 10 ) ); |
165 | | - |
166 | | - var remainingTime = _this.getRemainingTime( fraction ); |
| 2 | +// XXX |
| 3 | +// this is sure starting to look like we should compose of UI, handler. |
167 | 4 | |
168 | | - if ( remainingTime !== null ) { |
169 | | - var t = mw.seconds2Measurements( parseInt( remainingTime / 1000, 10 ) ); |
170 | | - var timeString; |
171 | | - if (t.hours === 0) { |
172 | | - if (t.minutes === 0) { |
173 | | - if (t.seconds === 0) { |
174 | | - timeString = gM( 'mwe-upwiz-finished' ); |
175 | | - } else { |
176 | | - timeString = gM( 'mwe-upwiz-secs-remaining', t.seconds ); |
177 | | - } |
178 | | - } else { |
179 | | - timeString = gM( 'mwe-upwiz-mins-secs-remaining', t.minutes, t.seconds ); |
180 | | - } |
181 | | - } else { |
182 | | - timeString = gM( 'mwe-upwiz-hrs-mins-secs-remaining', t.hours, t.minutes, t.seconds ); |
183 | | - } |
184 | | - _this.$selector.find( '.mwe-upwiz-etr' ).html( timeString ); |
185 | | - } |
186 | | - }, |
187 | 5 | |
188 | | - /** |
189 | | - * Calculate remaining time for all uploads to complete. |
190 | | - * |
191 | | - * @param fraction fraction of progress to show |
192 | | - * @return estimated time remaining (in milliseconds) |
193 | | - */ |
194 | | - getRemainingTime: function ( fraction ) { |
195 | | - var _this = this; |
196 | | - if ( _this.beginTime ) { |
197 | | - var elapsedTime = ( new Date() ).getTime() - _this.beginTime; |
198 | | - if ( fraction > 0.0 && elapsedTime > 0 ) { // or some other minimums for good data |
199 | | - var rate = fraction / elapsedTime; |
200 | | - return parseInt( ( 1.0 - fraction ) / rate, 10 ); |
201 | | - } |
202 | | - } |
203 | | - return null; |
204 | | - }, |
205 | | - |
206 | | - |
207 | | - /** |
208 | | - * Show the overall count as we upload |
209 | | - * @param count -- the number of items that have done whatever has been done e.g. in "uploaded 2 of 5", this is the 2 |
210 | | - */ |
211 | | - showCount: function( count ) { |
212 | | - var _this = this; |
213 | | - _this.$selector |
214 | | - .find( '.mwe-upwiz-count' ) |
215 | | - .html( gM( 'mwe-upwiz-upload-count', [ count, _this.uploads.length ] ) ); |
216 | | - } |
217 | | - |
218 | | - |
219 | | -}; |
220 | | - |
221 | | - |
222 | | - |
223 | | -//mw.setConfig('uploadHandlerClass', mw.MockUploadHandler); // ApiUploadHandler? |
224 | | - |
225 | | -// available licenses should be a configuration of the MediaWiki instance, |
226 | | -// not hardcoded here. |
227 | | -// but, MediaWiki has no real concept of a License as a first class object -- there are templates and then specially - parsed |
228 | | -// texts to create menus -- hack on top of hacks -- a bit too much to deal with ATM |
229 | 6 | /** |
230 | | - * Create a group of checkboxes for licenses. N.b. the licenses are named after the templates they invoke. |
231 | | - * @param div |
232 | | - * @param values (optional) array of license key names to activate by default |
233 | | - */ |
234 | | -mw.UploadWizardLicenseInput = function( selector, values ) { |
235 | | - var _this = this; |
236 | | - |
237 | | - var widgetCount = mw.UploadWizardLicenseInput.prototype.count++; |
238 | | - |
239 | | - _this.inputs = []; |
240 | | - |
241 | | - // TODO incompatibility check of this license versus others |
242 | | - |
243 | | - _this.$selector = $j( selector ); |
244 | | - _this.$selector.append( $j( '<div class="mwe-error"></div>' ) ); |
245 | | - |
246 | | - $j.each( mw.UploadWizard.config[ 'licenses' ], function( i, licenseConfig ) { |
247 | | - var template = licenseConfig.template; |
248 | | - var messageKey = licenseConfig.messageKey; |
249 | | - |
250 | | - var name = 'license_' + template; |
251 | | - var id = 'licenseInput' + widgetCount + '_' + name; |
252 | | - var $input = $j( '<input />' ) |
253 | | - .attr( { id: id, name: name, type: 'checkbox', value: template } ) |
254 | | - // we use the selector because events can't be unbound unless they're in the DOM. |
255 | | - .click( function() { _this.$selector.trigger( 'changeLicenses' ); } ); |
256 | | - _this.inputs.push( $input ); |
257 | | - _this.$selector.append( |
258 | | - $input, |
259 | | - $j( '<label />' ).attr( { 'for': id } ).html( gM( messageKey ) ), |
260 | | - $j( '<br/>' ) |
261 | | - ); |
262 | | - } ); |
263 | | - |
264 | | - if ( values ) { |
265 | | - _this.setValues( values ); |
266 | | - } |
267 | | - |
268 | | - return _this; |
269 | | -}; |
270 | | - |
271 | | -mw.UploadWizardLicenseInput.prototype = { |
272 | | - count: 0, |
273 | | - |
274 | | - /** |
275 | | - * Sets the value(s) of a license input. |
276 | | - * @param object of license-key to boolean values, e.g. { cc_by_sa_30: true, gfdl: true } |
277 | | - */ |
278 | | - setValues: function( licenseValues ) { |
279 | | - var _this = this; |
280 | | - $j.each( _this.inputs, function( i, $input ) { |
281 | | - var template = $input.val(); |
282 | | - $input.attr( 'checked', ~~!!licenseValues[template] ); |
283 | | - } ); |
284 | | - // we use the selector because events can't be unbound unless they're in the DOM. |
285 | | - _this.$selector.trigger( 'changeLicenses' ); |
286 | | - }, |
287 | | - |
288 | | - /** |
289 | | - * Set the default configured licenses |
290 | | - */ |
291 | | - setDefaultValues: function() { |
292 | | - var _this = this; |
293 | | - var values = {}; |
294 | | - $j.each( mw.UploadWizard.config[ 'licenses' ], function( i, licenseConfig ) { |
295 | | - values[ licenseConfig.template ] = licenseConfig['default']; |
296 | | - } ); |
297 | | - _this.setValues( values ); |
298 | | - }, |
299 | | - |
300 | | - /** |
301 | | - * Gets the templates associated with checked inputs |
302 | | - * @return array of template names |
303 | | - */ |
304 | | - getTemplates: function() { |
305 | | - return $j( this.inputs ) |
306 | | - .filter( function() { return this.is( ':checked' ); } ) |
307 | | - .map( function() { return this.val(); } ); |
308 | | - }, |
309 | | - |
310 | | - /** |
311 | | - * Check if a valid value is set, also look for incompatible choices. |
312 | | - * Side effect: if no valid value, add notes to the interface. Add listeners to interface, to revalidate and remove notes. |
313 | | - * @return boolean; true if a value set, false otherwise |
314 | | - */ |
315 | | - valid: function() { |
316 | | - var _this = this; |
317 | | - var isValid = true; |
318 | | - |
319 | | - if ( ! _this.isSet() ) { |
320 | | - isValid = false; |
321 | | - errorHtml = gM( 'mwe-upwiz-deeds-need-license' ); |
322 | | - } |
323 | | - |
324 | | - // XXX something goes here for licenses incompatible with each other |
325 | | - |
326 | | - var $errorEl = this.$selector.find( '.mwe-error' ); |
327 | | - if (isValid) { |
328 | | - $errorEl.fadeOut(); |
329 | | - } else { |
330 | | - // we bind to $selector because unbind() doesn't work on non-DOM objects |
331 | | - _this.$selector.bind( 'changeLicenses.valid', function() { |
332 | | - _this.$selector.unbind( 'changeLicenses.valid' ); |
333 | | - _this.valid(); |
334 | | - } ); |
335 | | - $errorEl.html( errorHtml ).show(); |
336 | | - } |
337 | | - |
338 | | - return isValid; |
339 | | - }, |
340 | | - |
341 | | - |
342 | | - /** |
343 | | - * Returns true if any license is set |
344 | | - * @return boolean |
345 | | - */ |
346 | | - isSet: function() { |
347 | | - return this.getTemplates().length > 0; |
348 | | - } |
349 | | - |
350 | | -}; |
351 | | - |
352 | | - |
353 | | -/** |
354 | 7 | * Represents the upload -- in its local and remote state. (Possibly those could be separate objects too...) |
355 | 8 | * This is our 'model' object if we are thinking MVC. Needs to be better factored, lots of feature envy with the UploadWizard |
356 | 9 | * states: |
— | — | @@ -370,9 +23,7 @@ |
371 | 24 | _this.mimetype = undefined; |
372 | 25 | _this.extension = undefined; |
373 | 26 | |
374 | | - // XXX |
375 | | - // this is sure starting to look like we should compose of UI, handler. |
376 | | - |
| 27 | + |
377 | 28 | // details |
378 | 29 | _this.ui = new mw.UploadWizardUploadInterface( _this, filesDiv ); |
379 | 30 | |
— | — | @@ -544,58 +195,32 @@ |
545 | 196 | }, |
546 | 197 | |
547 | 198 | /** |
548 | | - * Supply information to create a thumbnail for this Upload. Runs async, with a callback. |
| 199 | + * Fetch a thumbnail for this upload of the desired width. |
549 | 200 | * It is assumed you don't call this until it's been transported. |
550 | 201 | * |
551 | | - * XXX should check if we really need this second API call or if we can get MediaWiki to make us a thumbnail URL upon upload |
552 | | - * |
| 202 | + * We create the thumbnail by passing a special URL which creates the thumbnail on the fly and returns the image contents. |
| 203 | + * If the original image URL is http://foo.com/bar/baz/xyz.jpg, and the desired width is 120 pixels, |
| 204 | + * the thumbnail URL is http://foo.com/bar/baz/120px-xyz.jpg |
| 205 | + * |
553 | 206 | * @param width - desired width of thumbnail (height will scale to match) |
554 | | - * @param callback - callback to execute once thumbnail has been obtained -- must accept object with properties of width, height, and url. |
| 207 | + * @param callback - callback to execute once thumbnail has been obtained -- must accept Image object |
555 | 208 | */ |
556 | 209 | getThumbnail: function( width, callback ) { |
557 | 210 | var _this = this; |
558 | | - if ( _this._thumbnails[ "width" + width ] !== undefined ) { |
559 | | - callback( _this._thumbnails[ "width" + width ] ); |
560 | | - return; |
561 | | - } |
562 | | - |
563 | | - var params = { |
564 | | - 'titles': _this.title, |
565 | | - 'prop': 'imageinfo', |
566 | | - 'iiurlwidth': width, |
567 | | - 'iiprop': 'url' |
568 | | - }; |
569 | | - |
570 | | - debugger; |
571 | | - this.api.get( params, function( data ) { |
572 | | - if ( !data || !data.query || !data.query.pages ) { |
573 | | - mw.log(" No data? "); |
574 | | - // XXX do something about the thumbnail spinner, maybe call the callback with a broken image. |
575 | | - return; |
| 211 | + key = "width" + width; |
| 212 | + if ( mw.isDefined( _this._thumbnails[key] ) && typeof _this._thumbnails[key] === 'Image' ) { |
| 213 | + callback( _this._thumbnails[key] ); |
| 214 | + } else { |
| 215 | + var thumbUrl = _this.imageinfo.url.replace( /(.*)/([^\/]+)$/, "$1/" + width + "px-" + $2 ); |
| 216 | + _this._thumbnails[ "width" + width ] = new Image( thumbUrl ); |
| 217 | + var image = new Image(); |
| 218 | + image.onload = function(){ |
| 219 | + _this._thumbnails[key] = image; |
| 220 | + callback( image ); |
576 | 221 | } |
577 | | - |
578 | | - if ( data.query.pages[-1] ) { |
579 | | - // XXX do something about the thumbnail spinner, maybe call the callback with a broken image. |
580 | | - return; |
581 | | - } |
582 | | - for ( var page_id in data.query.pages ) { |
583 | | - var page = data.query.pages[ page_id ]; |
584 | | - if ( ! page.imageinfo ) { |
585 | | - alert("imageinfo missing"); |
586 | | - // not found? error |
587 | | - } else { |
588 | | - var imageInfo = page.imageinfo[0]; |
589 | | - var thumbnail = { |
590 | | - width: imageInfo.thumbwidth, |
591 | | - height: imageInfo.thumbheight, |
592 | | - url: imageInfo.thumburl |
593 | | - }; |
594 | | - _this._thumbnails[ "width" + width ] = thumbnail; |
595 | | - callback( thumbnail ); |
596 | | - } |
597 | | - } |
598 | | - } ); |
599 | | - |
| 222 | + image.src = thumbUrl; |
| 223 | + } |
| 224 | + |
600 | 225 | }, |
601 | 226 | |
602 | 227 | |
— | — | @@ -624,7 +249,7 @@ |
625 | 250 | $j( '<img/>' ) |
626 | 251 | .attr( 'width', thumbnail.width ) |
627 | 252 | .attr( 'height', thumbnail.height ) |
628 | | - .attr( 'src', thumbnail.url ) ) ); |
| 253 | + .attr( 'src', thumbnail.src ) ) ); |
629 | 254 | }; |
630 | 255 | |
631 | 256 | $j( selector ).loadingSpinner(); |
— | — | @@ -2640,558 +2265,6 @@ |
2641 | 2266 | } |
2642 | 2267 | }; |
2643 | 2268 | |
2644 | | -mw.UploadWizardNullDeed = $j.extend( new mw.UploadWizardDeed(), { |
2645 | | - valid: function() { |
2646 | | - return false; |
2647 | | - } |
2648 | | -} ); |
2649 | | - |
2650 | | - |
2651 | | -/** |
2652 | | - * Set up the form and deed object for the deed option that says these uploads are all the user's own work. |
2653 | | - * XXX these deeds are starting to turn into jquery fns |
2654 | | - */ |
2655 | | -mw.UploadWizardDeedOwnWork = function( uploadCount ) { |
2656 | | - uploadCount = uploadCount ? uploadCount : 1; |
2657 | | - |
2658 | | - var _this = new mw.UploadWizardDeed(); |
2659 | | - |
2660 | | - _this.authorInput = $j( '<input />') |
2661 | | - .attr( { name: "author", type: "text" } ) |
2662 | | - .addClass( 'mwe-upwiz-sign' ); |
2663 | | - |
2664 | | - var licenseInputDiv = $j( '<div class="mwe-upwiz-deed-license"></div>' ); |
2665 | | - _this.licenseInput = new mw.UploadWizardLicenseInput( licenseInputDiv ); |
2666 | | - _this.licenseInput.setDefaultValues(); |
2667 | | - |
2668 | | - return $j.extend( _this, { |
2669 | | - |
2670 | | - name: 'ownwork', |
2671 | | - |
2672 | | - /** |
2673 | | - * Is this correctly set, with side effects of causing errors to show in interface. |
2674 | | - * @return boolean true if valid, false if not |
2675 | | - */ |
2676 | | - valid: function() { |
2677 | | - // n.b. valid() has side effects and both should be called every time the function is called. |
2678 | | - // do not short-circuit. |
2679 | | - var formValid = _this.$form.valid(); |
2680 | | - var licenseInputValid = _this.licenseInput.valid(); |
2681 | | - return formValid && licenseInputValid; |
2682 | | - }, |
2683 | | - |
2684 | | - getSourceWikiText: function() { |
2685 | | - return '{{own}}'; |
2686 | | - }, |
2687 | | - |
2688 | | - // XXX do we need to escape authorInput, or is wikitext a feature here? |
2689 | | - // what about scripts? |
2690 | | - getAuthorWikiText: function() { |
2691 | | - return "[[User:" + mw.UploadWizard.config[ 'userName' ] + '|' + $j( _this.authorInput ).val() + ']]'; |
2692 | | - }, |
2693 | | - |
2694 | | - |
2695 | | - getLicenseWikiText: function() { |
2696 | | - var wikiText = '{{self'; |
2697 | | - $j.each( _this.licenseInput.getTemplates(), function( i, template ) { |
2698 | | - wikiText += '|' + template; |
2699 | | - } ); |
2700 | | - wikiText += '}}'; |
2701 | | - return wikiText; |
2702 | | - }, |
2703 | | - |
2704 | | - setFormFields: function( $selector ) { |
2705 | | - _this.$selector = $selector; |
2706 | | - |
2707 | | - _this.$form = $j( '<form/>' ); |
2708 | | - |
2709 | | - var $standardDiv = $j( '<div />' ).append( |
2710 | | - $j( '<label for="author2" generated="true" class="mwe-validator-error" style="display:block;"/>' ), |
2711 | | - $j( '<p>' ) |
2712 | | - .html( gM( 'mwe-upwiz-source-ownwork-assert', |
2713 | | - uploadCount, |
2714 | | - '<span class="mwe-standard-author-input"></span>' ) |
2715 | | - ), |
2716 | | - $j( '<p class="mwe-small-print" />' ).append( gM( 'mwe-upwiz-source-ownwork-assert-note' ) ) |
2717 | | - ); |
2718 | | - $standardDiv.find( '.mwe-standard-author-input' ).append( $j( '<input name="author2" type="text" class="mwe-upwiz-sign" />' ) ); |
2719 | | - |
2720 | | - var $customDiv = $j('<div/>').append( |
2721 | | - $j( '<label for="author" generated="true" class="mwe-validator-error" style="display:block;"/>' ), |
2722 | | - $j( '<p>' ) |
2723 | | - .html( gM( 'mwe-upwiz-source-ownwork-assert-custom', |
2724 | | - uploadCount, |
2725 | | - '<span class="mwe-custom-author-input"></span>' ) ), |
2726 | | - licenseInputDiv |
2727 | | - ); |
2728 | | - // have to add the author input this way -- gM() will flatten it to a string and we'll lose it as a dom object |
2729 | | - $customDiv.find( '.mwe-custom-author-input' ).append( _this.authorInput ); |
2730 | | - |
2731 | | - |
2732 | | - var $crossfader = $j( '<div>' ).append( $standardDiv, $customDiv ); |
2733 | | - var $toggler = $j( '<p class="mwe-more-options" style="text-align: right" />' ) |
2734 | | - .append( $j( '<a />' ) |
2735 | | - .append( gM( 'mwe-upwiz-license-show-all' ) ) |
2736 | | - .click( function() { |
2737 | | - _this.formValidator.resetForm(); |
2738 | | - if ( $crossfader.data( 'crossfadeDisplay' ) === $customDiv ) { |
2739 | | - _this.licenseInput.setDefaultValues(); |
2740 | | - $crossfader.morphCrossfade( $standardDiv ); |
2741 | | - $j( this ).html( gM( 'mwe-upwiz-license-show-all' ) ); |
2742 | | - } else { |
2743 | | - $crossfader.morphCrossfade( $customDiv ); |
2744 | | - $j( this ).html( gM( 'mwe-upwiz-license-show-recommended' ) ); |
2745 | | - } |
2746 | | - } ) ); |
2747 | | - |
2748 | | - var $formFields = $j( '<div class="mwe-upwiz-deed-form-internal" />' ) |
2749 | | - .append( $crossfader, $toggler ); |
2750 | | - |
2751 | | - |
2752 | | - // synchronize both username signatures |
2753 | | - // set initial value to configured username |
2754 | | - // if one changes all the others change (keyup event) |
2755 | | - // |
2756 | | - // also set tooltips ( the title, tipsy() ) |
2757 | | - $formFields.find( '.mwe-upwiz-sign' ) |
2758 | | - .attr( { |
2759 | | - title: gM( 'mwe-upwiz-tooltip-sign' ), |
2760 | | - value: mw.UploadWizard.config[ 'userName' ] |
2761 | | - } ) |
2762 | | - .tipsyPlus() |
2763 | | - .keyup( function() { |
2764 | | - var thisInput = this; |
2765 | | - var thisVal = $j( thisInput ).val(); |
2766 | | - $j.each( $formFields.find( '.mwe-upwiz-sign' ), function( i, input ) { |
2767 | | - if (thisInput !== input) { |
2768 | | - $j( input ).val( thisVal ); |
2769 | | - } |
2770 | | - } ); |
2771 | | - } ); |
2772 | | - |
2773 | | - _this.$form.append( $formFields ); |
2774 | | - $selector.append( _this.$form ); |
2775 | | - |
2776 | | - // done after added to the DOM, so there are true heights |
2777 | | - $crossfader.morphCrossfader(); |
2778 | | - |
2779 | | - |
2780 | | - // and finally, make it validatable |
2781 | | - _this.formValidator = _this.$form.validate( { |
2782 | | - rules: { |
2783 | | - author2: { |
2784 | | - required: function( element ) { |
2785 | | - return $crossfader.data( 'crossfadeDisplay' ).get(0) === $standardDiv.get(0); |
2786 | | - }, |
2787 | | - minlength: mw.UploadWizard.config[ 'minAuthorLength' ], |
2788 | | - maxlength: mw.UploadWizard.config[ 'maxAuthorLength' ] |
2789 | | - }, |
2790 | | - author: { |
2791 | | - required: function( element ) { |
2792 | | - return $crossfader.data( 'crossfadeDisplay' ).get(0) === $customDiv.get(0); |
2793 | | - }, |
2794 | | - minlength: mw.UploadWizard.config[ 'minAuthorLength' ], |
2795 | | - maxlength: mw.UploadWizard.config[ 'maxAuthorLength' ] |
2796 | | - } |
2797 | | - }, |
2798 | | - messages: { |
2799 | | - author2: { |
2800 | | - required: gM( 'mwe-upwiz-error-signature-blank' ), |
2801 | | - minlength: gM( 'mwe-upwiz-error-signature-too-short', mw.UploadWizard.config[ 'minAuthorLength' ] ), |
2802 | | - maxlength: gM( 'mwe-upwiz-error-signature-too-long', mw.UploadWizard.config[ 'maxAuthorLength' ] ) |
2803 | | - }, |
2804 | | - author: { |
2805 | | - required: gM( 'mwe-upwiz-error-signature-blank' ), |
2806 | | - minlength: gM( 'mwe-upwiz-error-signature-too-short', mw.UploadWizard.config[ 'minAuthorLength' ] ), |
2807 | | - maxlength: gM( 'mwe-upwiz-error-signature-too-long', mw.UploadWizard.config[ 'maxAuthorLength' ] ) |
2808 | | - } |
2809 | | - } |
2810 | | - } ); |
2811 | | - } |
2812 | | - |
2813 | | - |
2814 | | - } ); |
2815 | | - |
2816 | | -}; |
2817 | | - |
2818 | | -// XXX these deeds are starting to turn into jquery fns |
2819 | | -mw.UploadWizardDeedThirdParty = function( uploadCount ) { |
2820 | | - var _this = new mw.UploadWizardDeed(); |
2821 | | - |
2822 | | - _this.uploadCount = uploadCount ? uploadCount : 1; |
2823 | | - _this.sourceInput = $j('<textarea class="mwe-source mwe-long-textarea" name="source" rows="1" cols="40"></textarea>' ) |
2824 | | - .growTextArea() |
2825 | | - .attr( 'title', gM( 'mwe-upwiz-tooltip-source' ) ) |
2826 | | - .tipsyPlus(); |
2827 | | - _this.authorInput = $j('<textarea class="mwe-author mwe-long-textarea" name="author" rows="1" cols="40"></textarea>' ) |
2828 | | - .growTextArea() |
2829 | | - .attr( 'title', gM( 'mwe-upwiz-tooltip-author' ) ) |
2830 | | - .tipsyPlus(); |
2831 | | - licenseInputDiv = $j( '<div class="mwe-upwiz-deed-license"></div>' ); |
2832 | | - _this.licenseInput = new mw.UploadWizardLicenseInput( licenseInputDiv ); |
2833 | | - |
2834 | | - |
2835 | | - return $j.extend( _this, mw.UploadWizardDeed.prototype, { |
2836 | | - name: 'thirdparty', |
2837 | | - |
2838 | | - setFormFields: function( $selector ) { |
2839 | | - var _this = this; |
2840 | | - _this.$form = $j( '<form/>' ); |
2841 | | - |
2842 | | - var $formFields = $j( '<div class="mwe-upwiz-deed-form-internal"/>' ); |
2843 | | - |
2844 | | - if ( uploadCount > 1 ) { |
2845 | | - $formFields.append( $j( '<div />' ).append( gM( 'mwe-upwiz-source-thirdparty-custom-multiple-intro' ) ) ); |
2846 | | - } |
2847 | | - |
2848 | | - $formFields.append ( |
2849 | | - $j( '<div class="mwe-upwiz-source-thirdparty-custom-multiple-intro" />' ), |
2850 | | - $j( '<label for="source" generated="true" class="mwe-validator-error" style="display:block;"/>' ), |
2851 | | - $j( '<div class="mwe-upwiz-thirdparty-fields" />' ) |
2852 | | - .append( $j( '<label for="source"/>' ).text( gM( 'mwe-upwiz-source' ) ), |
2853 | | - _this.sourceInput ), |
2854 | | - $j( '<label for="author" generated="true" class="mwe-validator-error" style="display:block;"/>' ), |
2855 | | - $j( '<div class="mwe-upwiz-thirdparty-fields" />' ) |
2856 | | - .append( $j( '<label for="author"/>' ).text( gM( 'mwe-upwiz-author' ) ), |
2857 | | - _this.authorInput ), |
2858 | | - $j( '<div class="mwe-upwiz-thirdparty-license" />' ) |
2859 | | - .append( gM( 'mwe-upwiz-source-thirdparty-license', uploadCount ) ), |
2860 | | - licenseInputDiv |
2861 | | - ); |
2862 | | - |
2863 | | - _this.$form.validate( { |
2864 | | - rules: { |
2865 | | - source: { required: true, |
2866 | | - minlength: mw.UploadWizard.config[ 'minSourceLength' ], |
2867 | | - maxlength: mw.UploadWizard.config[ 'maxSourceLength' ] }, |
2868 | | - author: { required: true, |
2869 | | - minlength: mw.UploadWizard.config[ 'minAuthorLength' ], |
2870 | | - maxlength: mw.UploadWizard.config[ 'maxAuthorLength' ] } |
2871 | | - }, |
2872 | | - messages: { |
2873 | | - source: { |
2874 | | - required: gM( 'mwe-upwiz-error-blank' ), |
2875 | | - minlength: gM( 'mwe-upwiz-error-too-short', mw.UploadWizard.config[ 'minSourceLength' ] ), |
2876 | | - maxlength: gM( 'mwe-upwiz-error-too-long', mw.UploadWizard.config[ 'maxSourceLength' ] ) |
2877 | | - }, |
2878 | | - author: { |
2879 | | - required: gM( 'mwe-upwiz-error-blank' ), |
2880 | | - minlength: gM( 'mwe-upwiz-error-too-short', mw.UploadWizard.config[ 'minAuthorLength' ] ), |
2881 | | - maxlength: gM( 'mwe-upwiz-error-too-long', mw.UploadWizard.config[ 'maxAuthorLength' ] ) |
2882 | | - } |
2883 | | - } |
2884 | | - } ); |
2885 | | - |
2886 | | - _this.$form.append( $formFields ); |
2887 | | - |
2888 | | - $selector.append( _this.$form ); |
2889 | | - }, |
2890 | | - |
2891 | | - /** |
2892 | | - * Is this correctly set, with side effects of causing errors to show in interface. |
2893 | | - * this is exactly the same as the ownwork valid() function... hopefully we can reduce these to nothing if we make |
2894 | | - * all validators work the same. |
2895 | | - * @return boolean true if valid, false if not |
2896 | | - */ |
2897 | | - valid: function() { |
2898 | | - // n.b. valid() has side effects and both should be called every time the function is called. |
2899 | | - // do not short-circuit. |
2900 | | - var formValid = _this.$form.valid(); |
2901 | | - var licenseInputValid = _this.licenseInput.valid(); |
2902 | | - return formValid && licenseInputValid; |
2903 | | - } |
2904 | | - } ); |
2905 | | -}; |
2906 | | - |
2907 | | - |
2908 | | - |
2909 | | - |
2910 | | -/** |
2911 | | - * @param selector where to put this deed chooser |
2912 | | - * @param isPlural whether this chooser applies to multiple files (changes messaging mostly) |
2913 | | - */ |
2914 | | -mw.UploadWizardDeedChooser = function( selector, deeds, uploadCount ) { |
2915 | | - var _this = this; |
2916 | | - _this.$selector = $j( selector ); |
2917 | | - _this.uploadCount = uploadCount ? uploadCount : 1; |
2918 | | - |
2919 | | - |
2920 | | - _this.$errorEl = $j( '<div class="mwe-error"></div>' ); |
2921 | | - _this.$selector.append( _this.$errorEl ); |
2922 | | - |
2923 | | - // name for radio button set |
2924 | | - mw.UploadWizardDeedChooser.prototype.widgetCount++; |
2925 | | - _this.name = 'deedChooser' + mw.UploadWizardDeedChooser.prototype.widgetCount.toString(); |
2926 | | - |
2927 | | - $j.each( deeds, function (i, deed) { |
2928 | | - var id = _this.name + '-' + deed.name; |
2929 | | - |
2930 | | - var $deedInterface = $j( |
2931 | | - '<div class="mwe-upwiz-deed mwe-upwiz-deed-' + deed.name + '">' |
2932 | | - + '<div class="mwe-upwiz-deed-option-title">' |
2933 | | - + '<span class="mwe-upwiz-deed-header">' |
2934 | | - + '<input id="' + id +'" name="' + _this.name + '" type="radio" value="' + deed.name + '">' |
2935 | | - + '<label for="' + id + '" class="mwe-upwiz-deed-name">' |
2936 | | - + gM( 'mwe-upwiz-source-' + deed.name, _this.uploadCount ) |
2937 | | - + '</label>' |
2938 | | - + '</input>' |
2939 | | - + '</span>' |
2940 | | - // + ' <a class="mwe-upwiz-macro-deeds-return">' + gM( 'mwe-upwiz-change' ) + '</a>' |
2941 | | - + '</div>' |
2942 | | - + '<div class="mwe-upwiz-deed-form">' |
2943 | | - + '</div>' |
2944 | | - ); |
2945 | | - |
2946 | | - var $deedSelector = _this.$selector.append( $deedInterface ); |
2947 | | - |
2948 | | - deed.setFormFields( $deedInterface.find( '.mwe-upwiz-deed-form' ) ); |
2949 | | - |
2950 | | - $deedInterface.find( 'span.mwe-upwiz-deed-header input' ).click( function() { |
2951 | | - if ( $j( this ).is(':checked' ) ) { |
2952 | | - _this.choose( deed ); |
2953 | | - _this.showDeed( $deedInterface ); |
2954 | | - } |
2955 | | - } ); |
2956 | | - |
2957 | | - } ); |
2958 | | - |
2959 | | - /* |
2960 | | - $j( '.mwe-upwiz-macro-deeds-return' ).click( function() { |
2961 | | - _this.choose( mw.UploadWizardNullDeed ); |
2962 | | - _this.showDeedChoice(); |
2963 | | - } ); |
2964 | | - */ |
2965 | | - |
2966 | | - _this.choose( mw.UploadWizardNullDeed ); |
2967 | | - _this.showDeedChoice(); |
2968 | | - |
2969 | | - |
2970 | | -}; |
2971 | | - |
2972 | | - |
2973 | | -mw.UploadWizardDeedChooser.prototype = { |
2974 | | - |
2975 | | - /** |
2976 | | - * How many deed choosers there are (important for creating unique ids, element names) |
2977 | | - */ |
2978 | | - widgetCount: 0, |
2979 | | - |
2980 | | - /** |
2981 | | - * Check if this form is filled out correctly, with side effects of showing error messages if invalid |
2982 | | - * @return boolean; true if valid, false if not |
2983 | | - */ |
2984 | | - valid: function() { |
2985 | | - var _this = this; |
2986 | | - // we assume there is always a deed available, even if it's just the null deed. |
2987 | | - var valid = _this.deed.valid(); |
2988 | | - // the only time we need to set an error message is if the null deed is selected. |
2989 | | - // otherwise, we can assume that the widgets have already added error messages. |
2990 | | - if (valid) { |
2991 | | - _this.hideError(); |
2992 | | - } else { |
2993 | | - if ( _this.deed === mw.UploadWizardNullDeed ) { |
2994 | | - _this.showError( gM( 'mwe-upwiz-deeds-need-deed', _this.uploadCount ) ); |
2995 | | - $j( _this ).bind( 'chooseDeed', function() { |
2996 | | - _this.hideError(); |
2997 | | - } ); |
2998 | | - } |
2999 | | - } |
3000 | | - return valid; |
3001 | | - }, |
3002 | | - |
3003 | | - showError: function( error ) { |
3004 | | - this.$errorEl.html( error ); |
3005 | | - this.$errorEl.fadeIn(); |
3006 | | - }, |
3007 | | - |
3008 | | - hideError: function() { |
3009 | | - this.$errorEl.fadeOut(); |
3010 | | - this.$errorEl.empty(); |
3011 | | - }, |
3012 | | - |
3013 | | - /** |
3014 | | - * How many uploads this deed controls |
3015 | | - */ |
3016 | | - uploadCount: 0, |
3017 | | - |
3018 | | - |
3019 | | - // XXX it's impossible to choose the null deed if we stick with radio buttons, so that may be useless later |
3020 | | - choose: function( deed ) { |
3021 | | - var _this = this; |
3022 | | - _this.deed = deed; |
3023 | | - if ( deed === mw.UploadWizardNullDeed ) { |
3024 | | - $j( _this ).trigger( 'chooseNullDeed' ); |
3025 | | - //_this.trigger( 'isNotReady' ); |
3026 | | - _this.$selector |
3027 | | - .find( 'input.mwe-accept-deed' ) |
3028 | | - .attr( 'checked', false ); |
3029 | | - } else { |
3030 | | - $j( _this ).trigger( 'chooseDeed' ); |
3031 | | - } |
3032 | | - }, |
3033 | | - |
3034 | | - /** |
3035 | | - * Go back to original source choice. |
3036 | | - */ |
3037 | | - showDeedChoice: function() { |
3038 | | - var $allDeeds = this.$selector.find( '.mwe-upwiz-deed' ); |
3039 | | - this.deselectDeed( $allDeeds ); |
3040 | | - // $allDeeds.fadeTo( 'fast', 1.0 ); //maskSafeShow(); |
3041 | | - }, |
3042 | | - |
3043 | | - /** |
3044 | | - * From the deed choices, make a choice fade to the background a bit, hide the extended form |
3045 | | - */ |
3046 | | - deselectDeed: function( $deedSelector ) { |
3047 | | - $deedSelector.removeClass( 'selected' ); |
3048 | | - // $deedSelector.find( 'a.mwe-upwiz-macro-deeds-return' ).hide(); |
3049 | | - $deedSelector.find( '.mwe-upwiz-deed-form' ).slideUp( 500 ); //.maskSafeHide(); |
3050 | | - }, |
3051 | | - |
3052 | | - /** |
3053 | | - * From the deed choice page, show a particular deed |
3054 | | - */ |
3055 | | - showDeed: function( $deedSelector ) { |
3056 | | - var $otherDeeds = $deedSelector.siblings().filter( '.mwe-upwiz-deed' ); |
3057 | | - this.deselectDeed( $otherDeeds ); |
3058 | | - // $siblings.fadeTo( 'fast', 0.5 ) // maskSafeHide(); |
3059 | | - |
3060 | | - $deedSelector |
3061 | | - .addClass('selected') |
3062 | | - .fadeTo( 'fast', 1.0 ) |
3063 | | - .find( '.mwe-upwiz-deed-form' ).slideDown( 500 ); // maskSafeShow(); |
3064 | | - // $deedSelector.find( 'a.mwe-upwiz-macro-deeds-return' ).show(); |
3065 | | - } |
3066 | | - |
3067 | | -}; |
3068 | | - |
3069 | | - |
3070 | | - |
3071 | | -/** |
3072 | | - * Miscellaneous utilities |
3073 | | - */ |
3074 | | -mw.UploadWizardUtil = { |
3075 | | - |
3076 | | - /** |
3077 | | - * Simple 'more options' toggle that opens more of a form. |
3078 | | - * |
3079 | | - * @param toggleDiv the div which has the control to open and shut custom options |
3080 | | - * @param moreDiv the div containing the custom options |
3081 | | - */ |
3082 | | - makeToggler: function ( toggleDiv, moreDiv ) { |
3083 | | - var $toggleLink = $j( '<a>' ) |
3084 | | - .addClass( 'mwe-upwiz-toggler mwe-upwiz-more-options' ) |
3085 | | - .append( gM( 'mwe-upwiz-more-options' ) ); |
3086 | | - $j( toggleDiv ).append( $toggleLink ); |
3087 | | - |
3088 | | - |
3089 | | - var toggle = function( open ) { |
3090 | | - if ( typeof open === 'undefined' ) { |
3091 | | - open = ! ( $j( this ).data( 'open' ) ) ; |
3092 | | - } |
3093 | | - $j( this ).data( 'open', open ); |
3094 | | - if ( open ) { |
3095 | | - moreDiv.maskSafeShow(); |
3096 | | - /* when open, show control to close */ |
3097 | | - $toggleLink.html( gM( 'mwe-upwiz-fewer-options' ) ); |
3098 | | - $toggleLink.addClass( "mwe-upwiz-toggler-open" ); |
3099 | | - } else { |
3100 | | - moreDiv.maskSafeHide(); |
3101 | | - /* when closed, show control to open */ |
3102 | | - $toggleLink.html( gM( 'mwe-upwiz-more-options' ) ); |
3103 | | - $toggleLink.removeClass( "mwe-upwiz-toggler-open" ); |
3104 | | - } |
3105 | | - }; |
3106 | | - |
3107 | | - toggle(false); |
3108 | | - |
3109 | | - $toggleLink.click( function( e ) { e.stopPropagation(); toggle(); } ); |
3110 | | - |
3111 | | - $j( moreDiv ).addClass( 'mwe-upwiz-toggled' ); |
3112 | | - }, |
3113 | | - |
3114 | | - /** |
3115 | | - * remove an item from an array. Tests for === identity to remove the item |
3116 | | - * XXX the entire rationale for this file may be wrong. |
3117 | | - * XXX The jQuery way would be to query the DOM for objects, not to keep a separate array hanging around |
3118 | | - * @param items the array where we want to remove an item |
3119 | | - * @param item the item to remove |
3120 | | - */ |
3121 | | - removeItem: function( items, item ) { |
3122 | | - for ( var i = 0; i < items.length; i++ ) { |
3123 | | - if ( items[i] === item ) { |
3124 | | - items.splice( i, 1 ); |
3125 | | - break; |
3126 | | - } |
3127 | | - } |
3128 | | - }, |
3129 | | - |
3130 | | - /** |
3131 | | - * Capitalise first letter and replace spaces by underscores |
3132 | | - * @param filename (basename, without directories) |
3133 | | - * @return typical title as would appear on MediaWiki |
3134 | | - */ |
3135 | | - pathToTitle: function ( filename ) { |
3136 | | - return mw.ucfirst( $j.trim( filename ).replace(/ /g, '_' ) ); |
3137 | | - }, |
3138 | | - |
3139 | | - /** |
3140 | | - * Capitalise first letter and replace underscores by spaces |
3141 | | - * @param title typical title as would appear on MediaWiki |
3142 | | - * @return plausible local filename |
3143 | | - */ |
3144 | | - titleToPath: function ( title ) { |
3145 | | - return mw.ucfirst( $j.trim( title ).replace(/_/g, ' ' ) ); |
3146 | | - }, |
3147 | | - |
3148 | | - |
3149 | | - /** |
3150 | | - * Transform "File:title_with_spaces.jpg" into "title with spaces" |
3151 | | - * @param typical title that would appear on mediawiki, with File: and extension, may include underscores |
3152 | | - * @return human readable title |
3153 | | - */ |
3154 | | - fileTitleToHumanTitle: function( title ) { |
3155 | | - var extension = mw.UploadWizardUtil.getExtension( title ); |
3156 | | - if ( typeof extension !== 'undefined' ) { |
3157 | | - // the -1 is to get the '.' |
3158 | | - title = title.substr( 0, title.length - extension.length - 1 ); |
3159 | | - } |
3160 | | - // usually File: |
3161 | | - var namespace = wgFormattedNamespaces[wgNamespaceIds['file']]; |
3162 | | - if ( title.indexOf( namespace + ':' ) === 0 ) { |
3163 | | - title = title.substr( namespace.length + 1 ); |
3164 | | - } |
3165 | | - return mw.UploadWizardUtil.titleToPath( title ); |
3166 | | - }, |
3167 | | - |
3168 | | - |
3169 | | - /** |
3170 | | - * Slice extension off a path |
3171 | | - * We assume that extensions are 1-4 characters in length |
3172 | | - * @param path to file, like "foo/bar/baz.jpg" |
3173 | | - * @return extension, like ".jpg" or undefined if it doesn't look lke an extension. |
3174 | | - */ |
3175 | | - getExtension: function( path ) { |
3176 | | - var extension = undefined; |
3177 | | - var idx = path.lastIndexOf( '.' ); |
3178 | | - if (idx > 0 && ( idx > ( path.length - 5 ) ) && ( idx < ( path.length - 1 ) ) ) { |
3179 | | - extension = path.substr( idx + 1 ).toLowerCase(); |
3180 | | - } |
3181 | | - return extension; |
3182 | | - }, |
3183 | | - |
3184 | | - /** |
3185 | | - * Last resort to guess a proper extension |
3186 | | - */ |
3187 | | - mimetypeToExtension: { |
3188 | | - 'image/jpeg': 'jpg', |
3189 | | - 'image/gif': 'gif' |
3190 | | - // fill as needed |
3191 | | - } |
3192 | | - |
3193 | | - |
3194 | | -}; |
3195 | | - |
3196 | 2269 | ( function( $j ) { |
3197 | 2270 | |
3198 | 2271 | /** |
— | — | @@ -3345,9 +2418,7 @@ |
3346 | 2419 | */ |
3347 | 2420 | |
3348 | 2421 | } |
3349 | | - |
3350 | | - // XXX bind to a custom event in case the div size changes : ? |
3351 | | - |
| 2422 | + // XXX bind to a custom event in case the div size changes |
3352 | 2423 | } ); |
3353 | 2424 | |
3354 | 2425 | return this; |
Index: branches/uploadwizard/extensions/UploadWizard/resources/mw.GroupProgressBar.js |
— | — | @@ -0,0 +1,178 @@ |
| 2 | +/** |
| 3 | + * this is a progress bar for monitoring multiple objects, giving summary view |
| 4 | + */ |
| 5 | +mw.GroupProgressBar = function( selector, text, uploads, endState, progressProperty, weightProperty ) { |
| 6 | + var _this = this; |
| 7 | + |
| 8 | + // XXX need to figure out a way to put text inside bar |
| 9 | + _this.$selector = $j( selector ); |
| 10 | + _this.$selector.html( |
| 11 | + '<div class="mwe-upwiz-progress">' |
| 12 | + + '<div class="mwe-upwiz-progress-bar-etr-container">' |
| 13 | + + '<div class="mwe-upwiz-progress-bar-etr" style="display: none">' |
| 14 | + + '<div class="mwe-upwiz-progress-bar"></div>' |
| 15 | + + '<div class="mwe-upwiz-etr"></div>' |
| 16 | + + '</div>' |
| 17 | + + '</div>' |
| 18 | + + '<div class="mwe-upwiz-count"></div>' |
| 19 | + + '</div>' |
| 20 | + ); |
| 21 | + |
| 22 | + _this.$selector.find( '.mwe-upwiz-progress-bar' ).progressbar( { value : 0 } ); |
| 23 | + |
| 24 | + _this.uploads = uploads; |
| 25 | + _this.endState = endState; |
| 26 | + _this.progressProperty = progressProperty; |
| 27 | + _this.weightProperty = weightProperty; |
| 28 | + _this.beginTime = undefined; |
| 29 | + |
| 30 | +}; |
| 31 | + |
| 32 | +mw.GroupProgressBar.prototype = { |
| 33 | + |
| 34 | + /** |
| 35 | + * Show the progress bar with a slideout motion |
| 36 | + */ |
| 37 | + showBar: function() { |
| 38 | + this.$selector.find( '.mwe-upwiz-progress-bar-etr' ).fadeIn( 200 ); |
| 39 | + }, |
| 40 | + |
| 41 | + /** |
| 42 | + * loop around the uploads, summing certain properties for a weighted total fraction |
| 43 | + */ |
| 44 | + start: function() { |
| 45 | + var _this = this; |
| 46 | + |
| 47 | + var totalWeight = 0.0; |
| 48 | + $j.each( _this.uploads, function( i, upload ) { |
| 49 | + totalWeight += upload[_this.weightProperty]; |
| 50 | + } ); |
| 51 | + |
| 52 | + _this.setBeginTime(); |
| 53 | + var shown = false; |
| 54 | + |
| 55 | + var displayer = function() { |
| 56 | + var fraction = 0.0; |
| 57 | + var endStateCount = 0; |
| 58 | + var hasData = false; |
| 59 | + $j.each( _this.uploads, function( i, upload ) { |
| 60 | + if ( upload.state == _this.endState ) { |
| 61 | + endStateCount++; |
| 62 | + } |
| 63 | + if (upload[_this.progressProperty] !== undefined) { |
| 64 | + fraction += upload[_this.progressProperty] * ( upload[_this.weightProperty] / totalWeight ); |
| 65 | + if (upload[_this.progressProperty] > 0 ) { |
| 66 | + hasData = true; |
| 67 | + } |
| 68 | + } |
| 69 | + } ); |
| 70 | + //mw.log( 'hasdata:' + hasData + ' endstatecount:' + endStateCount ); |
| 71 | + // sometimes, the first data we have just tells us that it's over. So only show the bar |
| 72 | + // if we have good data AND the fraction is less than 1. |
| 73 | + if ( hasData && fraction < 1.0 ) { |
| 74 | + if ( ! shown ) { |
| 75 | + _this.showBar(); |
| 76 | + shown = true; |
| 77 | + } |
| 78 | + _this.showProgress( fraction ); |
| 79 | + } |
| 80 | + _this.showCount( endStateCount ); |
| 81 | + |
| 82 | + if ( endStateCount < _this.uploads.length ) { |
| 83 | + setTimeout( displayer, 200 ); |
| 84 | + } else { |
| 85 | + _this.showProgress( 1.0 ); |
| 86 | + // not necessary to hide bar since we're going to the next step. |
| 87 | + /* setTimeout( function() { _this.hideBar(); }, 500 ); */ |
| 88 | + } |
| 89 | + }; |
| 90 | + displayer(); |
| 91 | + }, |
| 92 | + |
| 93 | + |
| 94 | + /** |
| 95 | + * Hide the progress bar with a slideup motion |
| 96 | + */ |
| 97 | + hideBar: function() { |
| 98 | + this.$selector.find( '.mwe-upwiz-progress-bar-etr' ).fadeOut( 200 ); |
| 99 | + }, |
| 100 | + |
| 101 | + /** |
| 102 | + * sets the beginning time (useful for figuring out estimated time remaining) |
| 103 | + * if time parameter omitted, will set beginning time to now |
| 104 | + * |
| 105 | + * @param time optional; the time this bar is presumed to have started (epoch milliseconds) |
| 106 | + */ |
| 107 | + setBeginTime: function( time ) { |
| 108 | + this.beginTime = time ? time : ( new Date() ).getTime(); |
| 109 | + }, |
| 110 | + |
| 111 | + |
| 112 | + /** |
| 113 | + * Show overall progress for the entire UploadWizard |
| 114 | + * The current design doesn't have individual progress bars, just one giant one. |
| 115 | + * We did some tricky calculations in startUploads to try to weight each individual file's progress against |
| 116 | + * the overall progress. |
| 117 | + * @param fraction the amount of whatever it is that's done whatever it's done |
| 118 | + */ |
| 119 | + showProgress: function( fraction ) { |
| 120 | + var _this = this; |
| 121 | + |
| 122 | + _this.$selector.find( '.mwe-upwiz-progress-bar' ).progressbar( 'value', parseInt( fraction * 100, 10 ) ); |
| 123 | + |
| 124 | + var remainingTime = _this.getRemainingTime( fraction ); |
| 125 | + |
| 126 | + if ( remainingTime !== null ) { |
| 127 | + var t = mw.seconds2Measurements( parseInt( remainingTime / 1000, 10 ) ); |
| 128 | + var timeString; |
| 129 | + if (t.hours === 0) { |
| 130 | + if (t.minutes === 0) { |
| 131 | + if (t.seconds === 0) { |
| 132 | + timeString = gM( 'mwe-upwiz-finished' ); |
| 133 | + } else { |
| 134 | + timeString = gM( 'mwe-upwiz-secs-remaining', t.seconds ); |
| 135 | + } |
| 136 | + } else { |
| 137 | + timeString = gM( 'mwe-upwiz-mins-secs-remaining', t.minutes, t.seconds ); |
| 138 | + } |
| 139 | + } else { |
| 140 | + timeString = gM( 'mwe-upwiz-hrs-mins-secs-remaining', t.hours, t.minutes, t.seconds ); |
| 141 | + } |
| 142 | + _this.$selector.find( '.mwe-upwiz-etr' ).html( timeString ); |
| 143 | + } |
| 144 | + }, |
| 145 | + |
| 146 | + /** |
| 147 | + * Calculate remaining time for all uploads to complete. |
| 148 | + * |
| 149 | + * @param fraction fraction of progress to show |
| 150 | + * @return estimated time remaining (in milliseconds) |
| 151 | + */ |
| 152 | + getRemainingTime: function ( fraction ) { |
| 153 | + var _this = this; |
| 154 | + if ( _this.beginTime ) { |
| 155 | + var elapsedTime = ( new Date() ).getTime() - _this.beginTime; |
| 156 | + if ( fraction > 0.0 && elapsedTime > 0 ) { // or some other minimums for good data |
| 157 | + var rate = fraction / elapsedTime; |
| 158 | + return parseInt( ( 1.0 - fraction ) / rate, 10 ); |
| 159 | + } |
| 160 | + } |
| 161 | + return null; |
| 162 | + }, |
| 163 | + |
| 164 | + |
| 165 | + /** |
| 166 | + * Show the overall count as we upload |
| 167 | + * @param count -- the number of items that have done whatever has been done e.g. in "uploaded 2 of 5", this is the 2 |
| 168 | + */ |
| 169 | + showCount: function( count ) { |
| 170 | + var _this = this; |
| 171 | + _this.$selector |
| 172 | + .find( '.mwe-upwiz-count' ) |
| 173 | + .html( gM( 'mwe-upwiz-upload-count', [ count, _this.uploads.length ] ) ); |
| 174 | + } |
| 175 | + |
| 176 | + |
| 177 | +}; |
| 178 | + |
| 179 | + |
Property changes on: branches/uploadwizard/extensions/UploadWizard/resources/mw.GroupProgressBar.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 180 | + native |