Sixtest Wiki:API4/Core

var TW = function { "use strict"; var API = this, newObject, newList, newEvent, newUI; window.$API = API; /* Refer to this to access top API level */ this.baseURL = "/wiki/Project:API4"; this.data = {}; /* Collections of data (items, npcs, monsters, objects, etc.) */ newObject = function (p) { var Func = function {}; Func.prototype = p;		Func.prototype.add = function (name, func) { Func.prototype[name] = func; };		return new Func; };	$API.data.merge = function { var list, merge, a = [], b = [], func = function (a, b) { return (a.name > b.name ? 1 : (a.name < b.name ? -1 : 0));			};		merge = function (a, b, func) { // assumes arr1 and arr2 are sorted themselves // a and b will be undefined (!!) if it is not a valid list object or follow that structure ... a = a || []; b = b || []; var fin = [], ai = 0, bi = 0, al = a.length, bl = b.length, dFunc = function (a, b) { var rtn; if (a < b) { rtn = -1; } else if (a > b) { rtn = 1; } else { rtn = 0; }					return rtn; },				cv; func = func || dFunc; while (ai < al && bi < bl) { cv = func(a[ai], b[bi]); if (cv <= 0) { fin[fin.length] = a[ai]; ai += 1; } else if (cv > 0) { fin[fin.length] = b[bi]; bi += 1; }			}			while (ai < al) { fin[fin.length] = a[ai]; ai += 1; }			while (bi < bl) { fin[fin.length] = b[bi]; bi += 1; }			return fin; };		for (list in $API.data) { if ($API.data.hasOwnProperty(list)) { b = $API.data[list].data; a = merge(a, b, func); }		}		$API.data.all = $API.create.list("all", a); };	newList = function { return newObject({			"iterate": function (func, callback) {				var returnVals = [], data = this.data, rtn, length = data.length, i = 0;				for (i; i < length; i += 1) {					returnVals[i] = func.apply(this, [i, data[i]]);				}				if (callback !== undefined) {					rtn = callback.apply(this, [returnVals]);				} else {					rtn = returnVals;				}				return rtn;			},			"subset": function (arr, name) {				var newList, data;				data = this.query(function (d) { return $.inArray(d.name, arr) > -1; });				newList = API.create.list(name, data);				return newList;			},			"getId": function (id) {				return $API.create.list('', [ this.data[id] ]);			},			"query": function (cond, limit) {				var data = this.data, i = 0, len = data.length, output, outputData = [], results = 0;				limit = limit || Infinity;				if (typeof cond !== 'function') {					return false;				}				function itemQuery(id) {					return cond(data[id]);				}				for (i; i < len && results < limit; i += 1) {					if (itemQuery(i)) {						outputData[outputData.length] = data[i];						results += 1;					}				}				output = $API.create.list( "_temp", outputData, false );				return output;			},			"filter": function (obj) {				var data = this.data, i = 0, len = data.length, output, filtered = [];				if (typeof obj !== 'object') {					return false;				}				function itemQuery(id) {					var p, item = data[id], strength = 0, f, v, outputObj = {};					outputObj.name = data[id].name;					for (p in obj) {						if (obj.hasOwnProperty(p)) {							f = (obj[p] === undefined) ? 0 : obj[p];							v = (item[p] === undefined) ? 0 : item[p];							strength += f * v;							outputObj[p] = item[p];						}					}					outputObj.strength = strength;					return outputObj;				}				for (i; i < len; i += 1) {					filtered[i] = itemQuery(i);				}				output = $API.create.list( "_temp", filtered, true );				output.data.sort(function (a, b) { return b.strength - a.strength; });				return output;			},			"edit": function (arg1, arg2) {				var items = this.data,					format,					edit,					validate,					editm0,					editm1,					editm2,					editm3;				format = (function { // 0 - array ( [p1, p2, p3] [v1, v2, v3] ) // 1 - object ({ p1: v1, p2: v2 }) // 2 - string ("p1", "p2") // 3 - function (function (item) { return [p1, p2] }					return function (type) {						type = typeof type;						return (type !== 'function' ? (type === 'object' ? (arg1.length ? 0 : 1) : (type === 'string' ? 2 : 4)) : 3);					};				});				validate = function { var type = format(arg1); if (type === 0 && arg1.length !== arg2.length) { editm0; } else if (type === 1) { editm1; } else if (type === 2) { editm2; } else if (type === 3) { editm3; } else { edit(arg1, arg2); }				};				edit = function (arg1, arg2) { var i = 0, len1 = arg1.length; for (i; i < len1; i += 1) { if (arg1[i] !== undefined && arg2[i] !== undefined) { items[i].twEdit(arg1[i], arg2[i]); }					}				};				editm0 = function { // input is an array var fillIn, len1 = arg1.length, len2 = arg2.length; fillIn = function { var i = len2; for (i; i < len1; i += 1) { arg2[i] = arg2[i % len2]; }						len2 = arg2.length; };					if (len1 === items.length) { if (len1 !== len2) { fillIn; }						edit(arg1, arg2); }				};				editm1 = function { var property, arr1 = [], arr2 = []; for (property in arg1) { if (arg1.hasOwnProperty(property)) { arr1[arr1.length] = property; arr2[arr2.length] = arg1[property]; }					}					edit(arr1, arr2); };				editm2 = function { edit([arg1], [arg2]); };				editm3 = function { var arr1 = [], arr2 = [], arrs = [], i = 0, len = items.length; for (i; i < len; i += 1) { arrs[i] = arg1(items[i]); arr1[i] = (arrs[i] || [])[0]; arr2[i] = (arrs[i] || [])[1]; }					edit(arr1, arr2); };				// iterate over all the items validate; }		});	};	newEvent = function {		return newObject({ "fire": function { if (!(this.runonce && this.runcount > 0)) { /* Fire all listeners attached to this object */ this.listeners = this.listeners || []; var listeners = this.listeners, i = 0, len = listeners.length, rtns = []; for (i; i < len; i += 1) { rtns[i] = listeners[i]; }					this.runcount += 1; }			},			"listen": function (func) { /* Listen to this object */ this.listeners = this.listeners || []; var pos = this.listeners.length; // identifier this.listeners[pos] = func; return pos; },			"remove": function (n) { if (n !== undefined) { delete (this.listeners[n]); } else { /* Remove all event listeners */ while (this.listeners.length) { this.remove(this.listeners.length - 1); this.listeners.length -= 1; }				}			}		});	};	newUI = function (e) {		var ui = $API.ui,			arrayClear = function (arr) {				var newArr = [],					i = 0,					len = arr.length;				for (i; i < len; i += 1) {					if (arr[i] !== undefined) {						newArr[newArr.length] = arr[i];					}				}				return newArr;			},			rtnObj = newObject({ children: [], removeReferences: function { // remove the references to the object for garbage collection delete ($API.ui.data[this.dataIndex]); delete (this.parent.children[this.parentIndex]); return true; },				addClass: function (cls, check) { if ((check !== false && !this.hasClass(cls)) || check === false) { this.ele.className = this.ele.className + (this.ele.className ? ' ' : '') + cls; }					return this.ele.className; },				hasClass: function (cls) { var regex = new RegExp("\\b" + cls + "\\b"); return regex.test(this.ele.className); },				removeClass: function (cls, check) { var regex; if (check === false || this.hasClass(cls)) { regex = new RegExp("\\s+\\b" + cls + "\\b"); this.ele.className = this.ele.className.replace(regex, ''); return this.ele.className; }				},				replaceClass: function (clsr, clsa, iff) { if (iff && this.hasClass(clsr)) { this.removeClass(clsr, false); this.addClass(clsa); } else { this.removeClass(clsr); this.addClass(clsa); }					return this.ele.className; },				child: function (e) { var eleObj = newUI(e); eleObj.parentIndex = this.children.length; this.children[eleObj.parentIndex] = eleObj; eleObj.dataIndex = $API.ui.data.length; $API.ui.data[eleObj.dataIndex] = eleObj; this.ele.appendChild(eleObj.ele); eleObj.parent = this; // used for infanticide eleObj.level = this.level + 1; return eleObj; },				text: function (str) { this.ele.appendChild(document.createTextNode(str)); },				destroy: function { this.remove; $API.ui.data = arrayClear($API.ui.data); },				remove: function { var i = 0, len = this.children.length, $c; for (i; i < len; i += 1) { this.children[i].remove; //delete (this.children[this.children[i].parentIndex]); //parent.children = arrayClear(this.parent.children); }					this.children = arrayClear(this.children); this.removeChildren; this.removeReferences; return this; },				removeChildren: function { while (this.ele.hasChildNodes) { this.ele.removeChild(this.ele.lastChild); }				},				getPos: function (ele) { var posx = 0, posy = 0; ele = ele || this.ele; if (ele.offsetParent) { do { posx += ele.offsetLeft; posy += ele.offsetTop; ele = ele.offsetParent; } while (ele); return [posx, posy]; }					return false; }			});		if (e !== undefined) {			rtnObj.ele = document.createElement(e);		}		return rtnObj;	};	this.create = {		/* Object for constructor creation		 * To add an object, use API.create[myObjName] = function(arg1, ..., argN) {}		 * ... and newObject(prototype)		 */		"list": function (name, data, apply) {			var list = newList;			if (apply === undefined) {				apply = true;			}			list.data = data;			if (apply) {				API.data[name] = list;			}			return list;		},		"event": function (name, data) {			var event, defaults;			data = data || {};			API.event = API.event || {};			event = newEvent;			defaults = {				"runonce": false,				"runcount": 0			};			event.runonce = data.runonce || defaults.runonce;			event.runcount = data.runcount || defaults.runcount;			API.event[name] = event;			return event;		},		"extension": function (name, hasUI) {			API.ext = API.ext || {};			API.ext[name] = {};			if (hasUI === undefined) { hasUI = true; }			API.ext[name].ui = hasUI ? newUI : undefined; if (API.ext.State && API.ext.State.getState && API.ext.State.setState) { API.ext[name].getState = $API.ext.State.getState(name); API.ext[name].setState = $API.ext.State.setState(name); }			return API.ext[name]; },		"ui": function (name) { var contentRoot = document.getElementById("mw-content-text"), $root = newUI('div'), list = [ $root ]; $root.ele.className = 'APIRoot'; $root.level = 0; contentRoot.appendChild($root.ele); $API.ui = $API.create.list(				'ui',				list,				false			); return $API.ui; },		"stylesheet": function (css) { var e = document.createElement("style"), at = document.getElementsByTagName("head")[0]; e.type = 'text/css'; function applyCSS(css) { if (e.styleSheet) { e.styleSheet.cssText = css; } else { e.appendChild(document.createTextNode(css)); }				at.appendChild(e); return e;			} if (css.charAt(0) === '/') { // relative url $.ajax({					url: $API.baseURL + css + '?action=raw',					success: function (response) {						css = response;						applyCSS(css);					}				}); } else { applyCSS(css); }		}	};	$API.Base64 = (function {		// mostly from http://www.webtoolkit.info/javascript-base64.html		// modified to comply with JSLint as much as possible		// applying to $API, using "real" private variables		/*jslint bitwise: true, regexp: true*/		var keyStr,			encode,			decode,			utf8_encode,			utf8_decode;		keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=";		encode = function (str) {			var output = '', i = 0, len, chr1, chr2, chr3, enc1, enc2, enc3, enc4;			str = utf8_encode(str);			len = str.length;			while (i < len) {				chr1 = str.charCodeAt(i);				i += 1;				chr2 = str.charCodeAt(i);				i += 1;				chr3 = str.charCodeAt(i);				i += 1;				enc1 = chr1 >> 2;				enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);				enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);				enc4 = chr3 & 63;				if (isNaN(chr2)) {					enc3 = enc4 = 64;				} else if (isNaN(chr3)) {					enc4 = 64;				} output += keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4); }			return output; };		decode = function (str) { var output = '', i = 0, len, chr1, chr2, chr3, enc1, enc2, enc3, enc4; str = str.replace(/[^A-Za-z0-9\+\/\=]/g, ""); len = str.length; while (i < len) { enc1 = keyStr.indexOf(str.charAt(i)); i += 1; enc2 = keyStr.indexOf(str.charAt(i)); i += 1; enc3 = keyStr.indexOf(str.charAt(i)); i += 1; enc4 = keyStr.indexOf(str.charAt(i)); i += 1; chr1 = (enc1 << 2) | (enc2 >> 4); chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); chr3 = ((enc3 & 3) << 6) | enc4; output += String.fromCharCode(chr1); if (enc3 !== 64) { output += String.fromCharCode(chr2); }				if (enc4 !== 64) { output += String.fromCharCode(chr3); }			}			output = utf8_decode(output); return output; };		utf8_encode = function (str) { var utftext = '', n = 0, len, c;			str = str.replace(/\r\n/g, "\n"); len = str.length; for (n; n < len; n += 1) { c = str.charCodeAt(n); if (c < 128) { utftext += String.fromCharCode(c); } else if ((c > 127) && (c < 2048)) { utftext += String.fromCharCode((c >> 6) | 192); utftext += String.fromCharCode((c & 63) | 128); } else { utftext += String.fromCharCode((c >> 12) | 224); utftext += String.fromCharCode(((c >> 6) & 63) | 128); utftext += String.fromCharCode((c & 63) | 128); }			}			return utftext; };		utf8_decode = function (utftext) { var str = '', i = 0, c = 0, c1 = 0, c2 = 0, len = utftext.length; while (i < len) { c = utftext.charCodeAt(i); if (c < 128) { str += String.fromCharCode(c); i += 1; } else if ((c > 191) && (c < 224)) { c1 = utftext.charCodeAt(i + 1); str += String.fromCharCode(((c & 31) << 6) | (c1 & 63)); i += 2; } else { c1 = utftext.charCodeAt(i + 1); c2 = utftext.charCodeAt(i + 2); str += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63)); i += 3; }			}			return str; };		/*jslint bitwise: false, regexp: false*/ return { encode: encode, decode: decode };	}); }; window.$API = new TW; (function Extension { "use strict"; var enable; $API.extensions = $API.extensions || []; enable = function (ext, callback) { var script, func; func = function { $API.extensions[$API.extensions.length] = ext; if (callback) { return callback; }			return false; };		script = document.createElement('script'); script.type = 'text/javascript'; script.src = $API.baseURL + '/' + ext + '?action=raw'; if (script.addEventListener === undefined && script.attachEvent) { /* IE < 9 */ script.attachEvent('onreadystatechange', function {				if (script.readyState === 'loaded') {					func;				}			}); } else { script.addEventListener('load', func); }		document.getElementsByTagName('head')[0].appendChild(script); };	$API.isEnabled = function (ext) { var i = 0, len = $API.extensions.length; for (i; i < len; i += 1) { if ($API.extensions[i] === ext) { return true; }		}		return false; };	$API.require = function (ext, callback) { if (!$API.isEnabled(ext)) { enable(ext, callback); } else if (callback) { callback; }	}; }); (function User { "use strict"; $API.user = {}; $API.user.vars = { edittoken: '' }; // rights are readonly bool, settings are read/write string. // Use .right for private variables that should not be changed once set // Use .setting for public variables etc.	$API.user.right = (function {		var rights = {};		return function (right, value) {			var output;			if (right !== undefined) {				if (value !== undefined) {					rights[right] = (rights[right] !== undefined ? rights[right] : value);					output = rights[right];				} else if (rights[right] !== undefined) {					output = rights[right];				}			}			return output;		};	}); $API.user.setting = (function {		var settings = {};		return function (setting, value) {			var output;			if (setting !== undefined) {				if (value !== undefined) {					settings[setting] = settings[setting] || {};					settings[setting].value = (settings[setting].value !== undefined ? settings[setting].value : value);					output = settings[setting].value;				} else if (settings[setting] !== undefined) {					output = settings[setting].value;				}			}			return output;		};	}); }); (function State { "use strict"; var extension = $API.create.extension('State', false), states = {}, getUID, getAPIState, recover; getAPIState = function { var param, str = ''; for (param in states) { if (states.hasOwnProperty(param)) { str += (str ? ',' : '') + 'Ext:' + param + ',' + getUID(states[param]); }		}		return str; };	getUID = function (obj) { var param, state = ''; for (param in obj) { if (obj.hasOwnProperty(param)) { state += (state ? ',' : '') + $API.Base64.encode(param + ':' + obj[param]); }		}		return state; };	extension.setState = function (ext) { states[ext] = {}; return function (param, value) { var result; if (param !== '' && param !== undefined) { states[ext][param] = value; result = getAPIState; location.hash = result; return result; }		};	};	extension.getState = function (ext) { return function { return states[ext]; };	};	recover = function (hash) { var state, uid, i, len, activeState, matches, stateIndexes = {}, states = []; //$API.require('Base64'); uid = hash || location.hash; state = uid.split(','); i = 0; len = state.length; for (i; i < len; i += 1) { /*jslint regexp: true */ matches = state[i].match(/^#?Ext:([^:]+)$/); /*jslint regexp: false */ if (matches) { activeState = matches[1]; if (stateIndexes[activeState] === undefined) { stateIndexes[activeState] = states.length; states[stateIndexes[activeState]] = { ExtName: activeState }; }			} else { /*jslint regexp: true */ matches = $API.Base64.decode(state[i]).match(/^(.+?):(.+?)$/); /*jslint regexp: false */ if (matches !== null) { states[stateIndexes[activeState]][matches[1]] = matches[2]; }			}		}		i = 0; len = states.length; for (i; i < len; i += 1) { $API.require(states[i].ExtName); }		return states; };	if (location.hash) { recover; } }); $API.require('Edit'); $API.require('Ajax'); $API.require('Parser'); $API.require('NPC'); $API.require('Item'); $API.require('Spell'); $API.require('SearchSuggest');