MediaWiki:QIhelperNew.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.
function qihelper2() {
	var tempRE = /\{\{QICbotMove\|([^\}]+)\}\}/,
		imfileRE = /^\s*([Ii]mage:|[Ff]ile:)(.*)$/,
		lastCat = null,
		QIHVersion = 2,
		categories = [
			'- select -',
			'Subject/Amoeboids',
			'Subject/Animals/Amphibians',
			'Subject/Animals/Annelida',
			'Subject/Animals/Platyhelminthes',
			'Subject/Animals/Arthropods/Spiders, Mites, Horseshoe crabs (Chelicerata)',
			'Subject/Animals/Arthropods/Dragonflies and Damselflies (Odonata)',
			'Subject/Animals/Arthropods/Grasshoppers, Crickets, Mantis, Bugs etc (Hemipterodea)',
			'Subject/Animals/Arthropods/Beetles (Coleoptera)',
			'Subject/Animals/Arthropods/Ants, Bees & Wasps (Hymenoptera)',
			'Subject/Animals/Arthropods/Butterflies and Moths (Lepidoptera)',
			'Subject/Animals/Arthropods/Flies & Mosquitoes (Diptera)',
			'Subject/Animals/Arthropods/Mayflies (Ephemeroptera)',
			'Subject/Animals/Arthropods/Mecoptera',
			'Subject/Animals/Arthropods/Raphidioptera',
			'Subject/Animals/Arthropods/Other insects',
			'Subject/Animals/Arthropods/Myriapoda',
			'Subject/Animals/Arthropods/Crustaceans',
			'Subject/Animals/Birds',
			'Subject/Animals/Cnidaria',
			'Subject/Animals/Echinoderms',
			'Subject/Animals/Fish',
			'Subject/Animals/Mammals/Domesticated',
			'Subject/Animals/Mammals/Wild',
			'Subject/Animals/Mammals/Zoo',
			'Subject/Animals/Molluscs',
			'Subject/Animals/Reptiles',
			'Subject/Animated',
			'Subject/Architecture/Agricultural and Industrial',
			'Subject/Architecture/Cityscapes',
			'Subject/Architecture/Close-ups',
			'Subject/Architecture/Feudal (Castles, Palaces)',
			'Subject/Architecture/Interior',
			'Subject/Architecture/Other',
			'Subject/Architecture/Public Buildings',
			'Subject/Architecture/Religious/Churches',
			'Subject/Architecture/Religious/Other',
			'Subject/Architecture/Residential Buildings',
			'Subject/Architecture/Ruins',
			'Subject/Architecture/Towers and Masts',
			'Subject/Architecture/Transport Infrastructure/Bridges',
			'Subject/Architecture/Transport Infrastructure/Other',
			'Subject/Astronomy',
			'Subject/Events',
			'Subject/Food and drink',
			'Subject/Fungi/Fungi',
			'Subject/Fungi/Lichen',
			'Subject/Microscopic',
			'Subject/Natural phenomena',
			'Subject/Non photographic media',
			'Subject/Objects/Cameras, Optics and Microscopes',
			'Subject/Objects/Closeups of Structures',
			'Subject/Objects/Electronics & electrical',
			'Subject/Objects/Geological objects',
			'Subject/Objects/Geological objects/Fossils',
			'Subject/Objects/Geological objects/Rocks, Minerals, Elements',
			'Subject/Objects/Household Items',
			'Subject/Objects/Industrial',
			'Subject/Objects/Other',
			'Subject/Objects/Statues, Monuments and Plaques',
			'Subject/Objects/Transport and Vehicles/Aerial Trams',
			'Subject/Objects/Transport and Vehicles/Automobiles',
			'Subject/Objects/Transport and Vehicles/Balloons, Aeroplanes, Helicopters etc',
			'Subject/Objects/Transport and Vehicles/Boats and Ships',
			'Subject/Objects/Transport and Vehicles/Cycles and Motorcycles',
			'Subject/Objects/Transport and Vehicles/Other vehicles',
			'Subject/Objects/Transport and Vehicles/Railway',
			'Subject/Objects/Transport and Vehicles/Steam Powered',
			'Subject/People',
			'Subject/People/Concerts',
			'Subject/Places/Man made structures',
			'Subject/Places/Man made structures/Panorama',
			'Subject/Places/Mixed',
			'Subject/Places/Mixed/Panorama',
			'Subject/Places/Natural structures',
			'Subject/Places/Natural structures/Panorama',
			'Subject/Plant life/Ferns and Horsetails',
			'Subject/Plant life/Flowers',
			'Subject/Plant life/Foliage etc',
			'Subject/Plant life/Fruit, berries, seeds etc',
			'Subject/Plant life/Mosses and Liverworts',
			'Subject/Plant life/Trees',
			'Subject/Sports',
			'Subject/Sunsets',
			'Subject/Works of art',
			'Technical/Color',
			'Technical/Composition',
			'Technical/Depth of field',
			'Technical/Exposure',
			'Technical/Movement control',
			'Technical/Perspective',
			'Technical/Proportion'
		],
		dropdown = $('<select></select>').css('width','100%'),
		ls = 'localStorage' in window ? window.localStorage : null,
		currSel = {},
		savedSel = {},
		found = {};
 
	// restore last categorization selections
	if (ls) {
		try {
			currSel = JSON.parse(ls.getItem('QIHelper_selections')) || {};
		} catch(e) {
			ls.removeItem('QIHelper_selections');
		}
	}
 
	// build the dropdown menu prototype
	for( var key in categories ) {
		dropdown.append( $('<option></option>').text(categories[key]).attr('name',categories[key]) );
	}
	dropdown.change(function(e) {
		// remember lat used category
		lastCat = $(e.target).val();
		$('#lastCat').text(lastCat);
		// store the selected index of the current dropdown in localStorage
		if (ls) {
			var name = $(e.target).parent().data('qi_image') || null;
			currSel[name] = $('option:selected',$(e.target)).index();
			ls.setItem('QIHelper_selections', JSON.stringify(currSel));
		}
	 });

	// Generate the User Interface to replace the textbox
	function buildGallery()  {
		var textbox = $('#wpTextbox1').hide(),
			wppreview = $('#wikiPreview');
		
		if( wppreview.length === 0 ) return;
		
		$('#editpage-copywarn').hide();
		$('#toolbar').hide();
		$('#wpPreview').hide();
		
		var preview = $('<div id="qigallery"></div>')
				.insertAfter(wppreview),
			advanced = $('<div class="qihelper2adv"></div>')
				.insertAfter(wppreview);
		
		var wikitext = textbox.text(),
			lines = wikitext.split( "\n" ),
			line, lline, pipe, file, desc, img, div, link, select,
			inGallery = false,
			versionTag = '<!-- QIHELPER_VERSION='+QIHVersion+' ', versionOk = false,
			m, filematch;
		
		for (var key in lines) {
			line = lines[key];
			lline = line.toLowerCase();
			
			// check needed version
			versionOk |= line.substr(0,versionTag.length) == versionTag;

			if (lline.search('<gallery') > -1)
				inGallery = true;
			else if (lline.search('</gallery>') > -1)
				inGallery = false;
			else if (inGallery) {
				m = imfileRE.exec(line); 
				if (m !== null && m.length == 3) {
					filematch = m[2];
					pipe = filematch.indexOf('|');
					if( pipe > 0 ) {
						file = filematch.substring(0, pipe);
						desc = filematch.substring(pipe + 1);
					} else {
						file = filematch;
						desc = '';
					}
					
					// register all seen files on the page so we can prune the cache
					found[file] = true;
		
					select = dropdown.clone(true);
					div = $('<div></div>')
						.append(
							$('<a></a>').attr('href', '//commons.wikimedia.org/wiki/File:' + file)
								.append($('<img>').attr('src', '//commons.wikimedia.org/wiki/Special:Redirect/file/' + encodeURIComponent(file) + '?width=150'))
						)
						.append($('<br>'))
						.append(select)
						.click(function(e) {
							if (e.ctrlKey || e.metaKey) {
								if (lastCat) 
									$(e.currentTarget).find('select').val(lastCat);
								e.preventDefault();
							}
						});
		
					var savedCat = null;
					if (tempRE.test(desc)) {
						tempRE.exec( desc );
						savedCat = RegExp.$1;
					}
					
					var cachedCat = file in currSel ? categories[currSel[file]] : null;
		
					if (cachedCat) {
						// restore category selection from cache
						select.val(cachedCat);
						if (cachedCat === savedCat) {
							// the cache is up to date saved data
							delete currSel[file];
							div.addClass('qihelper2dne');
						} else {
							if (savedCat) {
								// conflict between set and saved category
								div.addClass('qihelper2con');
								$('option[name="' + savedCat + '"]', select).css('font-weight', 'bold');
								savedSel[file] = savedCat;
							} else {
								// no value saved yet
								div.addClass('qihelper2rst');
							}
						}
					}
					else if (savedCat) {
						// set category from saved version
						select.val(savedCat);
						div.addClass('qihelper2dne');
					}
					else {
						div.addClass('qihelper2pnd');
					}
		
					div.data('qi_image', file);
					preview.append(div);
				}
			}
		}
		
		// prune the cache and throw out irrelevant entries for old images
		for (file in currSel) {
			if (!(file in found)) {
				delete currSel[file];
			}
		}
  
		if (!versionOk) {
			preview.text('Wrong QIHelper script version loaded. Please purge your browser cache!');
		}
  
		wppreview.css('display', 'block');

		// Build advanced options menu
		advanced
			.append($('<input type="button" value="Hide processed images">').click(function(){$('div.qihelper2dne').hide()}))
			.append($('<a href="//commons.wikimedia.org/wiki/MediaWiki_talk:QIhelperNew.js#Quick_Apply_Category" target="qahelp">Quick apply</a>:&nbsp;<span id="lastCat"><i>none</i></span>'));
	}
 

	 // translate changes in the GUI back onto the wikitext of the page
	 function commitChanges() {
		var divs = $('div.qihelper2dne,div.qihelper2pnd'),
			textbox = $('#wpTextbox1'),
			wikitext = textbox.text(),
			newwikitext = '',
			lines = wikitext.split('\n'),
			line, lline, pipe, file, desc,
			inGallery = false,
			results = {},
			cntDone=0, cntAll=0,
			m, filematch;
		
		divs.each(function(i, e) {
			file=$(e).data('qi_image');
			if (file) {
				results[file] = $(e).find('select').val();
				console.log(file, results[file]);
			}
		});
	
		for (var key in lines) {
			line = lines[key];
			lline = line.toLowerCase();
			
			if (lline.search('<gallery') > -1)
				inGallery = true;
			else if (lline.search('</gallery>') > -1)
				inGallery = false;
			else if (inGallery) {
				m = imfileRE.exec(line); 
				if (m !== null && m.length == 3) {
					filematch = m[2];
					pipe = filematch.indexOf('|');
					if (pipe > 0) {
						file = filematch.substring(0, pipe);
						desc = filematch.substring(pipe + 1);
					} else {
						file = filematch;
						desc = '';
					}
					
					// already tagged?
					if (results[file]) {
						if (results[file] != '- select -' && results[file] != '-select-') {
							// change tag
							line = 'File:' + file.replace( /[\n\r]/, '' ) + '|' + '{{QICbotMove|' + results[file] + '}}' + desc.replace(tempRE, '');
							cntDone++;
						} else {
							// remove tag
							line = 'File:' + file.replace(/[\n\r]/, '');
						}
					}
					cntAll++;
				}
			}
			newwikitext += line + "\n";
		}
		textbox.text(newwikitext);
		$('#wpSummary').val('Categorizing new QIs using [[MediaWiki:QIhelperNew.js]] (' + cntDone + '/' + cntAll + ' done)');
	}

	// add css classes
	$('<style>div.qihelper2pnd { width:300px; float:left; text-align:center; margin:2px; padding:2px; border: 2px solid red }'+
		'       div.qihelper2dne { width:300px; float:left; text-align:center; margin:2px; padding:2px; border: 2px solid green }'+
		'       div.qihelper2rst { width:300px; float:left; text-align:center; margin:2px; padding:2px; border: 2px solid yellow }'+
		'       div.qihelper2con { width:300px; float:left; text-align:center; margin:2px; padding:2px; border: 2px solid orange }'+
		'       div.qihelper2adv { width:100%;  padding:2px; border: 1px solid gray; background-color: lightblue }</style>')
		.appendTo($('html > head'));

	// set up everything
	var editform = $('#editform');
	if (editform.length === 0) return;
	
	$('#wpSave,#wpDiff').click(commitChanges);
	buildGallery();
}

if (mw.config.get('wgAction') == 'edit') $(qihelper2);