User:MonkeysHK/common.js

/* jshint esversion: 5, forin: false, immed: true, indent: 4, latedef: true, newcap: true, noarg: true, undef: true, undef: true, unused: true, browser: true, jquery: true, onevar: true, eqeqeq: true, multistr: true, maxerr: 999999, -W082, -W084 /* global mw */

console.log("[Halloween Effects] Script Loading..");

var that, HalloweenEffects; window.HalloweenEffects = HalloweenEffects = that = Object.assign(this, {	N: 5, // number of sprites	H: 80, // width and height of a sprite in pixels	T: 5000, // animation time in ms	MINSEP: 0.1, // images are no closer to each other or with the edge than MINSEP times the image size	MINWAIT: 3000, // minimum delay time in ms	MAXWAIT: 7000, // maximum delay time in ms	MAXTRIES: 200, // maximum tries for program to allocate position for sprite, until displaying on original position again instead; the safeguard for performance	avoidElements: [".global-navigation", ".main-container .page", ".wds-global-footer"], // selectors for elements to avoid setting sprites onto	pause: false,	DEBUG: false,	debuggerReady: false,	$document: $(document),	init: function {		$(":root").css("--halloween-sprite-size", this.H + "px");		$(":root").css("--halloween-animation-time", this.T + "ms");

this.loaded = true, this.debugCounter = [0, 0, this.MAXTRIES + 999, -999], this.x = Array.apply(null, Array(this.N)), // empty array this.y = Array.apply(null, Array(this.N)), // empty array this.bounds = this.avoidElements.map(function (v) {				return {					selector: v,					debug: $(" "),				};			}), this.regions = Array.apply(null, Array(this.N)).map(function {				return {					debug: $(" "),				};			}), this.sprites = Array.apply(null, Array(this.N)).map(function {				return $(" ");			}), this.canvas = $(" ").append(this.sprites);

$("body").prepend(this.canvas); for (var i in this.x)			this.calculate(i); },	calculate: function (index) { if (document.visibilityState !== "visible" || this.pause) return this.waitUntilFocus.then(function {				that.calculate(index);			});

this.setbounds; var boundSep = this.H * (this.MINSEP); // minimun separation to screen height boundaries var centerSep = this.H * (this.MINSEP + 1); // minimun separation between sprites

var info = [ this.canvas.width - boundSep * 2, // info[0]: width, taking care of resizing this.canvas.height - boundSep * 2, // info[1]: height, taking care of resizing ];

var centerX = -1, centerY = -1, tries = 0;

var allBounds = [].concat(this.bounds, this.regions); do { centerX = this.rand(boundSep, info[0]), centerY = this.rand(boundSep, info[1]); } while (this.withinBounds(allBounds, centerX, centerY) && (++tries) < this.MAXTRIES);

this.debugCounter[1] += tries; if (tries < this.debugCounter[2]) this.debugCounter[2] = tries; // store minimum if (tries > this.debugCounter[3]) this.debugCounter[3] = tries; // store maximum if (++this.debugCounter[0] >= 10) { if (this.DEBUG) console.log("[HalloweenEffects Debug Mode] Last 10 Tries Average: " + this.debugCounter[1] / 10 + " Min: " + this.debugCounter[2] + " Max: " + this.debugCounter[3]); // reset counters this.debugCounter[0] = this.debugCounter[1] = 0, this.debugCounter[2] = this.MAXTRIES + 999, this.debugCounter[3] = -999; }

if (tries < this.MAXTRIES) this.x[index] = centerX, this.y[index] = centerY, this.regions[index].top = centerY - centerSep * 1, this.regions[index].left = centerX - centerSep * 1, this.regions[index].width = centerSep * 2, this.regions[index].height = centerSep * 2; else console.log("[HalloweenEffects] Setting Element " + index + " to old position.\nTry resizing your browser and/or use the 'collapse' view to get a better performance.");

if (this.prepareDebug) this.regions[index].debug.show.css({				top: this.regions[index].top + this.$document.scrollTop,				left: this.regions[index].left,				width: this.regions[index].width,				height: this.regions[index].height,			}); else this.regions[index].debug.hide;

this.set(index, this.x[index] - this.H * 0.5, this.y[index] - this.H * 0.5); },	set: function (index, x, y) { var delay = Math.floor(Math.random * this.MAXWAIT + this.MINWAIT); if (isNaN(x) || isNaN(y)) setTimeout(that.calculate.bind(null, index), delay); else setTimeout(function {				that.sprites[index].css({ left: x,					top: y + that.$document.scrollTop, }).addClass("animate");				setTimeout(function { that.sprites[index].removeClass("animate"); that.calculate(index); }, that.T);			}, delay); },	setbounds: function { var scrolltop = this.$document.scrollTop, screenHeight = this.canvas.height;

for (var i in this.bounds) { var $el = $(this.bounds[i].selector); this.bounds[i].debug.hide;

if ($el.length) { var offset = $el.offset, elmHeight = $el.innerHeight, elmWidth = $el.innerWidth; if (!(offset.top > scrolltop + screenHeight || offset.top + elmHeight < scrolltop)) { var top = Math.max(offset.top - scrolltop, 0), bottom = Math.min(offset.top + elmHeight - scrolltop, screenHeight); this.bounds[i].top = top, this.bounds[i].left = offset.left, this.bounds[i].width = elmWidth, this.bounds[i].height = bottom - top; if (this.prepareDebug) this.bounds[i].debug.show.css({							top: top + scrolltop,							left: offset.left,							width: elmWidth,							height: bottom - top,						}); }			}		}	},	withinBounds: function (allBounds, x, y) { for (var i in allBounds) { if (typeof allBounds[i] !== "undefined"				&& typeof allBounds[i].left !== "undefined"				&& typeof allBounds[i].top !== "undefined"				&& typeof allBounds[i].width !== "undefined"				&& typeof allBounds[i].height !== "undefined") { var xmin = allBounds[i].left, xmax = allBounds[i].left + allBounds[i].width, ymin = allBounds[i].top, ymax = allBounds[i].top + allBounds[i].height; if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) return true; }		}		return false; },	rand: function (min, max) { return Math.floor(Math.random * Math.floor(max)) + Math.ceil(min); },	waitUntilFocus: function { var promise = $.Deferred; if (document.visibilityState !== "visible") document.addEventListener("visibilitychange", function {				promise.resolve;			}, {				once: true			}); else if (this.pause) (function waitUntilUnpause {				if (this.pause)					setTimeout(waitUntilUnpause, 100);				else					promise.resolve;			}); else return promise.resolve; return promise; },	prepareDebug: function { if (this.DEBUG && !this.debuggerReady) { for (var i in this.x)				this.regions[i].debug.appendTo(this.canvas); for (i in this.bounds) this.bounds[i].debug.appendTo(this.canvas); this.debuggerReady = true; }		return this.DEBUG; },	// functions to be used in console: HalloweenEffects. startAll: function { this.pause = false; },	stopAll: function { this.pause = true; },	startDebug: function { this.DEBUG = true; this.canvas.addClass("debug-mode"); console.log("[Halloween Effects] Entered Debug Mode"); },	stopDebug: function { this.DEBUG = false; this.canvas.removeClass("debug-mode"); console.log("[Halloween Effects] Exited Debug Mode"); }, });

mw.loader.using(["mediawiki.api", "mediawiki.util", "mediawiki.Uri"]).then(function {	if (mw.config.get("wgAction") !== "view" || HalloweenEffects.loaded)		return;	console.log("[Halloween Effects] Initializing..");	$(" ", { rel: "stylesheet", href: new mw.Title("Gadget-HalloweenEffects.css", 8).getUrl({			action: "raw",			ctype: "text/css"		}) }).appendTo("head");	HalloweenEffects.init; });