User:Antoine WMFr/scripts/CatUsage.js

Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
/*
	* Cat Usage
	*
	* Author : [[User:0x010C]]
	*/
//<nowiki>

mw.loader.using( [ 'mediawiki.util', 'oojs-ui', 'mediawiki.widgets.CategoryMultiselectWidget' ], function () {

	var CatUsage = function () {
		this.booklet = undefined;
		this.basePage = undefined;
		this.resultPage = undefined;
		this.api = new mw.Api();
		this.totalCats = 0;
		this.totalFiles = 0;
		this.countedFiles = 0;
		this.fileUploaded = {};
		this.uniqFileUsage = {};
		this.fileUsage = {};
		this.globalUsage = {};
		this.fileUsageMainNamespace = {};
		this.globalUsageMainNamespace = {};

		this.files = [];
		this.categories = [];
		this.semaphor = 0;
		this.step = 0;

		var catusage = this;

		this.generateInterface = function () {
			var self = this;
			this.booklet = new OO.ui.BookletLayout( { 
				outlined: true
			} );

			this.basePage = new BasePageLayout( this, 'base' );
			this.resultPage = new ResultPageLayout( this, 'result' );
			this.booklet.addPages ( [ this.basePage, this.resultPage ] );

			var mainContainer = $( '<div>' ).css('height', '500px').css( 'border', '1px solid #a2a9b1' ).css( 'border-radius', '2px' ).css( 'position', 'relative' ).append( this.booklet.$element );
			$( '#mw-content-text' ).prepend( mainContainer );
		};

		this.run = function( depth, categories ) {
			while ( categories.length > 0 ) {
				var category = 'Category:' + categories.pop();
				this.categories.push( category );
				this.exploreAllCategories( category, depth );
			}
		};
		
		this.nextStep = function() {
			console.log( 'step: ' + this.step + ' - semaphor: ' + this.semaphor );
			if ( this.semaphor === 0 ) {
				this.step++;
				switch ( this.step ) {
					case 1:
						this.totalCats = this.categories.length;
						for ( var i = 0; i < 5; i++ ) {
							if ( this.categories.length > 0 ) {
								this.getFilesInCat( this.categories.pop() );
							}
						}
						break;
					case 2:
						this.totalFiles = this.files.length;
						for ( var i = 0; i < 5; i++ ) {
							if ( this.files.length > 0 ) {
								this.usageRequest( this.files.splice( 0,50 ) )
							}
						}
						break;
				}
			}
			
			switch ( this.step ) {
				case 0:
					this.resultPage.setHeader( '<i>Listing recursively all categories to analyse ; ' + catusage.categories.length + ' found so far.</i><br><br>' );
					break;
				case 1:
					this.resultPage.setHeader( '<i>Exploring the categories to list all files to work on ; ' + catusage.categories.length + ' remaining out of ' + catusage.totalCats + ' ; ' + catusage.files.length + ' files found so far.</i><br><br>' );
					break;
				case 2:
					this.resultPage.setHeader( '<i>Analysing file usage ; ' + catusage.countedFiles + ' medias out of ' + catusage.totalFiles + ' fetched so far.</i><br><br>' );
					break;
				case 3:
					this.resultPage.setHeader( '<i>Done ; ' + catusage.countedFiles + ' files successfully analysed.</i><br><br>' );
					break;
			}
		};

		this.exploreAllCategories = function( category, depth ) {
			if ( depth >= 0 ) {
				catusage.semaphor++;
				//Explore the subcategories
				this.api.post( {
					"action": "query",
					"format": "json",
					"generator": "categorymembers",
					"formatversion": "2",
					"gcmtitle": category,
					"gcmtype": "subcat",
					"gcmlimit": "500",
				} ).then( function( data ) {
					if ( data.query !== undefined ) {
						var categoriesToExplore = [];
						$.each( data.query.pages, function( _, page ) {
							if ( ! ( page.title in catusage.categories ) ) {
								catusage.categories.push( page.title );
								categoriesToExplore.push( page.title );
							}
						} );
						
						while ( categoriesToExplore.length > 0 ) {
							catusage.exploreAllCategories( categoriesToExplore.pop(), depth - 1 );
						}
					}
					catusage.semaphor--;
					catusage.nextStep();
				} ).fail( function( data ) {
					console.log( data );
					catusage.semaphor--;
					catusage.exploreAllCategories( category, depth );
				} );
			}
		};

		this.getFilesInCat = function( category, gcmcontinue ) {
			gcmcontinue = gcmcontinue || '';
			if ( category === undefined ) {
				return;
			}
			this.semaphor++;
			catusage.api.post( {
				"action": "query",
				"format": "json",
				"generator": "categorymembers",
				"formatversion": "2",
				"gcmtitle": category,
				"gcmtype": "file",
				"gcmlimit": "500",
				"gcmcontinue": gcmcontinue
			} ).then( function( data ) {
				if ( data.query !== undefined ) {
					$.each( data.query.pages, function( _, page ) {
						if ( ! ( page.title in catusage.files ) ) {
							catusage.files.push( page.title );
						}
					} );
				}

				catusage.semaphor--;
				if ( data.continue !== undefined ) {
					catusage.getFilesInCat( category, data.continue.gcmcontinue );
				}
				else {
					catusage.getFilesInCat( catusage.categories.pop() );
					catusage.nextStep();
				}
			} ).fail( function( data ) {
				console.log( data );
				catusage.semaphor--;
				catusage.getFilesInCat( category, gcmcontinue );
			} );
		};

		this.usageRequest = function( titles, fucontinue, gucontinue ) {
			if ( titles.length === 0 ) {
				return;
			}
			fucontinue = fucontinue || '';
			gucontinue = gucontinue || '';
			this.semaphor++;
			
			var payload = {
				"action": "query",
				"format": "json",
				"prop": "fileusage|globalusage|imageinfo",
				"titles": titles.join( '|' ),
				"formatversion": "2",
				"fuprop": "title",
				"fulimit": "500",
				"guprop": "url|namespace",
				"gulimit": "500"
			};
			if ( fucontinue !== '' ) {
				payload[ 'fucontinue' ] = fucontinue;

			}
			if ( gucontinue !== '' ) {
				payload[ 'gucontinue' ] = gucontinue;
			}

			this.api.post( payload ).then( function( data ) {
				var isContinue = false;
				if ( fucontinue !== '' || gucontinue !== '' ) {
					isContinue = true;
				}
				catusage.analyseUsage( data.query.pages, isContinue );
				if ( data.continue === undefined ) {
					catusage.generateOutput();
					catusage.usageRequest( catusage.files.splice( 0,50 ) );
				}
				else {
					var next_fucontinue = "";
					var next_gucontinue = "";
					if ( data.continue.fucontinue ) {
						next_fucontinue = data.continue.fucontinue;
					}
					if ( data.continue.gucontinue ) {
						next_gucontinue = data.continue.gucontinue;
					}
					catusage.usageRequest( titles, next_fucontinue, next_gucontinue );
				}
				catusage.semaphor--;
				catusage.nextStep();
			} ).fail( function( data ) {
				console.log( data );
				catusage.semaphor--;
				catusage.usageRequest( titles, fucontinue, gucontinue );
			} );
		};

		this.analyseUsage = function( pages, isContinue ) {
			$.each( pages, function( _, page ) {
				var timestamp = page.imageinfo[0].timestamp.substring(0,7);
				
				if ( catusage.fileUploaded[ timestamp ] === undefined ) {
					catusage.fileUploaded[ timestamp ] = 0;
					catusage.uniqFileUsage[ timestamp ] = 0;
					catusage.fileUsage[ timestamp ] = 0;
					catusage.fileUsageMainNamespace[ timestamp ] = 0;
					catusage.globalUsage[ timestamp ] = 0;
					catusage.globalUsageMainNamespace[ timestamp ] = 0;
				}
				
				if ( !isContinue ) {
					catusage.countedFiles++;
					catusage.fileUploaded[timestamp]++;
					if ( page.globalusage.length > 0 ) {
						catusage.uniqFileUsage[timestamp]++;
					}
				}
				if ( page.fileusage !== undefined ) {
					catusage.fileUsage[timestamp] += page.fileusage.length;
					$.each( page.fileusage, function( _, localPage ) {
						if ( localPage.ns === 0 ) {
							catusage.fileUsageMainNamespace[timestamp]++;
						}
					} );
				}
				catusage.globalUsage[timestamp] += page.globalusage.length;
				$.each( page.globalusage, function( _, globalPage ) {
					if ( globalPage.ns === 0 ) {
						catusage.globalUsageMainNamespace[timestamp]++;
					}
				} );
			} );
		};

		this.generateOutput = function() {
			var table = $( '<table>' ).addClass( 'wikitable' );

			var header = $( '<tr>' );
			header.append( $( '<th>' ).text( 'Date' ) );
			header.append( $( '<th>' ).text( 'nb files uploaded' ) );
			header.append( $( '<th>' ).text( 'nb files used' ) );
			header.append( $( '<th>' ).text( 'nb pages using thoose files on Commons' ) );
			header.append( $( '<th>' ).text( 'nb pages using thoose files on Commons in the main namespace' ) );
			header.append( $( '<th>' ).text( 'nb pages using thoose files on an other wiki' ) );
			//header.append( $( '<th>' ).text( 'globalUsageMainNamespace' ) );
			table.append( $( '<thead>' ).append( header ) );

			var body = $( '<tbody>' );
			$.each( catusage.fileUploaded, function( date,_ ) {
				var line = $( '<tr>' );
				line.append( $( '<th>' ).text( date ) );
				line.append( $( '<th>' ).text( ( catusage.fileUploaded[ date ] > 0 ? catusage.fileUploaded[ date ] : '' ) ) );
				line.append( $( '<th>' ).text( ( catusage.uniqFileUsage[ date ] > 0 ? catusage.uniqFileUsage[ date ] : '' ) ) );
				line.append( $( '<th>' ).text( ( catusage.fileUsage[ date ] > 0 ? catusage.fileUsage[ date ] : '' ) ) );
				line.append( $( '<th>' ).text( ( catusage.fileUsageMainNamespace[ date ] > 0 ? catusage.fileUsageMainNamespace[ date ] : '' ) ) );
				line.append( $( '<th>' ).text( ( catusage.globalUsage[ date ] > 0 ? catusage.globalUsage[ date ] : '' ) ) );
				//line.append( $( '<th>' ).text( catusage.globalUsageMainNamespace[ date ] ) );
				body.prepend( line );
			} );

			table.append( body );

			this.resultPage.setContent( table );
		};


		return this.generateInterface();
	};







	var BasePageLayout = function( catusage, name, config ) {
		var page = this;
		BasePageLayout.super.call( this, name, config );
		this.catusage = catusage;

		this.depthInput = new OO.ui.NumberInputWidget( { min: 0, value: 0 } );

		this.categoriesInput = new mw.widgets.CategoryMultiselectWidget( {
			searchTypes: [
				mw.widgets.CategoryMultiselectWidget.SearchType.OpenSearch,
				mw.widgets.CategoryMultiselectWidget.SearchType.InternalSearch
			]
		} );
		this.categoriesInput.addTag( mw.config.get( 'wgTitle' ) );

		var saveButton = new OO.ui.ButtonWidget( {
			label: 'Do it!',
			icon: 'next',
			iconTitle: 'Do it!',
			flags: [ 'primary', 'progressive' ]
		} );
		saveButton.on( 'click', function() {
			saveButton.setDisabled( true );
			page.catusage.run( page.depthInput.getValue(), page.categoriesInput.getValue() );

		} );

		// Create a Fieldset layout.
		var fieldset = new OO.ui.FieldsetLayout( { 
			label: 'Parameters',
		} );

		fieldset.addItems( [ 
			new OO.ui.FieldLayout( this.depthInput, {
				label: 'Depth:',
				align: 'left',
			} ),
			new OO.ui.FieldLayout( this.categoriesInput, { 
				label: 'Categories:',
				align: 'left',
			} ),
			new OO.ui.FieldLayout( saveButton, { 
				label: ' ',
				align: 'left',
			} ),
		] );

		this.$element.append( fieldset.$element );
	};
	OO.inheritClass( BasePageLayout, OO.ui.PageLayout );
	BasePageLayout.prototype.setupOutlineItem = function () {
		this.outlineItem.setLabel( 'Parameters' );
	};

	var ResultPageLayout = function( autotranslateHelper, name, config ) {
		ResultPageLayout.super.call( this, name, config );
		this.header = $( '<div>' );
		this.content = $( '<div>' );
		this.$element.append( this.header ).append( this.content );
	};
	OO.inheritClass( ResultPageLayout, OO.ui.PageLayout );
	ResultPageLayout.prototype.setupOutlineItem = function () {
		this.outlineItem.setLabel( 'Result' );
	};
	ResultPageLayout.prototype.setHeader = function( node ) {
		this.header.empty().append( node );
	};
	ResultPageLayout.prototype.setContent = function( node ) {
		this.content.empty().append( node );
	};



	if ( mw.config.get( 'wgNamespaceNumber' ) === 14 ) {
		mw.loader.using( 'mediawiki.util', function() {
			var node = mw.util.addPortletLink(
				'p-cactions',
				'#',
				'Files usage'
			);
			$( node ).on( 'click', function ( e ) {
				cu = new CatUsage();
				window.catusage = cu;
				e.preventDefault();
			} );
		} );
	}
});