|
|
| Строка 1: |
Строка 1: |
| − | ( 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', [
| |
| − | "//wiki.neverlands.ru/index.php?action=raw&ctype=text/javascript&title=User:Kolbaska/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] = "//wiki.neverlands.ru/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 ) );
| |