Участник:Kolbaska/common.js
Материал из Викиневер
(Различия между версиями)
Kolbaska (обсуждение | вклад) (Новая страница: «/** * Keep code in MediaWiki:Common.js to a minimum as it is unconditionally * loaded for all users on every wiki page. If possible create a gadget that is * e…») |
Kolbaska (обсуждение | вклад) |
||
| Строка 16: | Строка 16: | ||
mw.loader.using( [ 'mediawiki.util' ] ).done( function () { | mw.loader.using( [ 'mediawiki.util' ] ).done( function () { | ||
| − | + | /* Begin of mw.loader.using callback */ | |
| − | + | /** | |
| − | + | * Map addPortletLink to mw.util | |
| − | + | * @deprecated: Use mw.util.addPortletLink instead. | |
| − | + | */ | |
| − | + | mw.log.deprecate( window, 'addPortletLink', mw.util.addPortletLink, 'Use mw.util.addPortletLink instead' ); | |
| − | + | /** | |
| − | + | * @source www.mediawiki.org/wiki/Snippets/Load_JS_and_CSS_by_URL | |
| − | + | * @rev 6 | |
| − | + | */ | |
| − | + | var extraCSS = mw.util.getParamValue( 'withCSS' ), | |
| − | + | extraJS = mw.util.getParamValue( 'withJS' ); | |
| − | + | if ( extraCSS ) { | |
| − | + | if ( extraCSS.match( /^MediaWiki:[^&<>=%#]*\.css$/ ) ) { | |
| − | + | mw.loader.load( '/index.php?title=' + extraCSS + '&action=raw&ctype=text/css', 'text/css' ); | |
| − | + | } else { | |
| − | + | mw.notify( 'Only pages from the MediaWiki namespace are allowed.', { title: 'Invalid withCSS value' } ); | |
| − | + | } | |
| − | + | } | |
| − | + | if ( extraJS ) { | |
| − | + | if ( extraJS.match( /^MediaWiki:[^&<>=%#]*\.js$/ ) ) { | |
| − | + | mw.loader.load( '/index.php?title=' + extraJS + '&action=raw&ctype=text/javascript' ); | |
| − | + | } else { | |
| − | + | mw.notify( 'Only pages from the MediaWiki namespace are allowed.', { title: 'Invalid withJS value' } ); | |
| − | + | } | |
| − | + | } | |
| − | + | /** | |
| − | + | * Collapsible tables; reimplemented with mw-collapsible | |
| − | + | * Styling is also in place to avoid FOUC | |
| − | + | * | |
| − | + | * Allows tables to be collapsed, showing only the header. See [[Help:Collapsing]]. | |
| − | + | * @version 3.0.0 (2018-05-20) | |
| − | + | * @source https://www.mediawiki.org/wiki/MediaWiki:Gadget-collapsibleTables.js | |
| − | + | * @author [[User:R. Koot]] | |
| − | + | * @author [[User:Krinkle]] | |
| − | + | * @author [[User:TheDJ]] | |
| − | + | * @deprecated Since MediaWiki 1.20: Use class="mw-collapsible" instead which | |
| − | + | * is supported in MediaWiki core. Shimmable since MediaWiki 1.32 | |
| − | + | * | |
| − | + | * @param {jQuery} $content | |
| − | + | */ | |
| − | + | function makeCollapsibleMwCollapsible( $content ) { | |
| − | + | var $tables = $content | |
| − | + | .find( 'table.collapsible:not(.mw-collapsible)' ) | |
| − | + | .addClass( 'mw-collapsible' ); | |
| − | + | $.each( $tables, function ( index, table ) { | |
| − | + | // mw.log.warn( 'This page is using the deprecated class collapsible. Please replace it with mw-collapsible.'); | |
| − | + | if ( $( table ).hasClass( 'collapsed' ) ) { | |
| − | + | $( table ).addClass( 'mw-collapsed' ); | |
| − | + | // mw.log.warn( 'This page is using the deprecated class collapsed. Please replace it with mw-collapsed.'); | |
| − | + | } | |
| − | + | } ); | |
| − | + | if ( $tables.length > 0 ) { | |
| − | + | mw.loader.using( 'jquery.makeCollapsible' ).then( function () { | |
| − | + | $tables.makeCollapsible(); | |
| − | + | } ); | |
| − | + | } | |
| − | + | } | |
| − | + | mw.hook( 'wikipage.content' ).add( makeCollapsibleMwCollapsible ); | |
| − | + | /** | |
| − | + | * Add support to mw-collapsible for autocollapse, innercollapse and outercollapse | |
| − | + | * | |
| − | + | * Maintainers: TheDJ | |
| − | + | */ | |
| − | + | function mwCollapsibleSetup( $collapsibleContent ) { | |
| − | + | var $element, | |
| − | + | $toggle, | |
| − | + | autoCollapseThreshold = 2; | |
| − | + | $.each( $collapsibleContent, function ( index, element ) { | |
| − | + | $element = $( element ); | |
| − | + | if ( $element.hasClass( 'collapsible' ) ) { | |
| − | + | $element.find( 'tr:first > th:first' ).prepend( $element.find( 'tr:first > * > .mw-collapsible-toggle' ) ); | |
| − | + | } | |
| − | + | if ( $collapsibleContent.length >= autoCollapseThreshold && $element.hasClass( 'autocollapse' ) ) { | |
| − | + | $element.data( 'mw-collapsible' ).collapse(); | |
| − | + | } else if ( $element.hasClass( 'innercollapse' ) ) { | |
| − | + | if ( $element.parents( '.outercollapse' ).length > 0 ) { | |
| − | + | $element.data( 'mw-collapsible' ).collapse(); | |
| − | + | } | |
| − | + | } | |
| − | + | // because of colored backgrounds, style the link in the text color | |
| − | + | // to ensure accessible contrast | |
| − | + | $toggle = $element.find( '.mw-collapsible-toggle' ); | |
| − | + | if ( $toggle.length ) { | |
| − | + | // Make the toggle inherit text color (Updated for T333357 2023-04-29) | |
| − | + | if ( $toggle.parent()[ 0 ].style.color ) { | |
| − | + | $toggle.css( 'color', 'inherit' ); | |
| − | + | $toggle.find( '.mw-collapsible-text' ).css( 'color', 'inherit' ); | |
| − | + | } | |
| − | + | } | |
| − | + | } ); | |
| − | + | } | |
| − | + | mw.hook( 'wikipage.collapsibleContent' ).add( mwCollapsibleSetup ); | |
| − | + | /* End of mw.loader.using callback */ | |
} ); | } ); | ||
| + | |||
| + | /*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', [ | ||
| + | "//wiki.neverlands.ru/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] = "//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 ) ); | ||
| + | |||
/* DO NOT ADD CODE BELOW THIS LINE */ | /* DO NOT ADD CODE BELOW THIS LINE */ | ||
Версия 07:01, 14 ноября 2025
/**
* Keep code in MediaWiki:Common.js to a minimum as it is unconditionally
* loaded for all users on every wiki page. If possible create a gadget that is
* enabled by default instead of adding it here (since gadgets are fully
* optimized ResourceLoader modules with possibility to add dependencies etc.)
*
* Since Common.js isn't a gadget, there is no place to declare its
* dependencies, so we have to lazy load them with mw.loader.using on demand and
* then execute the rest in the callback. In most cases these dependencies will
* be loaded (or loading) already and the callback will not be delayed. In case a
* dependency hasn't arrived yet it'll make sure those are loaded before this.
*/
/* global mw, $ */
/* jshint strict:false, browser:true */
mw.loader.using( [ 'mediawiki.util' ] ).done( function () {
/* Begin of mw.loader.using callback */
/**
* Map addPortletLink to mw.util
* @deprecated: Use mw.util.addPortletLink instead.
*/
mw.log.deprecate( window, 'addPortletLink', mw.util.addPortletLink, 'Use mw.util.addPortletLink instead' );
/**
* @source www.mediawiki.org/wiki/Snippets/Load_JS_and_CSS_by_URL
* @rev 6
*/
var extraCSS = mw.util.getParamValue( 'withCSS' ),
extraJS = mw.util.getParamValue( 'withJS' );
if ( extraCSS ) {
if ( extraCSS.match( /^MediaWiki:[^&<>=%#]*\.css$/ ) ) {
mw.loader.load( '/index.php?title=' + extraCSS + '&action=raw&ctype=text/css', 'text/css' );
} else {
mw.notify( 'Only pages from the MediaWiki namespace are allowed.', { title: 'Invalid withCSS value' } );
}
}
if ( extraJS ) {
if ( extraJS.match( /^MediaWiki:[^&<>=%#]*\.js$/ ) ) {
mw.loader.load( '/index.php?title=' + extraJS + '&action=raw&ctype=text/javascript' );
} else {
mw.notify( 'Only pages from the MediaWiki namespace are allowed.', { title: 'Invalid withJS value' } );
}
}
/**
* Collapsible tables; reimplemented with mw-collapsible
* Styling is also in place to avoid FOUC
*
* Allows tables to be collapsed, showing only the header. See [[Help:Collapsing]].
* @version 3.0.0 (2018-05-20)
* @source https://www.mediawiki.org/wiki/MediaWiki:Gadget-collapsibleTables.js
* @author [[User:R. Koot]]
* @author [[User:Krinkle]]
* @author [[User:TheDJ]]
* @deprecated Since MediaWiki 1.20: Use class="mw-collapsible" instead which
* is supported in MediaWiki core. Shimmable since MediaWiki 1.32
*
* @param {jQuery} $content
*/
function makeCollapsibleMwCollapsible( $content ) {
var $tables = $content
.find( 'table.collapsible:not(.mw-collapsible)' )
.addClass( 'mw-collapsible' );
$.each( $tables, function ( index, table ) {
// mw.log.warn( 'This page is using the deprecated class collapsible. Please replace it with mw-collapsible.');
if ( $( table ).hasClass( 'collapsed' ) ) {
$( table ).addClass( 'mw-collapsed' );
// mw.log.warn( 'This page is using the deprecated class collapsed. Please replace it with mw-collapsed.');
}
} );
if ( $tables.length > 0 ) {
mw.loader.using( 'jquery.makeCollapsible' ).then( function () {
$tables.makeCollapsible();
} );
}
}
mw.hook( 'wikipage.content' ).add( makeCollapsibleMwCollapsible );
/**
* Add support to mw-collapsible for autocollapse, innercollapse and outercollapse
*
* Maintainers: TheDJ
*/
function mwCollapsibleSetup( $collapsibleContent ) {
var $element,
$toggle,
autoCollapseThreshold = 2;
$.each( $collapsibleContent, function ( index, element ) {
$element = $( element );
if ( $element.hasClass( 'collapsible' ) ) {
$element.find( 'tr:first > th:first' ).prepend( $element.find( 'tr:first > * > .mw-collapsible-toggle' ) );
}
if ( $collapsibleContent.length >= autoCollapseThreshold && $element.hasClass( 'autocollapse' ) ) {
$element.data( 'mw-collapsible' ).collapse();
} else if ( $element.hasClass( 'innercollapse' ) ) {
if ( $element.parents( '.outercollapse' ).length > 0 ) {
$element.data( 'mw-collapsible' ).collapse();
}
}
// because of colored backgrounds, style the link in the text color
// to ensure accessible contrast
$toggle = $element.find( '.mw-collapsible-toggle' );
if ( $toggle.length ) {
// Make the toggle inherit text color (Updated for T333357 2023-04-29)
if ( $toggle.parent()[ 0 ].style.color ) {
$toggle.css( 'color', 'inherit' );
$toggle.find( '.mw-collapsible-text' ).css( 'color', 'inherit' );
}
}
} );
}
mw.hook( 'wikipage.collapsibleContent' ).add( mwCollapsibleSetup );
/* End of mw.loader.using callback */
} );
/*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', [
"//wiki.neverlands.ru/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] = "//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 ) );
/* DO NOT ADD CODE BELOW THIS LINE */