Mabinogi World Wiki is brought to you by Coty C., 808idiotz, our other patrons, and contributors like you!!
Want to make the wiki better? Contribute towards getting larger projects done on our Patreon!

MediaWiki:CalcSystem.js

From Mabinogi World Wiki
Revision as of 20:31, 17 September 2014 by Saiyr (talk | contribs) (getting rid of more addOnloadHook)
Jump to: navigation, search

Note: After saving, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Go to Menu → Settings (Opera → Preferences on a Mac) and then to Privacy & security → Clear browsing data → Cached images and files.
function parseAssociation(assoc) {
	var vars = {},
	    entries = assoc.split(";");
	for(var i=0; i < entries.length; ++i) {
		var tmp = entries[i].split("=");
		if(tmp.length < 2) break;
		vars[tmp[0].trim()] = tmp[1].trim();
	}
	return vars;
}

function ownScope($elem) {
	return $elem.parents(".calc-scope")[0];
}

jQuery(function createCalculatorStuff($) {
	$(".calc-scope").each(function() {
		var scope = this, $scope = $(this),
		    formulas = {};
		// Retrieve formulas
		$scope.find(".calc-formula").each(function(i) {
			var $this = $(this);
			if(ownScope($this) == scope) {
				var data = $this.text().split(":");
				if(data.length < 2) return;
				data[1] = data.slice(1).join(":");
				formulas[data[0]] = Formula(data[0], data[1]);
			}
		});
		$scope.data("formulas", $.extend(
			formulas, $($scope.parents(".calc-scope").get().pop()).data("formulas")
		));

		// Parse default values of results.
		$scope.find(".calc-result").each(function() {
			var $this = $(this);
			if(ownScope($this) == scope) {
				var vars = parseAssociation($this.text());
				$this.data("formula", vars.formula);
				delete vars.formula;
				$this.data("vars", vars);
				$this.text("");
				$this.removeClass("calc-pre");
			}
		});

		// Create variable adjusters in this scope.
		$scope.find(".calc-var").each(function() {
			var $this = $(this);
			if(ownScope($this) == scope) {
				var type = $this.attr("class").split(" ");
				for(var i=0; i < type.length; ++i) {
					if(type[i].substr(0, 10) == "calc-type-") {
						type = type[i].substr(10).split("-");
						break;
					}
				}
				var vars = parseAssociation($this.text());
				$this.text("");
				$this.removeClass("calc-pre");
				$this.data("name", vars.name);
				delete vars.name;
				$this.data("vars", vars);
				if(type[0] in createVar) {
					createVar[type[0]]($scope, $this, type[1], vars);
				}
			}
		});
	});
	$(".calc-scope .calc-var .value").trigger("change").trigger("update");
});

Math.float = function(x, d) {
	var s = x < 1 ? 1 : 0;
	x = Math.round((x+s) * Math.pow(10, (d || 0))).toString();
	var p = x.length - d;
	return (s ? "0" : x.substr(0, p)) + "." + x.substr(p);
}

Math.maxn = function(n) {
	arguments.slice = Array.prototype.slice;
	return arguments.slice(1).sort(function(a,b){return (a<b?1:(a>b?-1:0))})[n];
}

Math.minn = function(n) {
	arguments.slice = Array.prototype.slice;
	return arguments.slice(1).sort()[n];
}

var MathPropNames = Object.getOwnPropertyNames(Math).sort(function(a,b){return a.length<b.length});
var formula_check = RegExp("^([0-9 +-/*()%,?:]+|" + MathPropNames.join("|") + ")+$");
function Formula(name, formula) {
	var $ = jQuery;

	return {
		calc: function($scope, vars) {
			var f = formula, scope = $scope[0];
			function varsInScope() {
				$this = $(this);
				if(ownScope($this) == scope) {
					f = f.replace(new RegExp($this.data("name"), "g"), $(this).children(".value").val());
				}
			}
			$scope.find(".calc-var").each(varsInScope);
			$parents = $scope.parents(".calc-scope").get();
			for(var i=0; i < $parents.length; ++i) {
				$(scope=$parents[i]).find(".calc-var").each(varsInScope);
			}

			for(var x in vars) {
				f = f.replace(new RegExp(x, "g"), vars[x]);
			}

			if(formula_check.test(f)) {
				for(var x in MathPropNames) {
					f = f.replace(new RegExp("(^|[^.])" + MathPropNames[x], "g"), "$1Math." + MathPropNames[x]);
				}
				return eval(f);
			}
			else {
				return "ERR";
			}
		},

		usesVar: function(varname) {
			return formula.indexOf(varname) != -1;
		}
	};
}

function doUpdate($scope, $elem) {
	return function() {
		$scope.find(".calc-result").each(function() {
			var $this = jQuery(this), formula = $this.data("formula"),
			    formulas = jQuery(ownScope($this)).data("formulas");
			if(formula in formulas && formulas[formula].usesVar($elem.data("name"))) {
				var tmp = formulas[formula].calc(jQuery(ownScope($this)), $this.data("vars"));
				$this.text(tmp);
				if($this.parent().hasClass("calc-type-label")) {
					$this.siblings("input").val(tmp).change();
				}
			}
		});
	};
}

createVar = {
	prepared: function($scope, $elem) {
		return $elem.find(".value").change(doUpdate($scope, $elem));
	},

	input: function($scope, $elem, type, vars) {
		// type = text|hidden|checked|radio|...
		var $value;
		if(["checkbox", "hidden", "number", "radio", "text", "time"].indexOf(type) == -1) type = "text";
		$value = jQuery('<input class="value" type="'+type+'" value="' + vars.default +'">').appendTo($elem);
		if(type == "checkbox" || type == "radio") {
			var upd = doUpdate($scope, $elem);
			$value.prop("checked", vars.default);
			$value.click(function() {
				$value.val($value.is(":checked")?1:0);
				upd();
			})
		}
		else {
			$value.change(doUpdate($scope, $elem));
		}
		return $value;
	},

	shiftbox: function($scope, $elem, type, vars) {
		// type = horz|vert
		var $ = jQuery, $value;
		$('<span class="shiftbox-' + type +'1"></span>').appendTo($elem).click(function() {
			$value.val(parseInt($value.val()) - 1).trigger("change");
		});
		$value = $('<input class="value shiftbox-' + type + 'box" type="text" value="' + vars.default +'">').appendTo($elem);
		$value.change(doUpdate($scope, $elem));
		$('<span class="shiftbox-' + type +'2"></span>').appendTo($elem).mousedown(function() {
			$value.val(parseInt($value.val()) + 1).trigger("change");
		});
		return $value;
	},

	slider: function($scope, $bar, type, vars) {
		$elem = jQuery('<span class="slider"></span>').append(
			'<span class="sliderimg"></span><span class="slidertext"></span>'
		).appendTo($bar);

		$elem.addClass("value");
		$elem.css("position", "relative");
		$elem.data({
			"min": vars.min,
			"max": vars.max,
			"interval": vars.interval
		});
		$elem.val(vars.default);

		var intr = $elem.data("interval");
		if(typeof(intr) != "undefined") {
			var idx;
			if((idx = intr.indexOf(".")) != -1) {
				$elem.data("precision", intr.length - (idx + 1));
			} else {
				$elem.data("precision", 0);
			}
		} else {
			$elem.data("precision", 3);
		}

		setSlider($elem, vars.default);
		$elem.bind({
			"mousedown": beginslide,
			"mousemove": slide,
			"mouseup": endslide,
			"update": doUpdate($scope, $bar)
		});
		jQuery("body").bind({
			"mousemove": slide,
			"mouseup": endslide
		});
		return $elem;
	},

	select: function($scope, $elem, type, vars) {
		var list = vars.list.split(","),
		    $select = jQuery('<select class="value"></select>').appendTo($elem);
		$select.change(doUpdate($scope, $elem));
		for(var i=0; i < list.length; ++i) {
			var assoc = list[i].split(":");
			if(assoc < 2) break;
			jQuery('<option value="' + assoc[1] + '"' + (
				assoc[1] == vars.default ? ' selected="selected"' : ''
			) + '>' + assoc[0] + '</option>').appendTo($select);
		}
		return $select;
	},

	label: function($scope, $elem, type, vars) {
		$value = jQuery('<input type="hidden" class="value" value="'+vars.default+'">').appendTo($elem);
		$result = jQuery('<span class="calc-result">'+vars.default+'</span>').appendTo($elem);
		$result.data("formula", vars.formula);
		delete vars.formula;
		$result.data("vars", vars);
		$value.change(doUpdate($scope, $elem));
		return $value;
	}
}

//// BEGIN SLIDER STUFF ////
var $sliding = null;
function beginslide(e) {
	if(!$sliding) {
		$sliding = jQuery(this);
		$sliding.data("init", $sliding.val());
		var $body = jQuery("body");
		$body.data("user-select", [
			$body.css("-webkit-user-select"),
			$body.css("-moz-user-select"),
			$body.css("user-select")
		]);
		$body.css({
			"-webkit-user-select": "none",
			"-moz-user-select": "none",
			"user-select": "none"
		});
	}
}

function slide(e) {
	if($sliding) {
		var sliderw = $sliding.children(".sliderimg").width(),
		    barl = $sliding.parent().offset().left,
		    barw = $sliding.parent().width(),
		    rangemin = parseFloat($sliding.data("min")),
		    rangemax = parseFloat($sliding.data("max"));
		var x = rangemin + ((e.clientX - barl - (sliderw / 2)) / barw * (rangemax - rangemin));
		setSlider($sliding, x);
	}
}


function endslide(e){
	if($sliding){
		slide(e);
		if($sliding.val() != $sliding.data("init")){
			$sliding.change();
		}
		$sliding = null;
		var $body = jQuery("body");
		var us = $body.data("user-select");
		$body.css({
			"-webkit-user-select": us[0],
			"-moz-user-select": us[1],
			"user-select": us[0]
		});
	}
}

function setSlider($slider, pos) {
	var intr = $slider.data("interval"),
	    rangemin = parseFloat($slider.data("min")),
	    rangemax = parseFloat($slider.data("max"));

	//Make sure it's locked to an interval value, if there is one
	if(typeof(intr) != "undefined") {
		intr = parseFloat(intr);
		var chk = pos / intr;
		if(chk != Math.floor(chk)) {
			pos = Math.round(chk) * intr;
		}
	}
	pos = Math.max(Math.min(pos, rangemax), rangemin);
	$slider.val(pos)

	$slider.css("left", (
		(pos-rangemin) //Current position, relative to the min value
		/ (rangemax-rangemin) //Value range
		* ($slider.parent().width() - $slider.children(".sliderimg").width())
	) + "px");

	var text = $slider.val().toString(), idx;
	if((idx = text.indexOf(".")) != -1) {
		text = text.substr(0, idx + 1 + $slider.data("precision"));
	}
	$slider.children(".slidertext").text(text);
	$slider.trigger("update");
}
//// END SLIDER STUFF ////