const UI = { text(value) { return document.createTextNode(value); }, button(text, callback, select=false) { let button = document.createElement("button"); button.innerText = text; if(select) { button.setAttribute("class", "selected"); } if(callback !== null) { button.addEventListener("click", callback); } return button; }, submit(text) { let button = document.createElement("input"); button.setAttribute("type", "submit"); button.value = text; return button; }, slider(id, callback) { let input = document.createElement("input"); if(id !== null) { input.setAttribute("id", id); } input.setAttribute("type", "range"); input.setAttribute("value", "0"); input.setAttribute("min", "0"); input.setAttribute("max", "0"); if(callback !== null) { input.addEventListener("input", callback); } return input; }, checkbox(id, callback) { let input = document.createElement("input"); if(id !== null) { input.setAttribute("id", id); } input.setAttribute("type", "checkbox"); if(callback !== null) { input.addEventListener("change", callback); } return input; }, textbox(id, placeholder) { let input = document.createElement("input"); input.setAttribute("type", "text"); if(id !== null) { input.setAttribute("id", id); } input.setAttribute("placeholder", placeholder); return input; }, password(id) { let input = document.createElement("input"); input.setAttribute("type", "password"); if(id !== null) { input.setAttribute("id", id); } return input; }, label(name, id) { let label = document.createElement("label"); label.setAttribute("for", id); label.innerText = name; return label; }, span(children, attr_class) { let span = document.createElement("span"); if(attr_class !== undefined) { span.setAttribute("class", attr_class); } for(child of children) { span.appendChild(child); } return span; }, div(children, attr_class) { let div = document.createElement("div"); if(attr_class !== undefined) { div.setAttribute("class", attr_class); } for(child of children) { div.appendChild(child); } return div; }, table_content(header, rows) { let tbody = document.createElement("tbody"); if(header !== null) { let row = document.createElement("tr"); for(head of header) { let cell = document.createElement("th"); cell.innerText = head; row.appendChild(cell); } tbody.appendChild(row); } for(row of rows) { let tr = document.createElement("tr"); for(node of row) { let cell = document.createElement("td"); if(Array.isArray(node)) { for(item of node) { cell.appendChild(item); } } else { cell.appendChild(node); } tr.appendChild(cell); } tbody.appendChild(tr); } return tbody; }, table(header, rows) { let table = document.createElement("table"); table.appendChild(this.table_content(header, rows)); return table; }, mainnav(left_children, right_children, features={}) { let header = document.createElement("nav"); let left = document.createElement("section"); if(sessionStorage.getItem("auth") === null) { if(features.auth === true) { left.appendChild(UI.button(LANG("register"), () => { LOAD(SCENES.Register); })); left.appendChild(UI.button(LANG("login"), () => { LOAD(SCENES.Authenticate); })); } } else { if(features.session === true) { let button_challenge = UI.button(LANG("requests"), () => { LOAD(SCENES.ChallengeList); }); button_challenge.setAttribute("id", "button-requests"); left.appendChild(UI.button(LANG("users"), () => { LOAD(SCENES.Challenge); })); left.appendChild(button_challenge); } } for(child of left_children) { left.appendChild(child); } let right = document.createElement("section"); for(child of right_children) { right.appendChild(child); } header.appendChild(left); header.appendChild(right); MAIN.appendChild(header); }, nav(top, bottom) { let section = document.createElement("section"); for(node of top) { section.appendChild(node); } MENU.appendChild(section); section = document.createElement("section"); for(node of bottom) { section.appendChild(node); } MENU.appendChild(section); }, mainmenu(page) { if(SOCKET !== null) { let top = [ ]; let bottom = [ ]; top.push(UI.button(LANG("browse"), () => { LOAD(SCENES.Browse); }, page == "browse")); if(sessionStorage.getItem("auth") !== null) { let button_resume = UI.button(LANG("resume"), () => { LOAD(SCENES.Continue); }, page == "continue"); button_resume.setAttribute("id", "button-resume"); top.push(button_resume); //top.push(UI.button("Join", () => { LOAD(SCENES.Join); }, page == "join")); } top.push(UI.button(LANG("live"), () => { LOAD(SCENES.Live); }, page == "live")); top.push(UI.button(LANG("history"), () => { LOAD(SCENES.History); }, page == "history")); top.push(UI.button(LANG("practice"), () => { LOAD(SCENES.GamePractice); }, page == "practice")); top.push(UI.button(LANG("guide"), () => { LOAD(SCENES.Guide); }, page == "guide")); top.push(UI.button(LANG("about"), () => { LOAD(SCENES.About); }, page == "about")); bottom.push(UI.button(LANG("extras"), () => { LOAD(SCENES.Extras) }, page == "extras")); if(sessionStorage.getItem("auth") !== null) { bottom.push(UI.button(LANG("account"), () => { })); bottom.push(UI.button(LANG("logout"), () => { MESSAGE_COMPOSE([ PACK.u16(OpCode.Deauthenticate), ]); sessionStorage.clear(); LOAD_URL(); })); } UI.nav(top, bottom); } }, session_table(records) { let rows = [ ]; for(let r = 0; r < records.length; ++r) { let buttons = [ ]; let join_callback = function() { LOAD(SCENES.Game, { token:this.token, player:this.player, turn:-1, mode:INTERFACE.Mode.Player, }); MESSAGE_SESSION_VIEW(this.token, true); }; join_callback = join_callback.bind({ token: records[r].token, player: records[r].player, }); let spectate_callback = function() { LOAD(SCENES.Game, { token:this.token, player:this.player, turn:-1, mode:INTERFACE.Mode.Review, }); MESSAGE_SESSION_VIEW(this.token, false); }; spectate_callback = spectate_callback.bind({ token: records[r].token, player: records[r].player, }); if(records[r].player != 0) { let button_resume = UI.button(LANG("resume"), join_callback); if(records[r].is_turn) { button_resume.setAttribute("class", "highlight"); } buttons.push(button_resume); buttons.push(UI.button(LANG("review"), spectate_callback)); } else { buttons.push(UI.button(LANG("view"), spectate_callback)); } let dawn = UI.text(records[r].dawn); let dusk = UI.text(records[r].dusk); rows.push([ dawn, dusk, UI.text(records[r].turn), UI.text(records[r].viewers), buttons, ]); } let tbody = UI.table_content( [ LANG("dawn"), LANG("dusk"), LANG("turns"), LANG("viewers"), "" ], rows, ); return tbody; }, session_table_resume(records) { let rows = [ ]; for(let r = 0; r < records.length; ++r) { let buttons = [ ]; let join_callback = function() { SCENE_FORWARD = SCENE; LOAD(SCENES.Game, { token:this.token, player:0, turn:-1, mode:INTERFACE.Mode.Player, }); MESSAGE_SESSION_VIEW(this.token, true); }; join_callback = join_callback.bind({token: records[r].token}); let spectate_callback = function() { SCENE_FORWARD = SCENE; LOAD(SCENES.Game, { token:this.token, player:0, turn:-1, mode:INTERFACE.Mode.Review, }); MESSAGE_SESSION_VIEW(this.token, false); }; spectate_callback = spectate_callback.bind({token: records[r].token}); let button_resume = UI.button(LANG("resume"), join_callback); if(records[r].is_turn) { button_resume.setAttribute("class", "highlight"); } buttons.push(button_resume); buttons.push(UI.button(LANG("review"), spectate_callback)); let handle = records[r].dawn; if(records[r].player == 1) { handle = records[r].dusk; } rows.push([ UI.text(handle), UI.text(records[r].turn), UI.text(records[r].viewers), buttons, ]); } let tbody = UI.table_content( [ LANG("handle"), LANG("turn"), LANG("viewers"), "" ], rows, ); return tbody; }, /*session_table_join(records) { let rows = [ ]; for(let r = 0; r < records.length; ++r) { let buttons = [ ]; let join_callback = function() { LOAD(SCENES.Game, { token:this.token, mode:INTERFACE.Mode.Player, }); MESSAGE_SESSION_VIEW(this.token, true); }; join_callback = join_callback.bind({token: records[r].token}); if(records[r].player) { buttons.push(UI.button("View", join_callback)); } else { buttons.push(UI.button("Join", join_callback)); } let host = UI.text(records[r].dawn); if(records[r].dawn == "") { dawn = UI.span([UI.text("Vacant")], "text-system"); } rows.push([ host, buttons, ]); } let tbody = UI.table_content( [ "Host", "" ], rows, ); return tbody; },*/ session_table_history(records) { let rows = [ ]; for(let r = 0; r < records.length; ++r) { let buttons = [ ]; let view_callback = function() { SCENE_FORWARD = SCENE; LOAD(SCENES.Game, { token:this.token, player:0, turn:-1, mode:INTERFACE.Mode.Review, }); MESSAGE_SESSION_VIEW(this.token, false); }; view_callback = view_callback.bind({token: records[r].token}); buttons.push(UI.button(LANG("review"), view_callback)); let dawn = UI.text(records[r].dawn); let dusk = UI.text(records[r].dusk); rows.push([ dawn, dusk, UI.text(records[r].turn), buttons, ]); } let tbody = UI.table_content( [ LANG("dawn"), LANG("dusk"), LANG("turns"), "" ], rows, ); return tbody; }, page_indicator(first, last, total) { let ind = document.getElementById("indicator-page"); UI.clear(ind); ind.appendChild(UI.text(LANG_PAGEOF(first, last, total))); }, clear(dom) { while(dom.lastChild !== null) { dom.removeChild(dom.lastChild); } }, rebuild() { this.clear(document.body); MENU = document.createElement("nav"); let title = document.createElement("header"); title.innerText = "Dzura"; MENU.appendChild(title); MAIN = document.createElement("main"); document.body.appendChild(MENU); document.body.appendChild(MAIN); }, update_status() { let b_requests = document.getElementById("button-requests"); let b_resume = document.getElementById("button-resume"); if(b_requests !== null) { let text = LANG("requests"); if(STATUS.challenge > 0) { if(STATUS.challenge < 10) { text += " " + String.fromCharCode("❶".charCodeAt(0) + (STATUS.challenge - 1)); } else { text += " ❾"; } } else { text += " ⓿"; } b_requests.innerText = text; } if(b_resume !== null) { let text = LANG("resume"); if(STATUS.resume > 0) { if(STATUS.resume < 10) { text += " " + String.fromCharCode("❶".charCodeAt(0) + (STATUS.resume - 1)); } else { text += " ❾"; } } else { text += " ⓿"; } b_resume.innerText = text; } }, };