source/logic/view.ts
6faf71a8
 namespace ns_view
 {
 
 	/**
 	 * updates the state (switches between login, connecting and regular "page")
 	 */
 	function update_state
 	(
 		model: type_model
 	): void
 	{
 		document.querySelector("body").setAttribute("class", model.state);
 	}
 
 
 	/**
 	 * updates the spots (channels and queries)
 	 */
 	function update_spots
 	(
 		conf: type_conf,
 		model: type_model
 	): void
 	{
 		let dom_spots: HTMLUListElement = document.querySelector("#spots");
 		const spots: Array<type_spot> = (
 			[]
 			.concat(Object.keys(model.channels).map((name) => ({"kind": "channel", "name": name})))
 			.concat(Object.keys(model.queries).map((name) => ({"kind": "query", "name": name})))
 		);
 		dom_spots.textContent = "";
 		for (const spot of spots)
 		{
 			let dom_spot: HTMLLIElement = document.createElement("li");
 			dom_spot.classList.add("spot");
 			{
 				let dom_kind: HTMLSpanElement = document.createElement("span");
 				dom_kind.classList.add("spot_kind");
 				dom_kind.textContent = spot.kind;
 				dom_spot.appendChild(dom_kind);
 			}
 			{
 				let dom_name: HTMLSpanElement = document.createElement("span");
 				dom_name.classList.add("spot_sender");
 				dom_name.textContent = spot.name;
 				dom_spot.appendChild(dom_name);
 			}
 			dom_spot.classList.toggle("spot_active", ((spot.kind === model.active.kind) && (spot.name === model.active.name)));
 			dom_spot.setAttribute("rel", JSON.stringify(spot));
 			dom_spots.appendChild(dom_spot);
 		}
 		// meeh…
 		ns_control.setup(conf, model);
 	}
 
 
 	/**
 	 * updates the chat entries
 	 */
 	function update_entries
 	(
 		model: type_model
 	): void
 	{
 		let dom_entries: HTMLUListElement = document.querySelector("#entries");
 		let entries: Array<type_entry>;
 		switch (model.active.kind)
 		{
 			case "channel":
 			{
 				entries = model.channels[model.active.name].entries;
 				break;
 			}
 			case "query":
 			{
 				entries = model.queries[model.active.name].entries;
 				break;
 			}
 		}
 		dom_entries.textContent = "";
 		for (const entry of entries)
 		{
 			let dom_entry: HTMLLIElement = document.createElement("li");
 			dom_entry.classList.add("entry");
 			{
 				let dom_time: HTMLSpanElement = document.createElement("span");
 				dom_time.classList.add("entry_time");
 				dom_time.textContent = (new Date(entry.timestamp*1000)).toISOString().slice(11, 19);
 				dom_entry.appendChild(dom_time);
 			}
 			{
 				let dom_sender: HTMLSpanElement = document.createElement("span");
 				dom_sender.classList.add("entry_sender");
 				dom_sender.style.color = get_usercolor(entry.sender);
 				dom_sender.textContent = entry.sender;
 				dom_entry.appendChild(dom_sender);
 			}
 			{
 				let dom_content: HTMLSpanElement = document.createElement("span");
 				dom_content.classList.add("entry_content");
 				dom_content.textContent = entry.content;
 				dom_entry.appendChild(dom_content);
 			}
 			dom_entries.appendChild(dom_entry);
 		}
 		dom_entries.scrollTo(0, dom_entries["scrollTopMax"]);
 	}
 
 
 	/**
 	 * updates the user list
 	 */
 	function update_users
 	(
de5e1e21
 		conf: type_conf,
6faf71a8
 		model: type_model
 	): void
 	{
 		let dom_users: HTMLUListElement = document.querySelector("#users");
 		dom_users.textContent = "";
 		let users: Array<type_user>;
 		switch (model.active.kind)
 		{
 			default:
 			{
 				console.warn("unhandled kind: " + model.active.kind);
 				users = [];
 				break;
 			}
 			case "channel":
 			{
 				users = model.channels[model.active.name].users;
 				break;
 			}
 			case "query":
 			{
 				users = [{"name": model.nickname, "role": ""}, {"name": model.active.name, "role": ""}];
 				break;
 			}
 		}
 		const users_sorted: Array<type_user> = users.sort
 		(
 			(x, y) =>
 			(
 				(x.role >= y.role)
 				? -1
 				: (
 					(x.role === y.role)
 					? ((x.name < y.name) ? -1 : +1)
 					: +1
 				)
 			)
 		);
 		for (const user of users_sorted)
 		{
 			let dom_user: HTMLLIElement = document.createElement("li");
 			dom_user.classList.add("user");
 			{
 				let dom_role: HTMLSpanElement = document.createElement("span");
 				dom_role.textContent = user.role;
 				dom_user.appendChild(dom_role);
 			}
 			{
 				let dom_name: HTMLSpanElement = document.createElement("span");
 				dom_name.textContent = user.name;
 				dom_name.style.color = get_usercolor(user.name);
 				dom_user.appendChild(dom_name);
 			}
de5e1e21
 			dom_user.setAttribute("rel", JSON.stringify(user.name));
6faf71a8
 			dom_users.appendChild(dom_user);
 		}
de5e1e21
 		// meeh…
 		ns_control.setup(conf, model);
6faf71a8
 	}
 
 
 	/**
 	 * clears the content and focus on the message content input
 	 */
 	function clear_content
 	(
 	): void
 	{
 		let dom_content: HTMLInputElement = document.querySelector<HTMLInputElement>("#content");
 		dom_content.value = "";
 		dom_content.focus();
 	}
 
 
 	/**
 	 * sets up the view
 	 */
 	export function setup
 	(
 		conf: type_conf,
 		model: type_model
 	): void
 	{
 		document.querySelector<HTMLInputElement>("#channel").value = conf.irc.predefined_channel;
 		document.querySelector<HTMLInputElement>("#nickname").value = (conf.irc.predefined_nickname_prefix + (Math.random()*100).toFixed(0));
 		
 		ns_model.listen(model, "state_changed", () => {update_state(model);});
 		ns_model.listen(model, "spots_changed", () => {update_spots(conf, model);});
 		ns_model.listen(model, "entries_changed", () => {update_entries(model);});
de5e1e21
 		ns_model.listen(model, "users_changed", () => {update_users(conf, model);});
6faf71a8
 		ns_model.listen(model, "message_sent", () => {clear_content();});
 	}
 	
 }