Home Reference Source

vgui/20-document.js

let instance = false;

/**
 * Represents the root node of the Element tree.
 * This is the VguiJavascriptContext panel or a subclass.
 */
export class Document extends Element {
	/**
	 * Creates a new Document. There can only be one document per context.
	 * @private
	 */
	constructor() {
		super(__vgui_GetMe());
		if (instance)
			throw new Error("Can't construct a second Document");
		instance = true;
	}
	
	/**
	 * @override
	 */
	get parentNode() {
		// Prevent traversal to panels above me
		return null;
	}

	/**
	 * @override
	 */
	dispatchEvent(e) {
		// Try handling locally
		if (!super.dispatchEvent(e))
			return false;

		// Otherwise dispatch to Source Engine
		if (!e.bubbles)
			return;

		if (!(e instanceof SourceEvent))
			return;

		if (!e.canEscape)
			return;

		__vgui_EmitEvent(e.data._serialize(e._type))
		return true
	}

	/**
	 * Looks recursively in child elements to find an Element that has an matching id.
	 * @param {!string} id - The id to look for
	 */
	getElementById(id) {
		var rec = undefined;
		rec = function(e, id) {
			if (e.id == id)
				return e;

			var children = e.childNodes;
			for(var i = 0; i < children.length; i++) {
				var result = rec(children[i], id);
				if (result != null)
					return result;
			}
			return null;
		}
		return rec(this, id);
	}

	/**
	 * Opens the Vgui Editor for this panel
	 */
	activateBuildMode() {

	}

	/**
	 * Registers a binding with the client.
	 * This should trigger an immediate {@link SettingsEvent} on Document so register a listener before registering.
	 * @param {string} key - The key to bind to
	 * @param {string} type - The type of the bind, can be ["int", "string", "bool", "float]
	 */
	registerBind(key, type = "int") {
		switch (type) {
			case "int":
				__vgui_SubscribeBindingInt(key);
				break;
			case "string":
				__vgui_SubscribeBindingString(key);
				break;
			case "bool":
				__vgui_SubscribeBindingBool(key);
				break;
			case "float":
				__vgui_SubscribeBindingFloat(key);
				break;
			default:
				throw new Error("Unknown binding type " + type);
		}
	}

	/**
	 * Plays a sound effect.
	 * soundName be defined in the empires soundscripts.
	 * @param {string} soundName - The key of the sound in the soundscript to play.
	 */
	playSound(soundName) {
		if (!soundName)
			throw new Error("soundName not set");
		__vgui_PlaySound(soundName);
	}

	/**
	 * @override
	 */
	toString() {
		return "Document";
	}

	/**
	 * Converts a source engine event to a DOM event and throws it at the right panel
	 */
	__constructEvent(panelId, type, keyValues) {

		var target = this;
		if (panelId != 0)
			target = new Node(panelId)._specialize();
		const e = SourceEvent.__createSpecific(type, keyValues);
		
		try {
			target.dispatchEvent(e);
		} catch (err) {
			console.log("Error during " + e.type + " event dispatch: " + err.stack);
		}
	}
}

let root = new Document();
if (!exports.Node)
	exports.Node = {}
exports.Node._cache = exports.Node._cache || {};
exports.Node._cache[root._id] = root;

/**
 * @ignore
 */
export let document = root;
global.document = root;

/**
 * @ignore
 */
export let __vgui_SettingsChanged = function() {
	var event = new SettingsEvent();
	try {
		root.dispatchEvent(event);
	} catch(e) {
		console.error("Error occured during external event: " + e.stack);
	}
}

/**
 * @ignore
 */
export let __vgui_BindTrigger = function(key, value) {
	var event = new BindEvent(key, value);
	try {
		root.dispatchEvent(event);
	} catch(e) {
		console.error("Error occured during bind event: " + e.stack);
	}
}