User:Aeroid/Legendary.js

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search
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.
// [[Category:User scripts|Legendary]] <nowiki>

function Legendary() {

	var messages = {
		'en': {
			'legendary': 'Legendary',
			'button': 'Get most significant colors from this image',
			'getting-image-info': "Getting image information.",
			'analyze': 'Analyze',
			'insert': 'Insert',
			'cancel': 'Cancel',
			'no-text': 'No colors could be found in the image.'
		}
	};
	var loadingGifUrl = 'https://upload.wikimedia.org/wikipedia/commons/4/42/Loading.gif';
	var lang = mw.config.get( 'wgUserLanguage' );

	var Legendary = {};
	
	Legendary.Dialog = function legendaryDialog( config ) {
	    Legendary.Dialog.parent.call( this, config );
	};

	OO.inheritClass( Legendary.Dialog, OO.ui.ProcessDialog );

	Legendary.Dialog.static.name = 'LegendaryDialog';
	Legendary.Dialog.static.title = getMsg( 'legendary' );
	Legendary.Dialog.static.size = 'full';
	Legendary.Dialog.static.actions = [
		{ label: getMsg( 'analyze' ), 	action: 'analyze', 	flags: [ 'primary', 'progressive' ]	},
		{ label: getMsg( 'insert' ), 	action: 'insert' 	},
		{ label: getMsg( 'cancel' ), 						flags: [ 'safe', 'close' ] 	}
	];

	Legendary.Dialog.prototype.getBodyHeight = function () {
		return 600;
	};

	hasCanvas = function() {
		var c = document.createElement("canvas");
		var val = false;
		try {
			val = !!((typeof c.getContext == "function") && c.getContext("2d"));
		} catch(e) {}
		return function() {
			return val;
		};
	};

	hasCanvasImageData = function() {
		var c = document.createElement("canvas");
		var val = false;
		var ctx;
		try {
			if (typeof c.getContext == "function" && (ctx = c.getContext("2d"))) {
				val = (typeof ctx.getImageData == "function");
			}
		} catch(e) {}
		return function() {
			return val;
		};
	};

	isIE = function() {
		return !!document.all && !!window.attachEvent && !window.opera;
	};

	Legendary.Dialog.prototype.populateTestData = function ( values ) {
		values[16777215] = 129398; // rgb(255,255,255) #FFFFFF
		values[14871806] = 87658; // rgb(226,236,254) #E2ECFE 
		values[15066597] = 34031; // rgb(229,229,229) #E5E5E5 
		values[16777185] = 28879; // rgb(255,255,225) #FFFFE1 
		values[12829635] = 5197; // rgb(195,195,195) #C3C3C3 
		values[4147404] = 3042; // rgb(63,72,204) #3F48CC 
		values[8355711] = 2615; // rgb(127,127,127) #7F7F7F
	};

	Legendary.Dialog.prototype.populateData = function ( values ) {
		try {
			var canvas = this.$toAnalyzeCanvas;
			var w=parseInt(canvas.offsetWidth); // this.$toAnalyzeImg.width();
			var h=parseInt(canvas.offsetHeight); //this.$toAnalyzeImg.height();
			var ctx = canvas.getContext("2d");
			var dataDesc = ctx.getImageData(0, 0, w, h);
			var data = dataDesc.data;

			var w4 = w*4;
			var y = h;
			do {
				var offsetY = (y-1)*w4;
				var x = w;
				do {
					var offset = offsetY + (x*4-4);
					var color = (data[offset]*256+data[offset+1])*256+data[offset+2];
					values[color]++;
				} while (--x);
			} while (--y);
		} catch ( e ) {
			console.log( e );
			this.populateTestData(values);
		}
	};

	Legendary.Dialog.prototype.convertToCanvas = function (img) {
		var imageIsCanvas = (img.tagName == "CANVAS");
		if (imageIsCanvas && isIE()) {
			// Tried to process a canvas element but browser is IE
			return false;
		}

		var canvas, ctx;
		if (hasCanvas()) {
			canvas = document.createElement("canvas");
			ctx = canvas.getContext("2d");
			var w = parseInt(img.offsetWidth);
			var h = parseInt(img.offsetHeight);
			canvas.width = w;
			canvas.height = h;
			canvas.style.width = w+"px";
			canvas.style.height = h+"px";
			ctx.drawImage(img,0,0,w,h);

			// copy properties and stuff from the source image
			canvas.title = img.title;
			if (!imageIsCanvas) canvas.alt  = img.alt;
			canvas.className = img.className;
			canvas.setAttribute("style", img.getAttribute("style"));
			canvas.cssText = img.cssText;
			canvas.name = img.name;
			canvas.tabIndex = img.tabIndex;
			canvas.id = img.id;

			return canvas;
		}
		return img;
	};

	Legendary.Dialog.prototype.initialize = function () {
		Legendary.Dialog.parent.prototype.initialize.apply( this, arguments );
		this.$toAnalyzeImg =   $( '<img>' )
			.attr( 'crossorigin', 'anonymous')
			.css( 'width', '100%' );
		this.$toAnalyzeImgWrap = $( '<div>' )
			.css( 'width', '50%' )
			.append( this.$toAnalyzeImg );
		this.$toAnalyzeTextarea = $( '<textarea>' )
			.css( { width: '50%' } );
		this.$toAnalyzePanel = $( '<div>' )
			.css( { display: 'flex', height: '90%' } )
			.append( this.$toAnalyzeImgWrap, this.$toAnalyzeTextarea );
		this.$body.append( this.$toAnalyzePanel );

		this.$progressBar = new OO.ui.ProgressBarWidget( { progress: 0 } );
		var fieldset = new OO.ui.FieldsetLayout();
		fieldset.addItems( [
			new OO.ui.FieldLayout( this.$progressBar, {
				label: 'Image Analysis',
				align: 'top'
			} ),
		] );
		this.$body.append( fieldset.$element );
	};

	Legendary.Dialog.prototype.getSetupProcess = function ( data ) {
		var dialog = this;
		return Legendary.Dialog.super.prototype.getSetupProcess.call( this, data )
		.next( function () {
			dialog.pushPending();
			new mw.Api().get( {
				action: 'query',
				prop: 'imageinfo',
				titles: mw.config.get( 'wgPageName' ),
				iiprop: 'url',
				iiurlwidth: 1500
			} )
			.done( dialog.setImg.bind( dialog ) )
			.fail( dialog.setImg.bind( dialog ) )
			.always( function () { dialog.popPending(); } );
		}, this );
	};
	
	Legendary.Dialog.prototype.setCanvas = function( dialog ) {
		this.$toAnalyzeCanvas = this.convertToCanvas( this.$toAnalyzeImg[0] );
		this.$toAnalyzeImgWrap
			.append( this.$toAnalyzeCanvas );
		this.$toAnalyzeImg.remove();
	};

	Legendary.Dialog.prototype.setImg = function( response ) {
		var dialog = this;
		// Get thumb URL.
		var pageId = Object.keys( response.query.pages )[ 0 ];
		var imageUrl = response.query.pages[ pageId ].imageinfo[ 0 ].thumburl;
		var srcResult = dialog.$toAnalyzeImg.attr( 'src', imageUrl );
		dialog.$toAnalyzeImg
			.one("load", dialog.setCanvas.bind( dialog ) )
			.each( function() {
				if(this.complete) {
					$(this).load(); // For jQuery < 3.0 
					// $(this).trigger('load'); // For jQuery >= 3.0 
				}
			});
	};
	
	function hexColor( color ) {
		return "#"+("000000"+color.toString(16).toUpperCase()).slice(-6);
	}
	
	function rgbColor ( color ) {
		var rgb = color;
		var b = rgb % 256; rgb = (rgb-b)/256; 
		var g = rgb % 256; rgb = (rgb-g)/256; 
		var r = rgb % 256;
		return "rgb("+ r+","+ g+","+ b +")";
	}

	Legendary.Dialog.prototype.rankColors = function( response ) {
		var dialog = this;
		this.$progressBar.setProgress( 1/27*100 );
		// init
		var values = [];
		var j=256*256*256; do {
			values[j] = 0;
		} while (--j > 0);
		this.$progressBar.setProgress( 2/27*100 );
		// get data
		dialog.populateData( values );
		// get maximum
		var max = 0;
		j=256*256*256; do {
			if (max < values[j]) max=values[j];
			if (values[j] > 0) console.log("\t\tvalues["+ j +"] = "+ values[j] +"; /"+"/ " + rgbColor( j ) +" "+ hexColor( j ));
		} while (--j > 0);
		this.$progressBar.setProgress( 3/27*100 );
		// output top 25
		var txt="";
		var val = 0;
		var i=0; do {
			var color = 0;
			val = 0;
			j=256*256*256; do {
				if (val < values[j]) { val=values[j]; color=j; } 
			} while (--j > 0);
				var pct = Math.round((val / max) * 100);
				console.log(color +" : "+val +" : "+ pct +" : "+ rgbColor( color ) +" "+ hexColor( color ));
			if (val > 0) {
				txt += "*	{{legend|"+ hexColor( color ) +"|"+ hexColor( color ) +" "+ rgbColor( color ) +" "+pct+"%}}\n";
			}
			this.$progressBar.setProgress( (3+i)/27*100 );
			values[color]=-1;
		} while (i++ < 25 && val > 0);
		this.$progressBar.setProgress( 100 );
		dialog.$toAnalyzeTextarea.val( "Significant Colors:\n"+txt );
	};

	Legendary.Dialog.prototype.getActionProcess = function ( action ) {
		var dialog = this;
		return Legendary.Dialog.super.prototype.getActionProcess.call( this, action )
			.next( function () {
				if ( action === 'analyze' ) {
					dialog.rankColors( dialog );
				} else if ( action === 'insert' ) {
					textSelectionOpts = {
						peri: dialog.$toAnalyzeTextarea.val(),
						replace: true,
						selectPeri: false
					};
					$( '#wpTextbox1' ).textSelection( 'encapsulateSelection', textSelectionOpts );
					dialog.close();
				}
			} );
	};

	function getMsg( msg ) {
		if ( messages[ lang ] !== undefined && messages[ lang ][ msg ] !== undefined ) {
			return messages[ lang ][ msg ];
		} else if ( messages.en[ msg ] !== undefined ) {
			return messages.en[ msg ];
		} else {
			return '⟨' + msg + '⟩';
		}
	}

	function main() {
		var legendaryDialog = new Legendary.Dialog();
		OO.ui.getWindowManager().addWindows( [ legendaryDialog ] );

		$( '#wpTextbox1' ).on( 'wikiEditor-toolbar-doneInitialSections', function () {
			var legendaryButtonDetails = {
				type: 'button',
				icon: 'https://upload.wikimedia.org/wikipedia/commons/e/e2/Legendary.png',
				label: getMsg( 'legendary' ),
				action: {
					type: 'callback',
					execute: function() {
						OO.ui.getWindowManager().openWindow( legendaryDialog );
					}
				}
			};
			var legendaryButton = {
				section: 'main',
				group: 'insert',
				tools: { 'Legendary': legendaryButtonDetails }
			};
			$( "#wpTextbox1" ).wikiEditor( 'addToToolbar', legendaryButton );
			$( "a[rel='legendaryDialog']" ).css("width", "64px");
		} );
	}

	main();
}

var isEditing = $.inArray( mw.config.get( 'wgAction' ), [ 'edit', 'submit' ] ) !== -1,
	isFile = mw.config.get( 'wgCanonicalNamespace' ) === 'File';

if ( isEditing && isFile ) {
	var dependencies = [
		'oojs-ui-core',
		'oojs-ui-windows'
	];
	mw.loader.using( dependencies, $.ready ).then( Legendary );
}
// EOF </nowiki>