MediaWiki:Gadget/Twinkle/twinkleimagetraverse.js

From OpenWetWare
Jump to: navigation, search
// If TwinkleConfig aint exist.
if( typeof( TwinkleConfig ) == 'undefined' ) {
    TwinkleConfig = {};
}

/**
 TwinkleConfig.summaryAd (string)
 If ad should be added or not to summary, default [[WP:TWINKLE|TWINKLE]]
 */
if( typeof( TwinkleConfig.summaryAd ) == 'undefined' ) {
    TwinkleConfig.summaryAd = " using [[WP:TW|TW]]";
}

/**
 TwinkleConfig.deletionSummaryAd (string)
 If ad should be added or not to deletion summary, default [[WP:TWINKLE|TWINKLE]]
 */
if( typeof( TwinkleConfig.deletionSummaryAd ) == 'undefined' ) {
    TwinkleConfig.deletionSummaryAd = " using [[WP:TW|TW]]";
}

function twinkleimagetraverse() {
    if( userIsInGroup( 'sysop' ) && wgNamespaceNumber == Namespace.CATEGORY ) {

        addPortletLink( 'p-cactions', "javascript:twinkleimagetraverse.callback()", "Traverse", "tw-imagetraverse", "Traverse category", "");
    }
}
addOnloadHook(twinkleimagetraverse);

twinkleimagetraverse.basequery = {
    'action': 'query',
    'generator': 'categorymembers',
    'gcmtitle': wgPageName,
    'gcmnamespace': Namespace.IMAGE,
    'gcmlimit' : 1, 
    'prop': [ 'imageinfo', 'categories', 'revisions' ],
    'rvlimit': 20,
    'iihistory': true,
    'rvprop': [ 'user', 'size', 'flags', 'ids', 'comment', 'timestamp' ],
    'iiprop': [ 'timestamp', 'user', 'url', 'size', 'comment' ]
};
twinkleimagetraverse.callback = function() {
    var Window = new SimpleWindow( 1200, 650 );
    Window.setTitle( "Image traverse" );
    var form = new QuickForm( twinkleimagetraverse.callback.evaluate );
    form.append( {
            type: 'button',
            label: 'Skip',
            event: twinkleimagetraverse.callbacks.skip
        } );
    form.append( {
            type: 'button',
            label: 'Delete',
            event: twinkleimagetraverse.callbacks.deleteMain
        } );
    form.append( {
            type: 'input',
            label: 'Reason',
            name: 'reason',
            value: 'Speedy deleted',
            size: 80
        } );
    form.append( {
            type: 'checkbox',
            list: [
                {
                    label: 'Remove image instances to the image',
                    name: 'unlink',
                    value: 'unlink',
                    checked: true
                }
            ]
        } );
    var root = document.createElement( 'table' );

    root.style.background = 'transparent';
    root.style.height = '780px';
    var row = root.appendChild( document.createElement( 'tr' ) );
    var options = row.appendChild(  document.createElement( 'td' ) );
    options.setAttribute( 'colspan', 2 );
    var rendered = form.render();
    options.appendChild( rendered );

    rendered.root = root;

    
    options.style.borderBottom = '1px solid gray';
    options.style.height = '80px';
    var row = root.appendChild( document.createElement( 'tr' ) );
    var oview = row.appendChild(  document.createElement( 'td' ) );
    var ohistbox = row.appendChild(  document.createElement( 'td' ) );
    ohistbox.style.width = '250px';
    ohistbox.style.verticalAlign = 'top';
    var histbox = ohistbox.appendChild(  document.createElement( 'div' ) );
    histbox.style.overflow = 'auto';
    histbox.style.height = '500px';
    oview.style.verticalAlign = 'top';
    var view = oview.appendChild(  document.createElement( 'div' ) );
    view.style.height = '500px';
    view.style.overflow = 'auto';
    var row = root.appendChild( document.createElement( 'tr' ) );
    var ostatus = row.appendChild(  document.createElement( 'td' ) );
    ostatus.style.borderTop = '1px solid gray';
    ostatus.setAttribute( 'colspan', 2 );
    var status = ostatus.appendChild(  document.createElement( 'div' ) );
    ostatus.style.verticalAlign = 'top';
    status.style.height = '180px';
    status.style.overflow = 'auto';
    Wikipedia.actionCompleted.event = function() {} // just avoid it
    var wikipedia_api = new Wikipedia.api( 'Grabbing images', twinkleimagetraverse.basequery, twinkleimagetraverse.callbacks.main );
    wikipedia_api.params = { root:root, view:view, histbox:histbox, status:status, Window:Window };
    root.params = wikipedia_api.params;
    wikipedia_api.post();

    Status.init( status );
    Window.setContent( root );
    Window.display();
}

twinkleimagetraverse.callback.evaluate = function() {
}

function make_wikilink( page, title, oldid, diff ) {
    var query = {
        'title': page,
        'diff': diff,
        'oldid': oldid
    }
    var url = wgScriptPath + '/index.php?' + QueryString.create( query );
    var a = document.createElement( 'a' );
    a.setAttribute( 'href', url );
    a.setAttribute( 'title', page );
    a.appendChild( document.createTextNode( title ) );
    return a;
}

twinkleimagetraverse.callbacks = {
    main: function( self ) {
        var xmlDoc = self.responseXML;

        var image = xmlDoc.evaluate( '//pages/page/@title', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue;

        if( !image ) {
            alert( 'no more images' );
            return;
        }
        var next = xmlDoc.evaluate( '//query-continue/categorymembers/@gcmcontinue', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue;
        var pagehistory = xmlDoc.evaluate( '//pages/page/revisions/rev', xmlDoc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );
        var filehistory = xmlDoc.evaluate( '//pages/page/imageinfo/ii', xmlDoc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );
        var categories = xmlDoc.evaluate( '//pages/page/categories/cl', xmlDoc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );

        var pagehistorylist = document.createElement( 'ul' );
        var filehistorylist = document.createElement( 'ul' );
        var categorylist = document.createElement( 'ul' );

        var entry = document.createElement( 'li' );

        for( var i = 0; i < pagehistory.snapshotLength; ++i ) {
            var cur = pagehistory.snapshotItem(i);
            var tmp = entry.cloneNode(false);
            tmp.appendChild( make_wikilink( image, cur.getAttribute( 'timestamp' ), cur.getAttribute( 'revid' ) ) );
            tmp.appendChild( document.createTextNode( ' ' ) );
            tmp.appendChild( make_wikilink( 'User:' + cur.getAttribute( 'user' ), cur.getAttribute( 'user' ) ) );
            tmp.appendChild( document.createTextNode( ' \(' + ( new Bytes( cur.getAttribute( 'size' ) ) ).toString() + '\) \(' ) );
            tmp.appendChild( document.createElement( 'em' ) ).appendChild(document.createTextNode( cur.getAttribute( 'comment' ) ) );
            tmp.appendChild( document.createTextNode( '\)' ) );
            pagehistorylist.appendChild( tmp );
        }
        
        for( var i = 0; i < filehistory.snapshotLength; ++i ) {
            var cur = filehistory.snapshotItem(i);
            var tmp = entry.cloneNode(false);
            var link = document.createElement( 'a' );
            link.setAttribute( 'href', cur.getAttribute( 'url' ) );
            link.appendChild( document.createTextNode( cur.getAttribute( 'timestamp' ) ) );
            tmp.appendChild( link );
            tmp.appendChild( document.createTextNode( ' ' ) );
            tmp.appendChild( make_wikilink( 'User:' + cur.getAttribute( 'user' ), cur.getAttribute( 'user' ) ) );
            tmp.appendChild( document.createTextNode( ' \(' + ( new Bytes( cur.getAttribute( 'size' ) ) ).toString() + '\) \(' ) );
            tmp.appendChild( document.createElement( 'em' ) ).appendChild(document.createTextNode( cur.getAttribute( 'comment' ) ) );
            tmp.appendChild( document.createTextNode( '\)' ) );
            filehistorylist.appendChild( tmp );
        }

        for( var i = 0; i < categories.snapshotLength; ++i ) {
            var cur = categories.snapshotItem(i);
            var tmp = entry.cloneNode(false);
            tmp.appendChild( make_wikilink( cur.getAttribute( 'title' ), cur.getAttribute( 'title' ).replace( /Category:/, '' ) ) );
            categorylist.appendChild( tmp );
        }
        self.params.next = next;
        self.params.image = image;
        var hist = self.params.histbox;
        while( hist.hasChildNodes() ) {
            hist.removeChild( hist.lastChild );
        }
        hist.appendChild( document.createElement( 'h2' ) ).appendChild( document.createTextNode( 'Image usage' ) );
        var placeholder = hist.appendChild( document.createElement( 'div' ));
        placeholder.appendChild( document.createTextNode( 'Grabbing data...' ) );
        self.params.imageusageplaceholder = placeholder;
        hist.appendChild( document.createElement( 'h2' ) ).appendChild( document.createTextNode( 'Page history' ) );
        hist.appendChild( pagehistorylist );
        hist.appendChild( document.createElement( 'h2' ) ).appendChild( document.createTextNode( 'File history' ) );
        hist.appendChild( filehistorylist );
        hist.appendChild( document.createElement( 'h2' ) ).appendChild( document.createTextNode( 'Categories' ) );
        hist.appendChild( categorylist );

        var query = {
            'action': 'parse',
            'title': image,
            'text': '\{\{Wikipedia:WikiProject User scripts/Scripts/Twinkle/Template|' + image.replace(/^File:/, '') + '\}\}',
            'prop': 'text'
        }
        var wikipedia_api = new Wikipedia.api( 'Rendering', query, twinkleimagetraverse.callbacks.render1 );
        wikipedia_api.params = self.params;
        wikipedia_api.post();
    },
    render1: function( self ) {
        var xmlDoc = self.responseXML;
        var html = xmlDoc.evaluate( '//parse/text', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue;
        self.params.view.innerHTML = html; // gah!

        // add instance usage
        var query = {
            'action': 'query',
            'list': 'imageusage',
            'iutitle': self.params.image,
            'iulimit': 20,
            'iufilterredir': 'nonredirects'
        }
        var wikipedia_api = new Wikipedia.api( 'Rendering', query, twinkleimagetraverse.callbacks.render2 );
        wikipedia_api.params = self.params;
        wikipedia_api.post();
    },
    render2: function( self ) {
        var xmlDoc = self.responseXML;
        var usage = xmlDoc.evaluate( '//imageusage/iu', xmlDoc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );

        var usagelist = document.createElement( 'ul' );

        var entry = document.createElement( 'li' );

        for( var i = 0; i < usage.snapshotLength; ++i ) {
            var cur = usage.snapshotItem(i);
            var tmp = entry.cloneNode(false);
            tmp.appendChild( make_wikilink( cur.getAttribute( 'title' ), cur.getAttribute( 'title' ) ) );
            usagelist.appendChild( tmp );
        }
        var hist = self.params.histbox;
        hist.replaceChild( usagelist, self.params.imageusageplaceholder );

    },
    next: function( params ) {
        twinkleimagetraverse.basequery['gcmcontinue'] = params.next;
        var wikipedia_api = new Wikipedia.api( 'Grabbing images', twinkleimagetraverse.basequery, twinkleimagetraverse.callbacks.main );
        wikipedia_api.params = params;
        wikipedia_api.post();
    },
    skip: function( event ) {
        var form = event.target.form;
        var params = form.root.params;
        twinkleimagetraverse.callbacks.next( params );
        Status.info( 'Skipped', params.image );
    },
    deleteMain: function( event ) {
        var form = event.target.form;
        var params = form.root.params;
        params.reason = form.reason.value;

        if( form.unlink.checked ) {
            var query = {
                'action': 'query',
                'list': 'imageusage',
                'titles': params.image,
                'iulimit': 5000,
                'iufilterredir': 'nonredirects'
            };
            var wikipedia_api = new Wikipedia.api( 'Grabbing image links', query, twinkleimagetraverse.callbacks.unlinkImageInstancesMain );
            wikipedia_api.params = params;

            wikipedia_api.post();
        }
        var query = { 
            'title': params.image, 
            'action': 'delete'
        };
        var wikipedia_wiki = new Wikipedia.wiki( 'Deleting image ' + params.image, query, twinkleimagetraverse.callbacks.deleteImage, function( self ) {
                twinkleimagetraverse.callbacks.next( self.params );
                self.statelem.unlink();
                Status.info( 'Deleted', self.params.image );

            });
        wikipedia_wiki.params = params;
        wikipedia_wiki.followRedirect = false;
        wikipedia_wiki.get();    
    },
    deleteImage: function( self ) {
        var form = this.responseXML.getElementById( 'deleteconfirm' );
        if( ! form ) { // Hell, image deletion is b0rked :(
            form = this.responseXML.getElementsByTagName( 'form' )[0];
            var postData = {
                'wpDeleteReasonList': 'other',
                'wpReason': "Deleted because \"" + self.params.reason + "\"." + TwinkleConfig.deletionSummaryAd,
                'wpEditToken': form.wpEditToken.value
            }
            self.post( postData );
        } else {

            var postData = {
                'wpWatch': form.wpWatch.checked ? '' : undefined,
                'wpDeleteReasonList': 'other',
                'wpReason': "Deleted because \"" + self.params.reason + "\"." + TwinkleConfig.deletionSummaryAd,
                'wpEditToken': form.wpEditToken.value
            }
            self.post( postData );
        }
    },
    unlinkImageInstancesMain: function( self ) {
        var xmlDoc = self.responseXML;
        var snapshot = xmlDoc.evaluate('//imageusage/iu/@title', xmlDoc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );

        if( snapshot.snapshotLength == 0 ) {
            return;
        }

        var statusIndicator = new Status('Unlinking instances image', '0%');

        var total = snapshot.snapshotLength * 2;

        var onsuccess = function( self ) {
            var obj = self.params.obj;
            var total = self.params.total;
            var now = parseInt( 100 * ++(self.params.current)/total ) + '%';
            obj.update( now );
            self.statelem.unlink();
            if( self.params.current >= total ) {
                obj.info( now + ' (completed)' );
                Wikipedia.removeCheckpoint();
            }
        }
        var onloaded = onsuccess;

        var onloading = function( self ) {}


        Wikipedia.addCheckpoint();
        if( snapshot.snapshotLength == 0 ) {
            statusIndicator.info( '100% (completed)' );
            Wikipedia.removeCheckpoint();
            return;
        }
        self.params.total = total;
        self.params.obj = statusIndicator;
        self.params.current =   0;

        for ( var i = 0; i < snapshot.snapshotLength; ++i ) {
            var title = snapshot.snapshotItem(i).value;
            var query = {
                'title': title,
                'action': 'submit'
            }
            var wikipedia_wiki = new Wikipedia.wiki( "Unlinking on " + title, query, twinkleimagetraverse.callbacks.unlinkImageInstances );
            var params = clone( self.params );
            params.title = title;

            wikipedia_wiki.params = params;
            wikipedia_wiki.onloading = onloading;
            wikipedia_wiki.onloaded = onloaded;
            wikipedia_wiki.onsuccess = onsuccess;
            wikipedia_wiki.get();
        }
    },
    unlinkImageInstances: function( self ) {
        var image = self.params.image.replace( /^File:/, '' );
        var form = self.responseXML.getElementById('editform');
        var text;

        if( self.params.title in twinkledeli.unlinkCache ) {
            text = twinkledeli.unlinkCache[ self.params.title ];
        } else {
            text = form.wpTextbox1.value;
        }
        var old_text = text;
        var wikiPage = new Mediawiki.Page( text );
        wikiPage.commentOutImage( image , 'Commented out because image was deleted' );

        text = wikiPage.getText();
        twinkledeli.unlinkCache[ self.params.title ] = text;
        if( text == old_text ) {
            // Nothing to do, return
            self.onsuccess( self );
            Wikipedia.actionCompleted( self );
            return;
        }
        var postData = {
            'wpMinoredit': form.wpMinoredit.checked ? '' : undefined,
            'wpWatchthis': undefined,
            'wpStarttime': form.wpStarttime.value,
            'wpEdittime': form.wpEdittime.value,
            'wpAutoSummary': form.wpAutoSummary.value,
            'wpEditToken': form.wpEditToken.value,
            'wpSummary': 'Removing instance of image ' + image + " that has been deleted because \"" + self.params.reason + "\")" + "; " + TwinkleConfig.deletionSummaryAd,
            'wpTextbox1': text
        };
        self.post( postData );
    }
}