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!

Difference between revisions of "MediaWiki:CalcSystem.js"

From Mabinogi World Wiki
Jump to: navigation, search
m (getting rid of more addOnloadHook)
Line 14: Line 14:
 
}
 
}
  
addOnloadHook(function createCalculatorStuff() {
+
jQuery(function createCalculatorStuff($) {
var $ = jQuery;
 
 
$(".calc-scope").each(function() {
 
$(".calc-scope").each(function() {
 
var scope = this, $scope = $(this),
 
var scope = this, $scope = $(this),

Revision as of 20:31, 17 September 2014

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 ////