User:Rillke/bigChunkedUpload.js: Difference between revisions
Jump to navigation
Jump to search
Content deleted Content added
m disable slider |
The ext property of mw.Title got removed, see phab:T232521. Issue reported by ShakespeareFan00. |
||
(19 intermediate revisions by 3 users not shown) | |||
Line 2: | Line 2: | ||
/*global jQuery:false, mediaWiki:false, MwJSBot:false*/ |
/*global jQuery:false, mediaWiki:false, MwJSBot:false*/ |
||
(function($, mw, undefined) { |
( function( $, mw, undefined ) { |
||
'use strict'; |
'use strict'; |
||
var modeNewFile; |
var modeNewFile; |
||
var i; |
|||
var random = Math.round(Math.random() * 0x1000000000); |
|||
var commonwWikiKey = "commonswiki" + random; |
|||
var commonsWiki = {}; |
|||
var modules = [ |
|||
[ "ext.gadget.editDropdown", "ver1_svg", [], null, commonwWikiKey ], |
|||
[ "ext.gadget.libAPI", "ver1_svg", [], null, commonwWikiKey ] |
|||
]; |
|||
function ucFirst( s ) { |
|||
var _install = function() { |
|||
return s[ 0 ].toUpperCase() + s.slice( 1 ); |
|||
} |
|||
var _install = function() { |
|||
var $reuploadLink = $('#mw-imagepage-reupload-link').find('a'), |
|||
$activationLinks; |
|||
var $reuploadLink = $( '#mw-imagepage-reupload-link' ) |
|||
.find( 'a' ), |
|||
$activationLinks; |
|||
text: " (chunked upload)" |
|||
}).attr({ |
|||
href: '#chunked upload' |
|||
}).insertAfter($reuploadLink); |
|||
if ( $reuploadLink.length ) { |
|||
$activationLinks = $activationLinks.add( mw.libs.commons.ui.addEditLink('#chunked upload', "upload new version (chunked)", 'e-chunkedupload-overwrite', "Overwrite file with another one using chunked uploading") ); |
|||
$activationLinks = $( '<a>', { |
|||
} else if (mw.config.get('wgCanonicalNamespace') === 'File') { |
|||
text: " (chunked upload)" |
|||
var title, validTitle; |
|||
} ) |
|||
.attr( { |
|||
title = mw.config.get('wgTitle'); |
|||
href: '#chunked upload' |
|||
validTitle = new mw.Title(title); |
|||
} ) |
|||
.insertAfter( $reuploadLink ); |
|||
$activationLinks = $activationLinks.add( |
|||
validTitle = validTitle.ext.length |
|||
mw.libs.commons.ui.addEditLink( |
|||
&& !/(?:\/|\#|\:)/.test(title); |
|||
'#chunked upload', |
|||
} catch(ex) {} |
|||
"upload new version (chunked)", |
|||
if (validTitle) { |
|||
'e-chunkedupload-overwrite', |
|||
$activationLinks = $( mw.libs.commons.ui.addEditLink('#chunked upload', "upload (chunked)", 'e-chunkedupload-overwrite', "Create new file using chunked uploading") ); |
|||
"Overwrite file with another one using chunked uploading" ) ); |
|||
modeNewFile = true; |
|||
} else if ( mw.config.get( 'wgCanonicalNamespace' ) === 'File' ) { |
|||
var title, validTitle; |
|||
try { |
|||
title = mw.config.get( 'wgTitle' ); |
|||
validTitle = new mw.Title( title ); |
|||
validTitle = validTitle.getExtension().length && !/(?:\/|\#|\:)/.test( title ); |
|||
} catch ( ex ) {} |
|||
if ( validTitle ) { |
|||
$activationLinks = $( mw.libs.commons.ui.addEditLink( |
|||
'#chunked upload', |
|||
"upload (chunked)", |
|||
'e-chunkedupload-overwrite', |
|||
"Create new file using chunked uploading" ) ); |
|||
modeNewFile = true; |
|||
} |
|||
} |
} |
||
if ( $activationLinks ) $activationLinks.click( window.bigChunkedUpload ); |
|||
} |
|||
if ( mw.util.getParamValue( 'chunkedupload' ) ) window.bigChunkedUpload(); |
|||
}; |
|||
if (mw.util.getParamValue('chunkedupload')) window.bigChunkedUpload(); |
|||
}; |
|||
window.bigChunkedUpload = function(e) { |
window.bigChunkedUpload = function( e ) { |
||
if ( e ) e.preventDefault(); |
|||
if ( null === mw.loader.getState( 'mediawiki.commons.MwJSBot' ) ) { |
|||
mw.loader.implement( 'mediawiki.commons.MwJSBot', [ |
|||
"//commons.wikimedia.org/w/index.php?action=raw&ctype=text/javascript&title=User:Rillke/MwJSBot.js&_=2" |
|||
], { /*no styles*/ }, { /*no messages*/ } ); |
|||
} |
|||
}); |
|||
mw.loader.using( [ |
|||
mw.loader.using(['mediawiki.commons.MwJSBot', 'jquery.ui.dialog', 'jquery.ui.progressbar', 'jquery.ui.slider', 'mediawiki.util'], _bigChunkedUpload); |
|||
'mediawiki.commons.MwJSBot', |
|||
}; |
|||
'jquery.ui', |
|||
'mediawiki.util' ], _bigChunkedUpload ); |
|||
}; |
|||
var _bigChunkedUpload = function() { |
var _bigChunkedUpload = function() { |
||
var instanceId = 'i' + Math.round( Math.random() * 1073741824 ), |
|||
start, |
start, |
||
makeWikiLink = function(t, text) { |
makeWikiLink = function( t, text ) { |
||
return $('<a>').attr({ |
return $( '<a>' ) |
||
.attr( { |
|||
href: mw.util.getUrl(t), |
href: mw.util.getUrl( t ), |
||
target: '_blank', |
target: '_blank', |
||
title: t |
title: t |
||
}).text(text || t); |
} ) |
||
.text( text || t ); |
|||
}, |
|||
$dlg = $('<div>'), |
|||
w = Math.min($(window).width(), 1200), |
|||
$logInRequired = $('<div class="ui-state-highlight" style="display:none; cursor:pointer">') |
|||
.text("To continue uploading, please log in and click here after you did so. Script will try to resume. Error reported by server is: ").appendTo($dlg), |
|||
$progDiv = $('<div>').appendTo($dlg), |
|||
$progBar = $('<div>').css({ |
|||
width: '98%', |
|||
padding: '2px' |
|||
}).progressbar({ value: 0 }).appendTo($dlg), |
|||
$progConsole = $('<div>').css({ |
|||
'background': 'black', |
|||
'color': 'white', |
|||
'font-family': '\'Lucida Console\',Console,monospace', |
|||
'overflow': 'auto', |
|||
'width': '98%', |
|||
'height': '200px', |
|||
'border': '1px solid grey', |
|||
'padding': '2px', |
|||
'white-space': 'pre-wrap', |
|||
'resize': 'both' |
|||
}).text('Hi, ' + mw.config.get('wgUserName') + '! Thank you for testing the beta version of ').append(makeWikiLink('User:Rillke/bigChunkedUpload.js'), '.').appendTo($dlg), |
|||
pad = function(digit, number, input) { |
|||
input += ''; |
|||
return new Array(Math.max(number + 1 - input.length, 1)).join(digit) + input; |
|||
}, |
|||
$lastLogLineEndSpan, |
|||
log = function(what, time, color) { |
|||
var $logline = $('<div>').text(pad('0', 5, time) + ': ' + what); |
|||
if (color) $logline.css('color', color); |
|||
$lastLogLineEndSpan = $('<span>').appendTo($logline); |
|||
$progConsole.append($logline); |
|||
$progConsole.clearQueue().animate({ scrollTop: $progConsole.scrollTop() + $logline.position().top }, 800); |
|||
}, |
|||
logInlineProgress = function(what) { |
|||
if ($lastLogLineEndSpan) $lastLogLineEndSpan.text(what); |
|||
}, |
|||
$progTextDiv = $('<div>').text("Ready. Selecting a file will immediately start the upload.").appendTo($progDiv), |
|||
$options = $('<fieldset>').appendTo($dlg), |
|||
$optionsL = $('<legend>').text("Upload options").appendTo($options), |
|||
$czWrap = $('<div>').appendTo($options), |
|||
$czl = $('<label for="chunksize' + instanceId + '" style="display:block">').text("Chunk size: ").appendTo($czWrap), |
|||
$czlz = $('<span>').appendTo($czl), |
|||
$cz = $('<div id="chunksize' + instanceId + '">').css({ width: '98%' }).slider({ |
|||
max: 20480, |
|||
min: 500, |
|||
change: function(e, ui) { |
|||
$czlz.text(ui.value + ' KiB'); |
|||
}, |
}, |
||
$dlg = $( '<div>' ), |
|||
w = Math.min( $( window ) |
|||
.width(), 1200 ), |
|||
} |
|||
$logInRequired = $( '<div class="ui-state-highlight" style="display:none; cursor:pointer">' ) |
|||
}).slider('option', 'value', 4096).appendTo($czWrap), |
|||
.text( "To continue uploading, please log in and click here after you did so. Script will try to resume. Error reported by server is: " ) |
|||
$fnWrap = $('<div>').appendTo($options), |
|||
.appendTo( $dlg ), |
|||
$fnl = $('<label for="filename' + instanceId + '" style="display:block">').text("File name: ").appendTo($fnWrap), |
|||
$progDiv = $( '<div>' ) |
|||
$fn = $('<input type="text" style="width:98%" placeholder="File:Filename.ext" title="file name goes here" id="filename' + instanceId + '">').val(mw.config.get('wgPageName')).appendTo($fnWrap), |
|||
.appendTo( $dlg ), |
|||
$progBar = $( '<div>' ) |
|||
$suml = $('<label for="summary' + instanceId + '" style="display:block">').text(modeNewFile ? "File description" : "Summary or Reason: ").appendTo($sumWrap), |
|||
.css( { |
|||
$sum = (modeNewFile |
|||
width: '98%', |
|||
? $('<textarea style="width:98%; height: 7em;" placeholder="File description" title="file description goes here" id="summary' + instanceId + '">').appendTo($sumWrap) |
|||
padding: '2px' |
|||
: $('<input type="text" style="width:98%" placeholder="Reason/Summary" title="reason/summary go here" id="summary' + instanceId + '">').appendTo($sumWrap) ), |
|||
} ) |
|||
$fsel = $('<input type="file" id="files" name="file" style="width:98%">').appendTo($options).change(function(e) { |
|||
.progressbar( { |
|||
start = new Date(); |
|||
value: 0 |
|||
} ) |
|||
.appendTo( $dlg ), |
|||
oldOnBeforeUnload = window.onbeforeunload, |
|||
$progConsole = $( '<div>' ) |
|||
oldDocTitle = document.title, |
|||
.css( { |
|||
filename = $.ucFirst($fn.val().replace(/File:/, '').replace(/_/g, ' ')), |
|||
'background': 'black', |
|||
lastblink, |
|||
'color': 'white', |
|||
_blink = function($node) { |
|||
'font-family': '\'Lucida Console\',Console,monospace', |
|||
if (lastblink) clearTimeout(lastblink); |
|||
'overflow': 'auto', |
|||
$node.addClass('ui-state-error'); |
|||
'width': '98%', |
|||
setTimeout(function() { |
|||
'height': '200px', |
|||
$node.removeClass('ui-state-error'); |
|||
'border': '1px solid grey', |
|||
}, 1000); |
|||
'padding': '2px', |
|||
'white-space': 'pre-wrap', |
|||
'resize': 'both' |
|||
} ) |
|||
.text( 'Hi, ' + mw.config.get( 'wgUserName' ) + '! Thank you for testing version 0.0.1 of ' ) |
|||
.append( makeWikiLink( 'User:Rillke/bigChunkedUpload.js' ), '.' ) |
|||
.appendTo( $dlg ), |
|||
pad = function( digit, number, input ) { |
|||
input += ''; |
|||
return new Array( Math.max( number + 1 - input.length, 1 ) ) |
|||
.join( digit ) + input; |
|||
}, |
|||
$lastLogLineEndSpan, |
|||
log = function( what, time, color ) { |
|||
var $logline = $( '<div>' ) |
|||
.text( pad( '0', 5, time ) + ': ' + what ); |
|||
if ( color ) $logline.css( 'color', color ); |
|||
$lastLogLineEndSpan = $( '<span>' ) |
|||
.appendTo( $logline ); |
|||
$progConsole.append( $logline ); |
|||
$progConsole.clearQueue() |
|||
.animate( { |
|||
scrollTop: $progConsole.scrollTop() + $logline.position() |
|||
.top |
|||
}, 800 ); |
|||
}, |
|||
logInlineProgress = function( what ) { |
|||
if ( $lastLogLineEndSpan ) $lastLogLineEndSpan.text( what ); |
|||
}, |
|||
$progTextDiv = $( '<div>' ) |
|||
.text( "Ready. Selecting a file will immediately start the upload." ) |
|||
.appendTo( $progDiv ), |
|||
$options = $( '<fieldset>' ) |
|||
.appendTo( $dlg ), |
|||
$optionsL = $( '<legend>' ) |
|||
.text( "Upload options" ) |
|||
.appendTo( $options ), |
|||
$czWrap = $( '<div>' ) |
|||
.appendTo( $options ), |
|||
$czl = $( '<label for="chunksize' + instanceId + '" style="display:block">' ) |
|||
.text( "Chunk size: " ) |
|||
.appendTo( $czWrap ), |
|||
$czlz = $( '<span>' ) |
|||
.appendTo( $czl ), |
|||
$cz = $( '<div id="chunksize' + instanceId + '">' ) |
|||
.css( { |
|||
width: '98%' |
|||
} ) |
|||
.slider( { |
|||
max: 20480, |
|||
min: 100, |
|||
change: function( e, ui ) { |
|||
$czlz.text( ui.value + ' KiB' ); |
|||
}, |
}, |
||
slide: function( e, ui ) { |
|||
$czlz.text( ui.value + ' KiB' ); |
|||
var _onNodeClick = function() { |
|||
} |
|||
$logInRequired.unbind('click', _onNodeClick).hide(); |
|||
} ) |
|||
callWhenDone(); |
|||
.slider( 'option', 'value', 4096 ) |
|||
.appendTo( $czWrap ), |
|||
$useStashWrap = $( '<div>' ) |
|||
.appendTo( $options ), |
|||
$useStash = $( '<input type="checkbox" checked="checked" id="usestash' + instanceId + '" />' ) |
|||
.appendTo( $useStashWrap ), |
|||
$useStashL = $( '<label for="usestash' + instanceId + '">' ) |
|||
.text( " use stash and async (recommended for large videos and photos)" ) |
|||
.appendTo( $useStashWrap ), |
|||
$fnWrap = $( '<div>' ) |
|||
.appendTo( $options ), |
|||
$fnl = $( '<label for="filename' + instanceId + '" style="display:block">' ) |
|||
.text( "File name: " ) |
|||
.appendTo( $fnWrap ), |
|||
$fn = $( '<input type="text" style="width:98%" placeholder="File:Filename.ext" title="file name goes here" id="filename' + instanceId + '">' ) |
|||
.val( mw.config.get( 'wgPageName' ) ) |
|||
.appendTo( $fnWrap ), |
|||
$sumWrap = $( '<div>' ) |
|||
.appendTo( $options ), |
|||
$suml = $( '<label for="summary' + instanceId + '" style="display:block">' ) |
|||
.text( modeNewFile ? "File description" : "Summary or Reason: " ) |
|||
.appendTo( $sumWrap ), |
|||
$sum = ( modeNewFile ? $( '<textarea style="width:98%; height: 7em;" placeholder="File description" title="file description goes here" id="summary' + instanceId + '">' ) |
|||
.appendTo( $sumWrap ) : $( '<input type="text" style="width:98%" placeholder="Reason/Summary" title="reason/summary go here" id="summary' + instanceId + '">' ) |
|||
.appendTo( $sumWrap ) ), |
|||
$fsel = $( '<input type="file" id="files" name="file" style="width:98%">' ) |
|||
.appendTo( $options ) |
|||
.change( function( e ) { |
|||
start = new Date(); |
|||
var lastdate, |
|||
oldOnBeforeUnload = window.onbeforeunload, |
|||
oldDocTitle = document.title, |
|||
filename = ucFirst( $fn.val() |
|||
.replace( /File:/, '' ) |
|||
.replace( /_/g, ' ' ) ), |
|||
lastblink, |
|||
_blink = function( $node ) { |
|||
if ( lastblink ) clearTimeout( lastblink ); |
|||
$node.addClass( 'ui-state-error' ); |
|||
setTimeout( function() { |
|||
$node.removeClass( 'ui-state-error' ); |
|||
}, 1000 ); |
|||
}, |
|||
_onLogInRequired = function( err, callWhenDone ) { |
|||
var _onNodeClick = function() { |
|||
$logInRequired.unbind( 'click', _onNodeClick ) |
|||
.hide(); |
|||
callWhenDone(); |
|||
}; |
|||
$logInRequired.find( 'span' ) |
|||
.first() |
|||
.remove(); |
|||
$logInRequired.append( $( '<span>' ) |
|||
.text( err ) ) |
|||
.show() |
|||
.click( _onNodeClick ); |
|||
}, |
|||
_onUploadProgress = function( progressCalculated, date ) { |
|||
if ( !lastdate ) lastdate = start; |
|||
if ( ( date - lastdate ) < 200 && progressCalculated !== 1 ) return; |
|||
lastdate = date; |
|||
progressCalculated = Math.round( progressCalculated, 1 ); |
|||
logInlineProgress( ' Upload: ' + progressCalculated + '%' ); |
|||
}, |
|||
_updateProgressBar = function( progressCalculated, date ) { |
|||
if ( !lastdate ) lastdate = start; |
|||
if ( ( date - lastdate ) < 200 && progressCalculated !== 100 ) return; |
|||
$progBar.progressbar( 'option', 'value', progressCalculated ); |
|||
document.title = Math.round( progressCalculated ) + "% of " + filename + " uploaded - Chunked upload - Wikimedia Commons"; |
|||
}; |
}; |
||
$logInRequired.find('span').first().remove(); |
|||
if ( !filename ) return _blink( $fn ); |
|||
$logInRequired.append($('<span>').text(err)).show().click(_onNodeClick); |
|||
}, |
|||
var params = { |
|||
_onUploadProgress = function(progressCalculated, date) { |
|||
maxChunkSize: $cz.slider( 'option', 'value' ) * 1024, |
|||
if (!lastdate) lastdate = start; |
|||
retry: { |
|||
if ((date - lastdate) < 200 && progressCalculated !== 1) return; |
|||
serverError: 250 |
|||
}, |
|||
progressCalculated = Math.round(progressCalculated, 1); |
|||
title: $fn.val() |
|||
logInlineProgress(' Upload: ' + progressCalculated + '%'); |
|||
.replace( /File:/, '' ), |
|||
}, |
|||
summary: '[[c:User:Rillke/bigChunkedUpload.js]]: ' + $sum.val(), |
|||
_updateProgressBar = function(progressCalculated, date) { |
|||
useStash: $useStash.prop( 'checked' ), |
|||
if (!lastdate) lastdate = start; |
|||
async: $useStash.prop( 'checked' ), |
|||
if ((date - lastdate) < 200 && progressCalculated !== 100) return; |
|||
passToAPI: { |
|||
$progBar.progressbar('option', 'value', progressCalculated); |
|||
upload: { |
|||
document.title = Math.round(progressCalculated) + "% of " + filename + " uploaded - Chunked upload - Wikimedia Commons"; |
|||
ignorewarnings: 1 |
|||
}; |
|||
}, |
|||
finish: { |
|||
if (!filename) return _blink($fn); |
|||
ignorewarnings: 1 |
|||
} |
|||
var $def = new MwJSBot().chunkedUpload({ |
|||
maxChunkSize: $cz.slider('option', 'value') * 1024, |
|||
retry: { |
|||
serverError: 250 |
|||
}, |
|||
title: $fn.val().replace(/File:/, ''), |
|||
summary: $sum.val() +" (uploaded using [[c:User:Rillke/bigChunkedUpload.js|chunked upload script]])", |
|||
passToAPI: { |
|||
upload: { |
|||
ignorewarnings: 1 |
|||
}, |
}, |
||
callbacks: { |
|||
loginRequired: _onLogInRequired |
|||
} |
} |
||
} |
}; |
||
if ( modeNewFile ) { |
|||
params.text = $sum.val(); |
|||
loginRequired: _onLogInRequired |
|||
} |
|||
}, this.files[0]).progress(function(type, chunkinfo, txt) { |
|||
var cc = chunkinfo.currentchunk, |
|||
idIsNumber = ('number' === typeof cc.id), |
|||
curIdPlus1 = idIsNumber ? (cc.id + 1) : cc.id, |
|||
curId = idIsNumber ? cc.id : 0, |
|||
l = chunkinfo.length, |
|||
progressCalculated = ((curId)/l)*100 + (cc.progress/l), |
|||
d = new Date(), |
|||
ddiff = Math.round((d - start) / 1000), |
|||
prog = '', |
|||
color = ''; |
|||
// second term respects progress of current chunk |
|||
if (idIsNumber) _updateProgressBar(progressCalculated); |
|||
// handle these often frequently occuring events differently |
|||
if ('uploadstatus' === type) { |
|||
return _onUploadProgress(cc.progress, d); |
|||
} |
} |
||
txt = txt || cc.progressText; |
|||
prog += "Uploaded part " + curIdPlus1 + " of " + l + ";"; |
|||
prog += " Time elapsed: " + ddiff + "s ;"; |
|||
prog += " Status: " + txt; |
|||
$progTextDiv.text(prog); |
|||
switch (type) { |
|||
case 'err': |
|||
case 'stuck': |
|||
color = '#E9D977'; |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
log(curIdPlus1 + '/' + l + '> ' + txt, ddiff, color); |
|||
}).done(function() { |
|||
var txt = "DONE.", |
|||
d = new Date(), |
|||
ddiff = Math.round((d - start) / 1000); |
|||
$progDiv.text(txt); |
|||
log(txt, ddiff, '#77E9C7'); |
|||
window.onbeforeunload = oldOnBeforeUnload; |
|||
window.location.href="/https/commons.wikimedia.org/wiki/File:" + encodeURIComponent($fn.val().replace(/^File:/i,"")); |
|||
}).fail(function(txt) { |
|||
txt = "FAILED: " + txt; |
|||
var d = new Date(), |
|||
ddiff = Math.round((d - start) / 1000); |
|||
$progDiv.text(txt); |
|||
log(txt, ddiff, '#E977C7'); |
|||
window.onbeforeunload = oldOnBeforeUnload; |
|||
document.title = "FAILED! File upload failed - Chunked upload - Wikimedia Commons"; |
|||
setTimeout(function() { |
|||
document.title = oldDocTitle; |
|||
}, 10000); |
|||
}); |
|||
var $def = new MwJSBot() |
|||
$fn.add($sum).add($fsel).attr('disabled', 'disabled'); |
|||
.chunkedUpload( params, this.files[ 0 ] ) |
|||
$cz.slider('option', 'disabled', true); |
|||
.progress( function( type, chunkinfo, txt ) { |
|||
var cc = chunkinfo.currentchunk, |
|||
// Prevent leaving the page accidentally |
|||
idIsNumber = ( 'number' === typeof cc.id ), |
|||
window.onbeforeunload = function() { |
|||
curIdPlus1 = idIsNumber ? ( cc.id + 1 ) : cc.id, |
|||
return "Upload seems to be still in progress. Do you really wish to quit?"; |
|||
curId = idIsNumber ? cc.id : 0, |
|||
}; |
|||
l = chunkinfo.length, |
|||
}); |
|||
progressCalculated = ( ( curId ) / l ) * 100 + ( cc.progress / l ), |
|||
d = new Date(), |
|||
ddiff = Math.round( ( d - start ) / 1000 ), |
|||
prog = '', |
|||
color = ''; |
|||
// second term respects progress of current chunk |
|||
$dlg.dialog({ |
|||
if ( idIsNumber ) _updateProgressBar( progressCalculated ); |
|||
'title': "Overwrite existing files using Chunked Upload protocol", |
|||
//'height': $(window).height(), |
|||
// handle these often frequently occuring events differently |
|||
'width': w |
|||
if ( 'uploadstatus' === type ) { |
|||
}); |
|||
return _onUploadProgress( cc.progress, d ); |
|||
} |
|||
// Set focus to summary-field |
|||
$sum.focus(); |
|||
txt = txt || cc.progressText; |
|||
}; |
|||
prog += "Uploaded part " + curIdPlus1 + " of " + l + ";"; |
|||
prog += " Time elapsed: " + ddiff + "s ;"; |
|||
prog += " Status: " + txt; |
|||
$progTextDiv.text( prog ); |
|||
switch ( type ) { |
|||
case 'err': |
|||
case 'stuck': |
|||
color = '#E9D977'; |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
log( curIdPlus1 + '/' + l + '> ' + txt, ddiff, color ); |
|||
} ) |
|||
.done( function() { |
|||
var txt = "DONE.", |
|||
d = new Date(), |
|||
ddiff = Math.round( ( d - start ) / 1000 ); |
|||
$progDiv.text( txt ); |
|||
log( txt, ddiff, '#77E9C7' ); |
|||
window.onbeforeunload = oldOnBeforeUnload; |
|||
window.location.href="/https/commons.wikimedia.org/wiki/File:" + encodeURIComponent( $fn.val() |
|||
.replace( /^File:/i, "" ) ); |
|||
} ) |
|||
.fail( function( txt ) { |
|||
txt = "FAILED: " + txt; |
|||
var d = new Date(), |
|||
ddiff = Math.round( ( d - start ) / 1000 ); |
|||
$progDiv.text( txt ); |
|||
log( txt, ddiff, '#E977C7' ); |
|||
window.onbeforeunload = oldOnBeforeUnload; |
|||
document.title = "FAILED! File upload failed - Chunked upload - Wikimedia Commons"; |
|||
setTimeout( function() { |
|||
document.title = oldDocTitle; |
|||
}, 10000 ); |
|||
} ); |
|||
$fn.add( $sum ) |
|||
.add( $fsel ) |
|||
.add( $useStash ) |
|||
.attr( 'disabled', 'disabled' ); |
|||
$cz.slider( 'option', 'disabled', true ); |
|||
// Prevent leaving the page accidentally |
|||
window.onbeforeunload = function() { |
|||
return "Upload seems to be still in progress. Do you really wish to quit?"; |
|||
}; |
|||
} ); |
|||
$dlg.dialog( { |
|||
'title': "Overwrite existing files using Chunked Upload protocol", |
|||
//'height': $(window).height(), |
|||
'width': w |
|||
} ); |
|||
// Set focus to summary-field |
|||
$sum.focus(); |
|||
}; |
|||
// Register globally |
|||
if ( $.inArray( mw.config.get( 'wgDBname' ), [ 'commonswiki', 'commonsarchivewiki' ] ) < 0 ) { |
|||
// mw.loader.addSource has a check for source key uniqueness |
|||
// that if it fails, throws an error. |
|||
// Since I am offering many scripts, I would like to be able to register |
|||
// a source from multiple code positions. However the loader has no |
|||
// accessors to its internally maintained list of sources. Therefore |
|||
// ensure with high probabiltiy that every source key added is unique. |
|||
commonsWiki[commonwWikiKey] = "//commons.wikimedia.org/w/load.php"; |
|||
mw.loader.addSource( commonsWiki ); |
|||
// Register Commons RL modules |
|||
for (i = 0; i < modules.length; i++) { |
|||
if (mw.loader.getState( modules[i][0] ) === null) { |
|||
mw.loader.register([modules[i]]); |
|||
} |
|||
} |
|||
} |
|||
mw.loader.using(['ext.gadget.editDropdown', 'mediawiki.util'], _install); |
mw.loader.using( [ 'ext.gadget.editDropdown', 'mediawiki.util', 'mediawiki.Title' ], _install ); |
||
}(jQuery, mediaWiki)); |
}( jQuery, mediaWiki ) ); |
Latest revision as of 12:28, 13 June 2020
/*jshint curly:false*/
/*global jQuery:false, mediaWiki:false, MwJSBot:false*/
( function( $, mw, undefined ) {
'use strict';
var modeNewFile;
var i;
var random = Math.round(Math.random() * 0x1000000000);
var commonwWikiKey = "commonswiki" + random;
var commonsWiki = {};
var modules = [
[ "ext.gadget.editDropdown", "ver1_svg", [], null, commonwWikiKey ],
[ "ext.gadget.libAPI", "ver1_svg", [], null, commonwWikiKey ]
];
function ucFirst( s ) {
return s[ 0 ].toUpperCase() + s.slice( 1 );
}
var _install = function() {
var $reuploadLink = $( '#mw-imagepage-reupload-link' )
.find( 'a' ),
$activationLinks;
if ( $reuploadLink.length ) {
$activationLinks = $( '<a>', {
text: " (chunked upload)"
} )
.attr( {
href: '#chunked upload'
} )
.insertAfter( $reuploadLink );
$activationLinks = $activationLinks.add(
mw.libs.commons.ui.addEditLink(
'#chunked upload',
"upload new version (chunked)",
'e-chunkedupload-overwrite',
"Overwrite file with another one using chunked uploading" ) );
} else if ( mw.config.get( 'wgCanonicalNamespace' ) === 'File' ) {
var title, validTitle;
try {
title = mw.config.get( 'wgTitle' );
validTitle = new mw.Title( title );
validTitle = validTitle.getExtension().length && !/(?:\/|\#|\:)/.test( title );
} catch ( ex ) {}
if ( validTitle ) {
$activationLinks = $( mw.libs.commons.ui.addEditLink(
'#chunked upload',
"upload (chunked)",
'e-chunkedupload-overwrite',
"Create new file using chunked uploading" ) );
modeNewFile = true;
}
}
if ( $activationLinks ) $activationLinks.click( window.bigChunkedUpload );
if ( mw.util.getParamValue( 'chunkedupload' ) ) window.bigChunkedUpload();
};
window.bigChunkedUpload = function( e ) {
if ( e ) e.preventDefault();
if ( null === mw.loader.getState( 'mediawiki.commons.MwJSBot' ) ) {
mw.loader.implement( 'mediawiki.commons.MwJSBot', [
"//commons.wikimedia.org/w/index.php?action=raw&ctype=text/javascript&title=User:Rillke/MwJSBot.js&_=2"
], { /*no styles*/ }, { /*no messages*/ } );
}
mw.loader.using( [
'mediawiki.commons.MwJSBot',
'jquery.ui',
'mediawiki.util' ], _bigChunkedUpload );
};
var _bigChunkedUpload = function() {
var instanceId = 'i' + Math.round( Math.random() * 1073741824 ),
start,
makeWikiLink = function( t, text ) {
return $( '<a>' )
.attr( {
href: mw.util.getUrl( t ),
target: '_blank',
title: t
} )
.text( text || t );
},
$dlg = $( '<div>' ),
w = Math.min( $( window )
.width(), 1200 ),
$logInRequired = $( '<div class="ui-state-highlight" style="display:none; cursor:pointer">' )
.text( "To continue uploading, please log in and click here after you did so. Script will try to resume. Error reported by server is: " )
.appendTo( $dlg ),
$progDiv = $( '<div>' )
.appendTo( $dlg ),
$progBar = $( '<div>' )
.css( {
width: '98%',
padding: '2px'
} )
.progressbar( {
value: 0
} )
.appendTo( $dlg ),
$progConsole = $( '<div>' )
.css( {
'background': 'black',
'color': 'white',
'font-family': '\'Lucida Console\',Console,monospace',
'overflow': 'auto',
'width': '98%',
'height': '200px',
'border': '1px solid grey',
'padding': '2px',
'white-space': 'pre-wrap',
'resize': 'both'
} )
.text( 'Hi, ' + mw.config.get( 'wgUserName' ) + '! Thank you for testing version 0.0.1 of ' )
.append( makeWikiLink( 'User:Rillke/bigChunkedUpload.js' ), '.' )
.appendTo( $dlg ),
pad = function( digit, number, input ) {
input += '';
return new Array( Math.max( number + 1 - input.length, 1 ) )
.join( digit ) + input;
},
$lastLogLineEndSpan,
log = function( what, time, color ) {
var $logline = $( '<div>' )
.text( pad( '0', 5, time ) + ': ' + what );
if ( color ) $logline.css( 'color', color );
$lastLogLineEndSpan = $( '<span>' )
.appendTo( $logline );
$progConsole.append( $logline );
$progConsole.clearQueue()
.animate( {
scrollTop: $progConsole.scrollTop() + $logline.position()
.top
}, 800 );
},
logInlineProgress = function( what ) {
if ( $lastLogLineEndSpan ) $lastLogLineEndSpan.text( what );
},
$progTextDiv = $( '<div>' )
.text( "Ready. Selecting a file will immediately start the upload." )
.appendTo( $progDiv ),
$options = $( '<fieldset>' )
.appendTo( $dlg ),
$optionsL = $( '<legend>' )
.text( "Upload options" )
.appendTo( $options ),
$czWrap = $( '<div>' )
.appendTo( $options ),
$czl = $( '<label for="chunksize' + instanceId + '" style="display:block">' )
.text( "Chunk size: " )
.appendTo( $czWrap ),
$czlz = $( '<span>' )
.appendTo( $czl ),
$cz = $( '<div id="chunksize' + instanceId + '">' )
.css( {
width: '98%'
} )
.slider( {
max: 20480,
min: 100,
change: function( e, ui ) {
$czlz.text( ui.value + ' KiB' );
},
slide: function( e, ui ) {
$czlz.text( ui.value + ' KiB' );
}
} )
.slider( 'option', 'value', 4096 )
.appendTo( $czWrap ),
$useStashWrap = $( '<div>' )
.appendTo( $options ),
$useStash = $( '<input type="checkbox" checked="checked" id="usestash' + instanceId + '" />' )
.appendTo( $useStashWrap ),
$useStashL = $( '<label for="usestash' + instanceId + '">' )
.text( " use stash and async (recommended for large videos and photos)" )
.appendTo( $useStashWrap ),
$fnWrap = $( '<div>' )
.appendTo( $options ),
$fnl = $( '<label for="filename' + instanceId + '" style="display:block">' )
.text( "File name: " )
.appendTo( $fnWrap ),
$fn = $( '<input type="text" style="width:98%" placeholder="File:Filename.ext" title="file name goes here" id="filename' + instanceId + '">' )
.val( mw.config.get( 'wgPageName' ) )
.appendTo( $fnWrap ),
$sumWrap = $( '<div>' )
.appendTo( $options ),
$suml = $( '<label for="summary' + instanceId + '" style="display:block">' )
.text( modeNewFile ? "File description" : "Summary or Reason: " )
.appendTo( $sumWrap ),
$sum = ( modeNewFile ? $( '<textarea style="width:98%; height: 7em;" placeholder="File description" title="file description goes here" id="summary' + instanceId + '">' )
.appendTo( $sumWrap ) : $( '<input type="text" style="width:98%" placeholder="Reason/Summary" title="reason/summary go here" id="summary' + instanceId + '">' )
.appendTo( $sumWrap ) ),
$fsel = $( '<input type="file" id="files" name="file" style="width:98%">' )
.appendTo( $options )
.change( function( e ) {
start = new Date();
var lastdate,
oldOnBeforeUnload = window.onbeforeunload,
oldDocTitle = document.title,
filename = ucFirst( $fn.val()
.replace( /File:/, '' )
.replace( /_/g, ' ' ) ),
lastblink,
_blink = function( $node ) {
if ( lastblink ) clearTimeout( lastblink );
$node.addClass( 'ui-state-error' );
setTimeout( function() {
$node.removeClass( 'ui-state-error' );
}, 1000 );
},
_onLogInRequired = function( err, callWhenDone ) {
var _onNodeClick = function() {
$logInRequired.unbind( 'click', _onNodeClick )
.hide();
callWhenDone();
};
$logInRequired.find( 'span' )
.first()
.remove();
$logInRequired.append( $( '<span>' )
.text( err ) )
.show()
.click( _onNodeClick );
},
_onUploadProgress = function( progressCalculated, date ) {
if ( !lastdate ) lastdate = start;
if ( ( date - lastdate ) < 200 && progressCalculated !== 1 ) return;
lastdate = date;
progressCalculated = Math.round( progressCalculated, 1 );
logInlineProgress( ' Upload: ' + progressCalculated + '%' );
},
_updateProgressBar = function( progressCalculated, date ) {
if ( !lastdate ) lastdate = start;
if ( ( date - lastdate ) < 200 && progressCalculated !== 100 ) return;
$progBar.progressbar( 'option', 'value', progressCalculated );
document.title = Math.round( progressCalculated ) + "% of " + filename + " uploaded - Chunked upload - Wikimedia Commons";
};
if ( !filename ) return _blink( $fn );
var params = {
maxChunkSize: $cz.slider( 'option', 'value' ) * 1024,
retry: {
serverError: 250
},
title: $fn.val()
.replace( /File:/, '' ),
summary: '[[c:User:Rillke/bigChunkedUpload.js]]: ' + $sum.val(),
useStash: $useStash.prop( 'checked' ),
async: $useStash.prop( 'checked' ),
passToAPI: {
upload: {
ignorewarnings: 1
},
finish: {
ignorewarnings: 1
}
},
callbacks: {
loginRequired: _onLogInRequired
}
};
if ( modeNewFile ) {
params.text = $sum.val();
}
var $def = new MwJSBot()
.chunkedUpload( params, this.files[ 0 ] )
.progress( function( type, chunkinfo, txt ) {
var cc = chunkinfo.currentchunk,
idIsNumber = ( 'number' === typeof cc.id ),
curIdPlus1 = idIsNumber ? ( cc.id + 1 ) : cc.id,
curId = idIsNumber ? cc.id : 0,
l = chunkinfo.length,
progressCalculated = ( ( curId ) / l ) * 100 + ( cc.progress / l ),
d = new Date(),
ddiff = Math.round( ( d - start ) / 1000 ),
prog = '',
color = '';
// second term respects progress of current chunk
if ( idIsNumber ) _updateProgressBar( progressCalculated );
// handle these often frequently occuring events differently
if ( 'uploadstatus' === type ) {
return _onUploadProgress( cc.progress, d );
}
txt = txt || cc.progressText;
prog += "Uploaded part " + curIdPlus1 + " of " + l + ";";
prog += " Time elapsed: " + ddiff + "s ;";
prog += " Status: " + txt;
$progTextDiv.text( prog );
switch ( type ) {
case 'err':
case 'stuck':
color = '#E9D977';
break;
default:
break;
}
log( curIdPlus1 + '/' + l + '> ' + txt, ddiff, color );
} )
.done( function() {
var txt = "DONE.",
d = new Date(),
ddiff = Math.round( ( d - start ) / 1000 );
$progDiv.text( txt );
log( txt, ddiff, '#77E9C7' );
window.onbeforeunload = oldOnBeforeUnload;
window.location.href = "/wiki/File:" + encodeURIComponent( $fn.val()
.replace( /^File:/i, "" ) );
} )
.fail( function( txt ) {
txt = "FAILED: " + txt;
var d = new Date(),
ddiff = Math.round( ( d - start ) / 1000 );
$progDiv.text( txt );
log( txt, ddiff, '#E977C7' );
window.onbeforeunload = oldOnBeforeUnload;
document.title = "FAILED! File upload failed - Chunked upload - Wikimedia Commons";
setTimeout( function() {
document.title = oldDocTitle;
}, 10000 );
} );
$fn.add( $sum )
.add( $fsel )
.add( $useStash )
.attr( 'disabled', 'disabled' );
$cz.slider( 'option', 'disabled', true );
// Prevent leaving the page accidentally
window.onbeforeunload = function() {
return "Upload seems to be still in progress. Do you really wish to quit?";
};
} );
$dlg.dialog( {
'title': "Overwrite existing files using Chunked Upload protocol",
//'height': $(window).height(),
'width': w
} );
// Set focus to summary-field
$sum.focus();
};
// Register globally
if ( $.inArray( mw.config.get( 'wgDBname' ), [ 'commonswiki', 'commonsarchivewiki' ] ) < 0 ) {
// mw.loader.addSource has a check for source key uniqueness
// that if it fails, throws an error.
// Since I am offering many scripts, I would like to be able to register
// a source from multiple code positions. However the loader has no
// accessors to its internally maintained list of sources. Therefore
// ensure with high probabiltiy that every source key added is unique.
commonsWiki[commonwWikiKey] = "//commons.wikimedia.org/w/load.php";
mw.loader.addSource( commonsWiki );
// Register Commons RL modules
for (i = 0; i < modules.length; i++) {
if (mw.loader.getState( modules[i][0] ) === null) {
mw.loader.register([modules[i]]);
}
}
}
mw.loader.using( [ 'ext.gadget.editDropdown', 'mediawiki.util', 'mediawiki.Title' ], _install );
}( jQuery, mediaWiki ) );