User:Rillke/MwJSBot.SVGXmlNSFixer.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.
/*global jQuery:false, mediaWiki:false, MwJSBot:false, SVGXmlNSFixer:false */
/*jshint curly:false */
/// JSHint valid

(function($, mw) {
	"use strict";

	if (null === mw.loader.getState('mediawiki.commons.MwJSBot')) mw.loader.implement('mediawiki.commons.MwJSBot', [
				"//commons.wikimedia.org/w/index.php?action=raw&ctype=text/javascript&title=User:Rillke/MwJSBot.js"
		], { /*no styles*/ }, { /*no messages*/ });

	try {
		mw.loader.register('mediawiki.commons.MwJSBot.SVGXmlNSFixer', '2013-04-03', ['mediawiki.commons.MwJSBot', 'ext.gadget.libAPI', 'mediawiki.user',
				'json'
		]); // 
	} catch (ex) { /* previously registerd */ }

	mw.loader.implement('mediawiki.commons.MwJSBot.SVGXmlNSFixer', function() {
		var jsb = new MwJSBot(),
			sxnf = function(myContinueStore, myLogStore) {
				this.lastQuery = {};
				this.cycleCounter = 0;
				this.myContinueStore = myContinueStore || "User:Rillke/botXMLNSfixer.js";
				this.myLogStore = myLogStore || "User:Rillke/botXMLNSfixer/log";
				jsb.log("Hello! I am your MwJSBot.SVGXmlNSFixer object.");
			};

		sxnf.fn = sxnf.prototype;
		$.extend(true, sxnf.fn, {
			query: {
				action: 'query',
				list: 'allimages',
				rawcontinue: 1,
				aiprop: 'mime|url|size',
				//aimime: 'image/svg+xml', // disabled in miser mode
				ailimit: 500
			},
			install: function() {
				var s = this;
				$(mw.util.addPortletLink('p-tb', '#', "Start bot", 't-startbot')).click(function(e) {
					e.preventDefault();
					s.start();
				});
			},
			start: function() {
				var s = this;
				jsb.$loadContinue(this.myContinueStore).done(function(r) {
					s.lastQueryContinue = s.loadedQueryContinue = JSON.parse(r);
					jsb.$continueQuery(s.query, {
						'query-continue': s.loadedQueryContinue
					}).done($.proxy(s.gotImages, s));
				}).fail($.proxy(s.run, s));
			},
			// First time the bot starts only
			run: function() {
				mw.libs.commons.api.query(this.query, {
					method: 'POST',
					cache: false,
					cb: $.proxy(this.gotImages, this),
					// r-result, query, text
					errCb: function(t, r, q) {
						jsb.fail("Failed starting query.");
					}
				});
			},
			gotImages: function(r, q) {
				this.svgList = $.grep(r.query.allimages, function(el) {
					return el.mime === 'image/svg+xml' && el.size < 9437184; // skip files bigger than 9MB (this will freeze the broser while parsing)
				});
				this.result = r;
				this.processedImageList();


				this.cycleCounter += this.svgList.length;
				if (this.cycleCounter > 400) {
					this.cycleCounter = 0;
					if (this.lastQueryContinue) jsb.$saveContinue(this.myContinueStore, JSON.stringify(this.lastQueryContinue));
					this.lastQueryContinue = r['query-continue'];
				}
			},
			processedImageList: function() {
				if (0 === this.svgList.length) {
					return jsb.$continueQuery(this.query, this.result).done($.proxy(this.gotImages, this));
				}
				var svgInfo = this.svgInfo = this.svgList.pop(),
					title = this.title = svgInfo.title,
					url = this.url = svgInfo.url;

				jsb.log("Downloading", title, " from ", url);

				jsb.$downloadXMLFile(url).done($.proxy(this.gotSVGRawData, this)).fail($.proxy(jsb.fail, jsb));
			},
			gotSVGRawData: function(xml) {
				if ('object' !== typeof xml) {
					jsb.$addLogline(this.myLogStore, "Invalid XML. Can't parse! [[:" + this.title + ']]', 'invalidxmlerror');
					jsb.fail("Invalid XML. Not an object! But ", typeof xml, this.title, " from ", this.url);
					return this.processedImageList();
				}
				var $xml = $(xml),
					$svg = $xml.find('svg').first();

				if (0 === $svg.length) $svg = $xml.find("svg:svg").first();
				if (0 === $svg.length) {
					jsb.warn(this.title, " does not contain an SVG elem. ", this.url);
					jsb.$addLogline(this.myLogStore, "No SVG root! [[:" + this.title + ']] [' + this.url + ' file]', 'nosvgrooterror');
					return this.processedImageList();
				}

				if (!$svg.attr("xmlns") && !$svg.attr("xmlns:svg")) {
					// default namespace/Null-namespace is not SVG!!!
					this.fixXMLNS($svg, $xml);
				} else {
					this.processedImageList();
				}
			},
			fixXMLNS: function($svg, $xml) {
				var s = this;
				// Firefox prevents retargeting the namespace when serializing the XML-DOM
				$svg.attr('randomstupidattribute', 'randomstupidvalue');
				// Why not also adding the xlink-namespace if it is not there?
				if (!$svg.attr('xmlns:xlink')) $svg.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');

				var xml = jsb.stringFrom$xml($xml)
					.replace('randomstupidattribute', 'xmlns')
					.replace('randomstupidvalue', 'http://www.w3.org/2000/svg');

				jsb.log(this.title, ' is being uploaded: ', xml);
				jsb.multipartMessageForUTF8Files()
					.appendPart('format', 'json')
					.appendPart('action', 'upload')
					.appendPart('filename', this.title)
					.appendPart('comment', 'MW-JS-BOT: Adding XMLNS attribute to <svg> node to ensure it is rendered in all browsers.')
					.appendPart('file', xml, this.title)
					.appendPart('ignorewarnings', 1)
					.appendPart('token', mw.user.tokens.get('csrfToken'))
					.$send().done(function(r) {
					s.processedImageList();
					if ('string' === typeof r) r = JSON.parse(r);
					if ('object' === typeof r) {
						if (r.upload && 'Success' === r.upload.result) {
							jsb.$addLogline(s.myLogStore, "SUCCESS: [[:" + s.title + ']].', 'success');
						} else {
							jsb.$addLogline(s.myLogStore, "Failed to re-upload [[:" + s.title + ']]. API response type error.', 'uploadnosuccesserror');
						}
					} else {
						jsb.$addLogline(s.myLogStore, "Failed to re-upload [[:" + s.title + ']]. API response type error.', 'uploadresponseerror');
					}
				}).fail(function(x) {
					jsb.fail(x);
					jsb.$addLogline(s.myLogStore, "Failed to re-upload [[:" + s.title + ']]. Server error.', 'uploadservererror');
				});
			}
		});

		window.SVGXmlNSFixer = sxnf;

		// Instantiate our new class right away
		var sxnfInst = new SVGXmlNSFixer();
		sxnfInst.install();
	}, { /*no styles*/ }, { /*no messages*/ });

	// And finally load ourself
	mw.loader.load('mediawiki.commons.MwJSBot.SVGXmlNSFixer');
}(jQuery, mediaWiki));