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 = ( [] .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; 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 ( conf: type_conf, model: type_model ): void { let dom_users: HTMLUListElement = document.querySelector("#users"); dom_users.textContent = ""; let users: Array; 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 = 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); } dom_user.setAttribute("rel", JSON.stringify(user.name)); dom_users.appendChild(dom_user); } // meeh… ns_control.setup(conf, model); } /** * clears the content and focus on the message content input */ function clear_content ( ): void { let dom_content: HTMLInputElement = document.querySelector("#content"); dom_content.value = ""; dom_content.focus(); } /** * sets up the view */ export function setup ( conf: type_conf, model: type_model ): void { document.querySelector("#channel").value = conf.irc.predefined_channel; document.querySelector("#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);}); ns_model.listen(model, "users_changed", () => {update_users(conf, model);}); ns_model.listen(model, "message_sent", () => {clear_content();}); } }