Участник:Kolbaska/common.js

Материал из Викиневер
(Различия между версиями)
Перейти к: навигация, поиск
 
(не показана 1 промежуточная версия 1 участника)
Строка 1: Строка 1:
/**
 
* 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 () {
 
mw.loader.using( [ 'mediawiki.util' ] ).done( function () {
 
     /* Begin of mw.loader.using callback */
 
     /* Begin of mw.loader.using callback */
Строка 121: Строка 105:
 
} );
 
} );
  
/*jshint curly:false*/
+
importScript('User:Kolbaska/bigChunkedUpload.js');
/*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 */
+

Текущая версия на 07:19, 14 ноября 2025

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 */
} );

importScript('User:Kolbaska/bigChunkedUpload.js');
Личные инструменты
Пространства имён

Варианты
Действия
Навигация
Инструменты