Jump to content

User:Indic-TechCom/Script/MoveAndReplace.js

From Meta, a Wikimedia project coordination wiki

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/*
    This is userscirpt is usefull for Move File on local wiki
    This will move file and replace its usage.

    @Author [[User:Jayprakash12345]]
    @Author from Gadget-libGlobalReplace.js and mw.libs.wikiDOM.nowikiEscaper
    @OwnBy [[meta:Indic-TechCom]]
*/

mw.loader.using( [ 'oojs-ui-windows', 'oojs-ui-widgets', 'oojs-ui-core', 'oojs-ui', 'oojs' ] ).then( function () {

    // i18n for Gadget
    var i18n_lang = mw.config.get( 'wgUserLanguage' );
    var i18nFormoveAndreplace = {
        'en' : {
            'mainTitle' : 'Move & Replace' ,
            'submit_acion' : 'Submit' ,
            'cancel_acion' : 'Cancel' ,
            'oldName' : 'Old File Name:' ,
            'newName' : 'New File Name:' ,
            'reason' : 'Reason:',
            'noredirect': 'Don\'t leave the redirect behind (Be careful)',
            'notsamename': 'New name should not same as old name.',
            'notempty': 'New name should not empty.',
            'dontClose': 'Don\'t Close the Dialog',
            'reload': 'Reload the Page',
            'reloadInst': 'Reload page When Query has stopped.',
            'didnotmove': 'Did not move :(',
            'moveFile': 'File has moved',
            'failAftermove': 'File moved, but imageusage query failed :( Please do it manually',
            'byUsing': 'By Using [[meta:Indic-TechCom/Tools|MoveAndReplace]]',
            'notDone': 'has faild to done :( Please do it manually',
            'Done': 'has done.',
            'failBeforeReQu': 'Image uses has replace, But query for redirects failed :( Please do it manually',
            'fixredirect': 'Fixed Redirect'
        },
        'hi' : {
            'mainTitle' : 'मूव & रिप्लेस' ,
            'submit_acion' : 'सबमिट' ,
            'cancel_acion' : 'रद्द करें' ,
            'oldName' : 'पुराना फ़ाइल नाम:' ,
            'newName' : 'नया फ़ाइल नाम:' ,
            'reason' : 'कारण:',
            'noredirect': 'पीछे रीडायरेक्ट न छोड़ें (सावधान रहे)',
            'notsamename': 'नया नाम पुराने नाम के समान नहीं होना चाहिए।',
            'notempty': 'नया नाम खाली नहीं होना चाहिए।',
            'dontClose': 'संवाद बंद मत करो',
            'reload': 'पृष्ठ को पुन: लोड करें',
            'reloadInst': 'पृष्ठ को फिर से लोड करें जब क्वेरी बंद हो।',
            'didnotmove': 'स्थानांतरित नहीं किया :(',
            'moveFile': 'फ़ाइल स्थानांतरित हो गया',
            'failAftermove': 'फ़ाइल स्थानांतरित हो गया, लेकिन छवि उपयोग क्वेरी विफल रही :( कृपया इसे मैन्युअल रूप से करें',
            'byUsing': '[[meta:Indic-TechCom/Tools|MoveAndReplace]] का उपयोग करके',
            'notDone': 'करने में असफल रहा है। :( कृपया इसे मैन्युअल रूप से करें',
            'Done': 'करने में सफल रहा है।',
            'failBeforeReQu': 'छवि उपयोग प्रतिस्थापित किया गया है, लेकिन रीडायरेक्ट के लिए क्वेरी विफल रही :( कृपया इसे मैन्युअल रूप से करें',
            'fixredirect': 'पुनर्निर्देशन ठीक किया'
        },
        'bn' : {
            'mainTitle' : 'স্থানান্তর ও প্রতিস্থাপন' ,
            'submit_acion' : 'জমা দিন' ,
            'cancel_acion' : 'বাতিল' ,
            'oldName' : 'চিত্রের পুরনো নাম:' ,
            'newName' : 'চিত্রের নতুন নাম:' ,
            'reason' : 'কারণ:',
            'noredirect': 'পুনর্নির্দেশ রেখে দিবেন না (সতর্ক থাকুন)',
            'notsamename': 'নতুন নামটি পুরানো নামের মত একই হওয়া উচিত নয়।',
            'notempty': 'নতুন নাম খালি হতে পারবে না।',
            'dontClose': 'এই বাক্সটি বন্ধ করবেন না',
            'reload': 'পাতাটি পুনরায় লোড করুন',
            'reloadInst': 'কোয়েরি শেষ হলে পাতাটি পুনরায় লোড করুন।',
            'didnotmove': 'স্থানান্তর করা যায়নি :(',
            'moveFile': 'চিত্র স্থানান্তর করা হয়েছে',
            'failAftermove': 'চিত্র স্থানান্তর করা হয়েছে, কিন্তু চিত্রের ব্যবহারের কোয়েরি ব্যর্থ হয়েছে :( দয়া করে হাত দিয়ে ঠিক করুন',
            'byUsing': '([[meta:Indic-TechCom/Tools|MoveAndReplace]] ব্যবহার করে)',
            'notDone': 'সম্পন্ন হতে ব্যর্থ হয়েছে :( দয়া করে হাত দিয়ে ঠিক করুন',
            'Done': 'সম্পন্ন হয়েছে',
            'failBeforeReQu': 'চিত্রের ব্যবহার প্রতিস্থাপন করা হয়েছে, কিন্তু পুনর্নিদেশের জন্য কোয়েরি ব্যর্থ হয়েছে :( দয়া করে হাত দিয়ে ঠিক করুন',
            'fixredirect': 'পুনর্নির্দেশ ঠিক করা হয়েছে'
        }
    };

    function RunMoveAndReplace(){

        var pageTitle = mw.config.get('wgTitle');
        var Api = new mw.Api();
       
        // Take from Gadget-libGlobalReplace.js
        var sanitizeFileName = function (fn) {
            return $.trim(fn.replace(/_/g, ' ')).replace(/^(?:File|Image)\:/, '');
        };

        // Take from Gadget-libGlobalReplace.js
        var getFileRegEx = function (title, prefix) {
            prefix = prefix || '[\\n\\[\\:\\=\\>\\|]\\s*';
            return new RegExp('(' + prefix + ')[' + mw.RegExp.escape(title[0].toUpperCase() + title[0].toLowerCase()) + ']' + mw.RegExp.escape(
                title.slice(1)).replace(/ /g, '[ _]'), 'g');
        };

        function MoveAndReplace( config ) {
            MoveAndReplace.super.call( this, config );
        }
        OO.inheritClass( MoveAndReplace, OO.ui.ProcessDialog );
    
        MoveAndReplace.static.title = i18nFormoveAndreplace[i18n_lang].mainTitle;
        MoveAndReplace.static.name = 'moveAndreplace';
        MoveAndReplace.static.actions = [
            { flags: [ 'primary', 'constructive' ], label: i18nFormoveAndreplace[i18n_lang].submit_acion , action: 'submit' },
            { flags: 'safe', label: i18nFormoveAndreplace[i18n_lang].cancel_acion }
        ];

        MoveAndReplace.prototype.initialize = function () {
            MoveAndReplace.super.prototype.initialize.call( this );
            this.panel = new OO.ui.PanelLayout( { padded: true, expanded: false } );
            this.content = new OO.ui.FieldsetLayout();
        
            // TextInputWidget for oldFileName, newFileName, reason
            this.oldFileName = new OO.ui.TextInputWidget( { disabled: true, value: pageTitle });
            this.newFileName = new OO.ui.TextInputWidget( { value: pageTitle,  required: true } );
            this.reason = new OO.ui.TextInputWidget( { value: '' } );

            // Add TextInputWidget in FieldLayout
            this.field1 = new OO.ui.FieldLayout( this.oldFileName, { label: i18nFormoveAndreplace[i18n_lang].oldName, align: 'top' } );
            this.field2 = new OO.ui.FieldLayout( this.newFileName, { label: i18nFormoveAndreplace[i18n_lang].newName, align: 'top' } );
            this.field3 = new OO.ui.FieldLayout( this.reason, { label: i18nFormoveAndreplace[i18n_lang].reason, align: 'top' } );

            // Add No redirect Check Widget only for sysop
            if ( $.inArray( 'sysop', mw.config.get('wgUserGroups') ) ) {
                this.notleaveredirect = new OO.ui.CheckboxInputWidget( { selected: false } );
                this.field4 = new OO.ui.FieldLayout( this.notleaveredirect, { label: i18nFormoveAndreplace[i18n_lang].noredirect, align: 'inline' } );
                this.content.addItems( [ this.field1, this.field2, this.field3, this.field4  ] );
            } else {
                this.content.addItems( [ this.field1, this.field2, this.field3 ] );
            }

            this.panel.$element.append( this.content.$element );
            this.$body.append( this.panel.$element );

        };

        MoveAndReplace.prototype.getBodyHeight = function () {
            return this.panel.$element.outerHeight( true );
        };
        
        MoveAndReplace.prototype.getActionProcess = function ( action ) {

            // Trigger for submit button
            if ( action === 'submit' ) {
                var OldFileName = this.oldFileName.value;
                var NewFileName = this.newFileName.value;
                var Reason = this.reason.value;
                var notLeaveRedirect = false;

                if ( $.inArray( 'sysop', mw.config.get('wgUserGroups') ) ) {
                    notLeaveRedirect = this.notleaveredirect.isSelected();
                }

                if ( OldFileName ==  NewFileName ) {
                    mw.notify( i18nFormoveAndreplace[i18n_lang].notsamename, { type: 'error' } );
                    return new OO.ui.Process( function () { this.close( { action: action } ); }, this );
                }

                if ( NewFileName ===  '' ) {
                    mw.notify( i18nFormoveAndreplace[i18n_lang].notempty, { type: 'error' } );
                    return new OO.ui.Process( function () { this.close( { action: action } ); }, this );
                }

                OldFileName = sanitizeFileName(OldFileName);
                NewFileName = sanitizeFileName(NewFileName);


               var dialogforResult = $('<div id="dialogforResult"></div>' ).attr('title', i18nFormoveAndreplace[i18n_lang].dontClose);

               $( dialogforResult ).append($( '<ul id="divforResult"></ul>' ));
               $("body").append( dialogforResult );
               
               $( dialogforResult ).dialog({
                    height: 300,
                    width: 400,
                    buttons: {
                            Submit: {
                            text: i18nFormoveAndreplace[i18n_lang].reload,
                            click: function(){
                                location.reload(true);
                            }
                        }
                    }
               });

               $( '#divforResult' ).append( $( '<p>' + i18nFormoveAndreplace[i18n_lang].reloadInst + '</p>' ) );
    
                Api.postWithToken( 'csrf', {
                    action: 'move',
                    from: 'File:' + OldFileName,
                    to: 'File:' + NewFileName,
                    reason: Reason,
                    watchlist: 'nochange',
                    movetalk: true,
                    noredirect: notLeaveRedirect,
                    ignorewarnings: true
                }).fail(function( move, errResp ){
                    $( '#divforResult' ).append( $( '<li style="color:red">' + i18nFormoveAndreplace[i18n_lang].didnotmove + '</li>' ) );
                }).done( function() {
                    $( '#divforResult' ).append( $( '<li style="color:green">' + i18nFormoveAndreplace[i18n_lang].moveFile + '</li>' ) );
                    Api.get({
                        action: 'query',
                        format: 'json',
                        generator: 'imageusage',
                        giufilterredir: 'nonredirects',
                        giulimit: '5000',
                        prop: 'info|revisions',
                        inprop: 'protection',
                        rvprop: 'content|timestamp',
                        giuredirect: 1,
                        giutitle: 'File:' + pageTitle
                    }).fail(function( move, errResp ){
                        $( '#divforResult' ).append( $( '<li style="color:red">' + i18nFormoveAndreplace[i18n_lang].failAftermove + '</li>' ) );
                    }).done( function (obj) {
                        var localUsage = obj.query.pages;

                        $.each(localUsage, function (id, pg) {
                            
                            var oldText = pg.revisions[0]['*'],
                                nwe1 = mw.libs.wikiDOM.nowikiEscaper(oldText),
                                newText = nwe1.secureReplace(getFileRegEx(OldFileName), '$1' + NewFileName).getText();
                                
                            var summary =  Reason + ' [[File:' + OldFileName + ']] → [[File:' + NewFileName + ']] ' + i18nFormoveAndreplace[i18n_lang].byUsing ;
                            var wpEditToken = mw.user.tokens.get( 'csrfToken' );

                            Api.post({
                                action: 'edit',
                                format: 'json',
                                title: pg.title,
                                text: newText,
                                editType: 'text',
                                watchlist: 'nochange',
                                minor: true,
                                summary: summary,
                                basetimestamp: pg.revisions[0].timestamp,
                                token: wpEditToken
                            }).fail(function( ){
                                $( '#divforResult' ).append( $( '<li style="color:red">'+ pg.title + ' ' + i18nFormoveAndreplace[i18n_lang].notDone + '</li>' ) );
                            }).done( function () { 
                                $( '#divforResult' ).append( $( '<li style="color:green">'+ pg.title + ' ' + i18nFormoveAndreplace[i18n_lang].Done + '</i>' ) );
                            });

                        });

                    });

                    // Query and for redirects
                    Api.get({
                        action: 'query',
                        format: 'json',
                        generator: 'backlinks',
                        gblfilterredir: 'redirects',
                        gbllimit: '5000',
                        prop: 'revisions',
                        rvprop: 'content',
                        rvslots: 'main',
                        gbltitle: 'File:' + pageTitle
                    }).fail(function( ){
                        $( '#divforResult' ).append( $( '<li style="color:red">'+ i18nFormoveAndreplace[i18n_lang].failBeforeReQu +'</li>' ) );
                    }).done( function(redirectResult) {

                        if ( redirectResult.query && redirectResult.query.pages ) {

                            $.each( redirectResult.query.pages, function ( id, pg ) {
                                var wpEditToken = mw.user.tokens.get( 'csrfToken' );
                                var rv = pg.revisions[ 0 ]['slots']['main'][ '*' ];

                                Api.post({
                                    action: 'edit',
                                    format: 'json',
                                    title: pg.title,
                                    text: rv.replace( OldFileName, NewFileName ),
                                    editType: 'text',
                                    watchlist: 'nochange',
                                    minor: true,
                                    summary: i18nFormoveAndreplace[i18n_lang].fixredirect,
                                    basetimestamp: pg.revisions[0].timestamp,
                                    token: wpEditToken
                                }).fail(function( ){
                                    $( '#divforResult' ).append( $( '<li style="color:red">'+ pg.title + ' ' + i18nFormoveAndreplace[i18n_lang].notDone + '</li>' ) );
                                }).done( function () { 
                                    $( '#divforResult' ).append( $( '<li style="color:green">' +  pg.title + ' ' + i18nFormoveAndreplace[i18n_lang].Done + '</i>' ) );
                                } );

                            });
                        }

                    });
                    
                });

            return new OO.ui.Process( function () { this.close( { action: action } ); }, this );
            }
            // Fallback to parent handler
            return MoveAndReplace.super.prototype.getActionProcess.call( this, action );
        };    

        var windowManager = new OO.ui.WindowManager();
        $( 'body' ).append( windowManager.$element );

        var moveAndreplace = new MoveAndReplace();

        windowManager.addWindows( [ moveAndreplace ] );
        windowManager.openWindow( moveAndreplace );

    }

    $(document).ready( function() {

        // Load module for mw.libs.wikiDOM.nowikiEscaper
        mw.loader.load( 'https://commons.wikimedia.org/w/index.php?title=MediaWiki:Gadget-libWikiDOM.js&action=raw&ctype=text/javascript' );
        mw.loader.load( 'jquery.ui' );

        // Check whether you are in file namespace or not
		if (mw.config.get('wgNamespaceNumber') != 6 ) {
            return;
        }

        // Set i18n for current user
        if ( undefined === i18nFormoveAndreplace[i18n_lang] ) {
            i18n_lang = 'en' ; 
        }
        // Check whether the page is redirect or not
        if ( mw.config.get('wgIsRedirect') === true ) {
            return;
        }

        // Check current user's 
        var usergroup = mw.config.get('wgUserGroups');
        if ( $.inArray( 'sysop', usergroup ) === -1 && $.inArray( 'filemover', usergroup ) === -1 ) {
            return;
        }

        // This is for local wikis, commons already have the bunch of script and module
        if ( mw.config.get('wgDBname') === 'commonswiki' ) {
            return;
        }

        // Add a portlet link. 
		var link = mw.util.addPortletLink(
			'p-views',
			'#',
			i18nFormoveAndreplace[i18n_lang].mainTitle
		);

        // Trigger for portlet link
		$(link).click( function( e ) {
			e.preventDefault();
			RunMoveAndReplace();
		});

    });

} );