func settingsTab(c dom.Element) { s, err := RPC.Settings() if err != nil { xjs.Alert("Error reading settings: %s", err) return } sn := xform.InputText("serverName", s.ServerName) sn.Required = true la := xform.InputText("listenAddr", s.ListenAddr) la.Required = true sp := xform.InputText("serversPath", s.DirServers) sp.Required = true mp := xform.InputText("mapsPath", s.DirMaps) mp.Required = true gp := xform.InputText("gensPath", s.DirGenerators) gp.Required = true ge := xform.InputText("genExe", s.GeneratorExecutable) ge.Required = true mm := xform.InputNumber("maxMem", 100, 10000, float64(s.GeneratorMaxMem/1024/1024)) mm.Required = true sb := xform.InputSubmit("Save") sb.AddEventListener("click", false, func(e dom.Event) { if sn.Value == "" || la.Value == "" || sp.Value == "" || mp.Value == "" || gp.Value == "" || ge.Value == "" || !mm.CheckValidity() { return } e.PreventDefault() sb.Disabled = true go func() { s.ServerName = sn.Value s.ListenAddr = la.Value s.DirServers = sp.Value s.DirMaps = mp.Value s.DirGenerators = gp.Value s.GeneratorExecutable = ge.Value s.GeneratorMaxMem = uint64(mm.ValueAsNumber * 1024 * 1024) if err := RPC.SetSettings(s); err != nil { xjs.Alert("Error saving settings: %s", err) return } SetTitle(sn.Value) span := xdom.Span() span.Style().Set("color", "#f00") c.AppendChild(xjs.SetInnerText(span, "Saved!")) time.Sleep(5 * time.Second) c.RemoveChild(span) sb.Disabled = false }() }) xjs.AppendChildren(c, xjs.AppendChildren(xdom.Form(), xjs.AppendChildren(xdom.Fieldset(), xjs.SetInnerText(xdom.Legend(), "Change Settings"), xform.Label("Server Name", "serverName"), sn, xdom.Br(), xform.Label("Listen Address", "listenAddr"), la, xdom.Br(), xform.Label("Servers Path", "serversPath"), sp, xdom.Br(), xform.Label("Maps Path", "mapsPath"), mp, xdom.Br(), xform.Label("Generators Path", "gensPath"), gp, xdom.Br(), xform.Label("Generator Executable", "genExe"), ge, xdom.Br(), xform.Label("Generator Memory (MB)", "maxMem"), mm, xdom.Br(), sb, ))) }
func serverEULA(s data.Server, d string) func(dom.Element) { return func(c dom.Element) { t := xform.TextArea("eula", d) submit := xform.InputSubmit("Save") c.AppendChild(xjs.AppendChildren(xdom.Form(), xjs.AppendChildren(xdom.Fieldset(), xjs.SetInnerText(xdom.Legend(), "End User License Agreement"), xform.Label("EULA", "eula"), t, xdom.Br(), submit, ))) submit.AddEventListener("click", false, func(e dom.Event) { e.PreventDefault() submit.Disabled = true go func() { err := RPC.SetServerEULA(s.ID, t.Value) if err != nil { xjs.Alert("Error setting server EULA: %s", err) return } d = t.Value span := xdom.Span() span.Style().Set("color", "#f00") c.AppendChild(xjs.SetInnerText(span, "Saved!")) time.Sleep(5 * time.Second) c.RemoveChild(span) submit.Disabled = false }() }) } }
func rangeWatch(r *dom.HTMLInputElement) dom.Element { s := xdom.Span() xjs.SetInnerText(s, r.Value) r.AddEventListener("input", false, func(dom.Event) { xjs.SetInnerText(s, r.Value) }) return s }
func GeneratorsTab(c dom.Element) { go func() { xjs.RemoveChildren(c) gs, err := RPC.Generators() if err != nil { xjs.Alert("Error getting generator list: %s", err) return } ng := xdom.Button() xjs.SetInnerText(ng, "New Generator") ng.AddEventListener("click", false, func(dom.Event) { d := xdom.Div() o := overlay.New(d) o.OnClose(func() { GeneratorsTab(c) }) d.AppendChild(transferFile("Map", "Upload/Download", 3, o)) xjs.Body().AppendChild(o) }) table := xjs.AppendChildren(xdom.Table(), xjs.AppendChildren(xdom.Tr(), xjs.SetInnerText(xdom.Th(), "Generator"))) if len(gs) == 0 { table.AppendChild(xjs.AppendChildren(xdom.Tr(), xjs.SetInnerText(xdom.Td(), "No Generators"))) } else { for _, g := range gs { td := xdom.Td() td.AddEventListener("click", false, func(g data.Generator) func(dom.Event) { return func(dom.Event) { d := xdom.Div() o := overlay.New(d) o.OnClose(func() { GeneratorsTab(c) }) d.AppendChild(tabs.New([]tabs.Tab{ {"Profile", generatorProfile(g.ID)}, {"Misc", misc("generator", g.ID, o, RPC.RemoveGenerator)}, })) xjs.Body().AppendChild(o) } }(g)) table.AppendChild(xjs.AppendChildren(xdom.Tr(), xjs.SetInnerText(td, g.Name))) } } xjs.AppendChildren(c, xjs.SetInnerText(xdom.H2(), "Generators"), ng, table, ) }() }
func SetTitle(title string) { title += " Server" xjs.SetInnerText(dom.GetWindow().Document().(dom.HTMLDocument).Body().ChildNodes()[0], title) tDoc, ok := dom.GetWindow().Document().(dom.HTMLDocument) if ok { tDoc.SetTitle(title) } }
// Add adds the given CSS string to the DOM func Add(css string) dom.Element { h := dom.GetWindow().Document().GetElementsByTagName("head") if len(h) == 0 { return nil } s := xdom.Style() h[0].AppendChild(xjs.SetInnerText(s, css)) return s }
func misc(mType string, id int, o *overlay.Overlay, deleteFunc func(int) error) func(dom.Element) { return func(c dom.Element) { download := xdom.A() download.Href = "http://" + js.Global.Get("location").Get("host").String() + "/download/" + mType + "/" + strconv.Itoa(id) + ".zip" download.Target = "_blank" del := xdom.Button() del.AddEventListener("click", false, func(dom.Event) { del.Disabled = true if dom.GetWindow().Confirm("Are you sure?") { go func() { err := deleteFunc(id) if err != nil { del.Disabled = false xjs.Alert("Error while deleting %s: %s", mType, err) } else { o.Close() } }() } }) xjs.AppendChildren(c, xjs.AppendChildren(xdom.Fieldset(), xjs.SetInnerText(xdom.Legend(), "Download"), xjs.SetInnerText(xdom.Div(), "Click the following link to download the "+mType+" as a zip file."), xjs.SetInnerText(download, download.Href), ), xjs.AppendChildren(xdom.Fieldset(), xjs.SetInnerText(xdom.Legend(), "Delete"), xjs.SetInnerText(xdom.Div(), "The following button will permanently delete the "+mType+" (this cannot be undone)."), xjs.SetInnerText(del, "Delete "+mType), ), ) } }
func rpcInit() error { conn, err := websocket.Dial("ws://" + js.Global.Get("location").Get("host").String() + "/rpc") if err != nil { return err } conn.WebSocket.Call("addEventListener", "close", func(*js.Object) { xjs.RemoveChildren(xdom.Body()).AppendChild(xjs.SetInnerText(xdom.H1(), "Connection Lost")) }, false) dom.GetWindow().AddEventListener("beforeunload", false, func(dom.Event) { switch conn.ReadyState { case websocket.Connecting, websocket.Open: conn.Close() } }) RPC = jRPC{jsonrpc.NewClient(conn)} return nil }
// New takes a list of tabs and generates a tabbed interface, which is return as a document fragment func New(t []Tab) dom.Node { f := xdom.DocumentFragment() if len(t) < 0 { return f } tabsDiv := xdom.Div() contents := xdom.Div() tabsDiv.Class().SetString("tabs") contents.Class().SetString("content") tabs := make([]dom.Element, len(t)) for n := range t { tabs[n] = xjs.SetInnerText(xdom.Div(), t[n].Name).(dom.Element) tabs[n].AddEventListener("click", false, func() func(dom.Event) { i := n return func(e dom.Event) { if tabs[i].Class().String() == "selected" { return } for _, tab := range tabs { tab.Class().Remove("selected") } newContents := contents.CloneNode(false).(*dom.HTMLDivElement) contents.ParentNode().ReplaceChild(newContents, contents) contents = newContents tabs[i].Class().Add("selected") go t[i].Func(contents) } }()) tabsDiv.AppendChild(tabs[n]) } go t[0].Func(contents) tabs[0].Class().Add("selected") f.AppendChild(tabsDiv) f.AppendChild(contents) return f }
func transferFile(typeName, method string, typeID uint8, o *overlay.Overlay) dom.Node { name := xform.InputText("name", "") url := xform.InputRadio("url", "switch", true) upload := xform.InputRadio("upload", "switch", false) fileI := xform.InputUpload("") urlI := xform.InputURL("", "") s := xform.InputSubmit(method) name.Required = true typeFunc := func(dom.Event) { if url.Checked { urlI.Style().RemoveProperty("display") fileI.Style().SetProperty("display", "none", "") urlI.Required = true fileI.Required = false fileI.SetID("") urlI.SetID("file") } else { fileI.Style().RemoveProperty("display") urlI.Style().SetProperty("display", "none", "") fileI.Required = true urlI.Required = false urlI.SetID("") fileI.SetID("file") } } typeFunc(nil) url.AddEventListener("change", false, typeFunc) upload.AddEventListener("change", false, typeFunc) f := xjs.AppendChildren(xdom.Form(), xjs.AppendChildren(xdom.Fieldset(), xjs.SetInnerText(xdom.Legend(), method+" "+typeName), xform.Label(typeName+" Name", "name"), name, xdom.Br(), xform.Label("URL", "url"), url, xdom.Br(), xform.Label("Upload", "upload"), upload, xdom.Br(), xform.Label("File", "file"), fileI, urlI, xdom.Br(), s, )) s.AddEventListener("click", false, func(e dom.Event) { if name.Value == "" { return } if url.Checked { if urlI.Value == "" { return } } else if len(fileI.Files()) != 1 { return } s.Disabled = true name.Disabled = true url.Disabled = true upload.Disabled = true fileI.Disabled = true urlI.Disabled = true e.PreventDefault() go func() { d := xdom.Div() uo := overlay.New(d) uo.OnClose(func() { o.Close() }) xjs.Body().AppendChild(uo) status := xdom.Div() d.AppendChild(xjs.SetInnerText(status, "Transferring...")) conn, err := websocket.Dial("ws://" + js.Global.Get("location").Get("host").String() + "/transfer") if err != nil { xjs.SetInnerText(status, err.Error()) return } defer conn.Close() w := byteio.StickyWriter{Writer: byteio.LittleEndianWriter{Writer: conn}} r := byteio.StickyReader{Reader: byteio.LittleEndianReader{Reader: conn}} pb := progress.New(color.RGBA{255, 0, 0, 0}, color.RGBA{0, 0, 255, 0}, 400, 50) d.AppendChild(pb) if url.Checked { w.WriteUint8(typeID << 1) data.WriteString(&w, urlI.Value) length := int(r.ReadInt32()) total := 0 for total < length { switch v := r.ReadUint8(); v { case 1: i := int(r.ReadInt32()) total += i pb.Percent(100 * total / length) default: xjs.SetInnerText(status, ReadError(&r).Error()) return } } } else { f := files.NewFileReader(files.NewFile(fileI.Files()[0])) l := f.Len() if l == 0 { xjs.SetInnerText(status, "Zero-length file") return } w.WriteUint8(typeID<<1 | 1) w.WriteInt32(int32(l)) io.Copy(&w, pb.Reader(f, l)) } d.RemoveChild(pb) xjs.SetInnerText(status, "Checking File") data.WriteString(&w, name.Value) var ctx *dom.CanvasRenderingContext2D for { switch v := r.ReadUint8(); v { case 0: if r.Err != nil { xjs.SetInnerText(status, r.Err.Error()) } else { xjs.SetInnerText(status, ReadError(&r).Error()) } return case 1: files := make([]xform.Option, r.ReadInt16()) for i := range files { files[i] = xform.Option{ Value: strconv.Itoa(i), Label: data.ReadString(&r), } } j := xform.SelectBox("files", files...) sel := xjs.SetInnerText(xdom.Button(), "Select") fo := overlay.New(xjs.AppendChildren(xdom.Div(), xjs.AppendChildren(xdom.Fieldset(), xjs.SetInnerText(xdom.Legend(), "Please select the "+typeName+" file"), xform.Label("File", "files"), j, xdom.Br(), sel, ))) c := make(chan int16, 0) done := false fo.OnClose(func() { if !done { done = true c <- -1 } }) sel.AddEventListener("click", false, func(dom.Event) { if !done { done = true v, err := strconv.Atoi(j.Value) if err != nil { v = -1 } c <- int16(v) fo.Close() } }) xjs.Body().AppendChild(fo) w.WriteInt16(<-c) close(c) case 2: w := r.ReadInt32() h := r.ReadInt32() canvas := xdom.Canvas() canvas.Width = int(w) * 8 canvas.Height = int(h) * 8 d.AppendChild(canvas) ctx = canvas.GetContext2d() ctx.Scale(8, 8) case 3: xjs.SetInnerText(status, data.ReadString(&r)) case 4: x := r.ReadInt32() y := r.ReadInt32() red := r.ReadUint8() green := r.ReadUint8() blue := r.ReadUint8() alpha := r.ReadUint8() ctx.FillStyle = "rgba(" + strconv.Itoa(int(red)) + ", " + strconv.Itoa(int(green)) + ", " + strconv.Itoa(int(blue)) + ", " + strconv.FormatFloat(float64(alpha)/255, 'f', -1, 32) + ")" ctx.FillRect(int(x), int(y), 1, 1) case 255: uo.Close() return } } }() }) return f }
func editProperties(c dom.Element, name string, id int, rpcGet func(int) (map[string]string, error), rpcSet func(id int, properties map[string]string) error) { sp, err := rpcGet(id) if err != nil { c.AppendChild(xjs.SetInnerText(xdom.Div(), "Failed to get properties: "+err.Error())) return } props := make(PropertyList, 0, len(sp)) for k, v := range sp { props = append(props, [2]string{k, v}) } sort.Sort(props) propE := make([][2]*dom.HTMLSpanElement, len(props)) df := xjs.DocumentFragment() toggleFunc := func(k, v *dom.HTMLSpanElement, toggle *dom.HTMLInputElement) func(dom.Event) { return func(dom.Event) { if toggle.Value == "-" { k.SetContentEditable("false") v.SetContentEditable("false") k.Style().SetProperty("background-color", "#888", "") v.Style().SetProperty("background-color", "#888", "") toggle.Value = "+" } else { k.SetContentEditable("true") v.SetContentEditable("true") k.Style().RemoveProperty("background-color") v.Style().RemoveProperty("background-color") toggle.Value = "-" } } } for i, prop := range props { k := xform.InputSizeable("", prop[0]) v := xform.InputSizeable("", prop[1]) toggle := xform.InputButton("", "-") toggle.AddEventListener("click", false, toggleFunc(k, v, toggle)) propE[i][0] = k propE[i][1] = v xjs.AppendChildren(df, toggle, k, xjs.SetInnerText(xdom.Span(), "="), v, xdom.Br(), ) } add := xform.InputButton("", "Add") submit := xform.InputButton("", "Save") fs := xjs.AppendChildren(xdom.Fieldset(), xjs.SetInnerText(xdom.Legend(), name+" Properties"), df, add, submit, ) add.AddEventListener("click", false, func(dom.Event) { k := xform.InputSizeable("", "") v := xform.InputSizeable("", "") toggle := xform.InputButton("", "-") toggle.AddEventListener("click", false, toggleFunc(k, v, toggle)) propE = append(propE, [2]*dom.HTMLSpanElement{k, v}) fs.InsertBefore(toggle, add) fs.InsertBefore(k, add) fs.InsertBefore(xjs.SetInnerText(xdom.Span(), "="), add) fs.InsertBefore(v, add) fs.InsertBefore(xdom.Br(), add) }) submit.AddEventListener("click", false, func(dom.Event) { submit.Disabled = true props := make(map[string]string, len(propE)) for _, spans := range propE { if spans[0].IsContentEditable() { props[spans[0].TextContent()] = spans[1].TextContent() } } go func() { err := rpcSet(id, props) if err != nil { xjs.Alert("Error setting "+name+" properties: %s", err) return } span := xdom.Span() span.Style().Set("color", "#f00") fs.AppendChild(xjs.SetInnerText(span, "Saved!")) time.Sleep(5 * time.Second) fs.RemoveChild(span) submit.Disabled = false }() }) xjs.AppendChildren(c, xjs.AppendChildren(xdom.Form(), fs)) }
func serverConsole(s data.Server) func(dom.Element) { return func(c dom.Element) { log := xform.TextArea("log", "") log.ReadOnly = true command := xform.InputText("command", "") command.Required = true send := xform.InputSubmit("Send") c.AppendChild(xjs.AppendChildren(xdom.Form(), xjs.AppendChildren(xdom.Fieldset(), xjs.SetInnerText(xdom.Legend(), "Console"), xform.Label("Log", ""), log, xdom.Br(), xform.Label("Command", "command"), command, send, ))) if s.State == data.StateStopped { send.Disabled = true command.Disabled = true } else { send.AddEventListener("click", false, func(e dom.Event) { if command.Value == "" { return } e.PreventDefault() send.Disabled = true cmd := command.Value log.Value += "\n>" + cmd + "\n" log.Set("scrollTop", log.Get("scrollHeight")) command.Value = "" go func() { err := RPC.WriteCommand(s.ID, cmd) if err != nil { xjs.Alert("Error sending command: %s", err) return } send.Disabled = false }() }) } go func() { conn, err := websocket.Dial("ws://" + js.Global.Get("location").Get("host").String() + "/console") if err != nil { xjs.Alert("Failed to connect to console: %s", err) return } defer conn.Close() w := byteio.StickyWriter{Writer: byteio.LittleEndianWriter{Writer: conn}} r := byteio.StickyReader{Reader: byteio.LittleEndianReader{Reader: conn}} updateStop := make(chan struct{}) registerUpdateStopper(c, updateStop) done := false go func() { <-updateStop done = true conn.Close() }() w.WriteInt32(int32(s.ID)) for { state := r.ReadUint8() switch state { case 0: if !done { err := ReadError(&r) if r.Err != nil { err = r.Err } log.Value += "\n\nError reading from console: " + err.Error() log.Set("scrollTop", log.Get("scrollHeight")) } return case 1: log.Value += data.ReadString(&r) log.Set("scrollTop", log.Get("scrollHeight")) } } }() } }
func serverGeneral(s data.Server) func(dom.Element) { return func(c dom.Element) { go func() { maps, err := RPC.MapList() if err != nil { c.AppendChild(xjs.SetInnerText(xdom.Div(), "Error getting map list: "+err.Error())) return } name := xform.InputText("name", s.Name) name.Required = true opts := make([]xform.Option, 1, len(maps)+1) opts[0] = xform.Option{ Label: "-- None -- ", Value: "-1", Selected: s.Map == -1, } for i, m := range maps { n := m.Name if m.Server != -1 { if m.ID == s.Map { n = "* - " + n } else { n = "! - " + n } } else { n = " " + n } opts = append(opts, xform.Option{ Label: n, Value: strconv.Itoa(i), Selected: m.ID == s.Map, }) } args := xform.InputSizeableList(s.Args...) sel := xform.SelectBox("map", opts...) submit := xform.InputSubmit("Set") submit.AddEventListener("click", false, func(e dom.Event) { if s.State != data.StateStopped { xjs.Alert("Cannot modify these settings while the server is running") return } if name.Value == "" { return } sID, err := strconv.Atoi(sel.Value) if err != nil || sID < -1 || sID >= len(maps) { return } submit.Disabled = true e.PreventDefault() if sID >= 0 { m := maps[sID] sID = m.ID } go func() { err = RPC.SetServerMap(s.ID, sID) if err != nil { xjs.Alert("Error setting server map: %s", err) return } s.Name = name.Value s.Args = args.Values() err = RPC.SetServer(s) if err != nil { xjs.Alert("Error setting server data: %s", err) return } span := xdom.Span() span.Style().Set("color", "#f00") c.AppendChild(xjs.SetInnerText(span, "Saved!")) time.Sleep(5 * time.Second) c.RemoveChild(span) submit.Disabled = false }() }) xjs.AppendChildren(c, xjs.AppendChildren(xdom.Form(), xform.Label("Server Name", "name"), name, xdom.Br(), xform.Label("Arguments", "args"), args, xdom.Br(), xform.Label("Map Name", "map"), sel, xdom.Br(), submit, )) }() } }
func mapGeneral(m data.Map) func(dom.Element) { return func(c dom.Element) { go func() { servers, err := RPC.ServerList() if err != nil { c.AppendChild(xjs.SetInnerText(xdom.Div(), "Error getting server list: "+err.Error())) return } name := xform.InputText("name", m.Name) name.Required = true opts := make([]xform.Option, 1, len(servers)+1) opts[0] = xform.Option{ Label: "-- None --", Value: "-1", Selected: m.Server == -1, } var cs data.Server for i, s := range servers { n := s.Name if s.Map != -1 { if s.ID == m.Server { cs = s n = "* - " + n } else { n = "! - " + n } } else { n = " " + n } opts = append(opts, xform.Option{ Label: n, Value: strconv.Itoa(i), Selected: s.ID == m.Server, }) } sel := xform.SelectBox("server", opts...) submit := xform.InputSubmit("Set") submit.AddEventListener("click", false, func(e dom.Event) { if cs.State != data.StateStopped { xjs.Alert("Cannot modify these settings while connected server is running.") return } if name.Value == "" { return } mID, err := strconv.Atoi(sel.Value) if err != nil || mID < -1 || mID >= len(servers) { return } submit.Disabled = true e.PreventDefault() if mID >= 0 { s := servers[mID] mID = s.ID } go func() { err = RPC.SetServerMap(mID, m.ID) if err != nil { xjs.Alert("Error setting map server: %s", err) return } m.Name = name.Value err = RPC.SetMap(m) if err != nil { xjs.Alert("Error setting map data: %s", err) return } span := xdom.Span() span.Style().Set("color", "#f00") c.AppendChild(xjs.SetInnerText(span, "Saved!")) time.Sleep(5 * time.Second) c.RemoveChild(span) submit.Disabled = false }() }) xjs.AppendChildren(c, xjs.AppendChildren(xdom.Form(), xform.Label("Server Name", "name"), name, xdom.Br(), xform.Label("Server Name", "server"), sel, xdom.Br(), submit, )) }() } }
func MapsTab() func(dom.Element) { forceUpdate := make(chan struct{}) nm := xdom.Button() nm.AddEventListener("click", false, func(dom.Event) { d := xdom.Div() o := overlay.New(d) o.OnClose(func() { go func() { forceUpdate <- struct{}{} }() }) xjs.AppendChildren(d, xjs.SetInnerText(xdom.H1(), "New Map"), tabs.New([]tabs.Tab{ {"Create", createMap(o)}, {"Upload/Download", func(c dom.Element) { c.AppendChild(transferFile("Map", "Upload/Download", 1, o)) }}, {"Generate", func(c dom.Element) { c.AppendChild(transferFile("Map", "Generate", 2, o)) }}, }), ) xjs.Body().AppendChild(o) }) noneTd := xdom.Td() noneTd.ColSpan = 2 none := xjs.AppendChildren(xdom.Tr(), xjs.SetInnerText(noneTd, "No Maps Found")) mapList := xjs.AppendChildren(xdom.Table(), xjs.AppendChildren(xdom.Thead(), xjs.AppendChildren(xdom.Tr(), xjs.SetInnerText(xdom.Th(), "Map Name"), xjs.SetInnerText(xdom.Th(), "Status"), )), none, ) nodes := xjs.AppendChildren(xdom.Div(), xjs.SetInnerText(xdom.H2(), "Maps"), xjs.SetInnerText(nm, "New Map"), mapList, ) maps := make(map[int]*Map) return func(c dom.Element) { c.AppendChild(nodes) updateStop := make(chan struct{}) registerUpdateStopper(c, updateStop) for { mps, err := RPC.MapList() if err != nil { xjs.Alert("Error getting map list: %s", err) return } if none.ParentNode() != nil { mapList.RemoveChild(none) } for _, m := range maps { m.ID = -1 } for _, m := range mps { om, ok := maps[m.ID] if ok { om.Map = m } else { name := xdom.Td() status := xdom.Td() om = &Map{ Map: m, row: xjs.AppendChildren(xdom.Tr(), name, status, ), name: name, status: status, } maps[m.ID] = om mapList.AppendChild(om.row) name.Class().SetString("mapName") name.AddEventListener("click", false, func() func(dom.Event) { m := om return func(dom.Event) { div := xdom.Div() o := overlay.New(div) div.AppendChild(tabs.New([]tabs.Tab{ {"General", mapGeneral(m.Map)}, {"Properties", mapProperties(m.Map)}, {"Misc.", misc("map", m.Map.ID, o, RPC.RemoveMap)}, })) o.OnClose(func() { go func() { forceUpdate <- struct{}{} }() }) xjs.Body().AppendChild(o) } }()) } switch om.Server { case -2: xjs.SetInnerText(om.status, "Busy") om.status.Style().SetProperty("color", "#f00", "") case -1: xjs.SetInnerText(om.status, "Unassigned") om.status.Style().SetProperty("color", "#00f", "") default: serv, err := RPC.Server(om.Server) if err == nil { xjs.SetInnerText(om.status, "Assigned") } else { xjs.SetInnerText(om.status, "Assigned - "+serv.Name) } om.status.Style().SetProperty("color", "#000", "") } xjs.SetInnerText(om.name, om.Name) } for id, m := range maps { if m.ID == -1 { delete(maps, id) mapList.RemoveChild(m.row) } } if len(maps) == 0 { mapList.AppendChild(none) } // Sleep until update if !updateSleep(forceUpdate, updateStop) { return } } } }
func createMap(o *overlay.Overlay) func(dom.Element) { return func(c dom.Element) { name := xform.InputText("name", "") name.Required = true gmOpts := make([]xform.Option, len(gameModes)) for i, m := range gameModes { gmOpts[i] = xform.Option{ Label: m, Value: strconv.Itoa(i), } } gameMode := xform.SelectBox("gamemode", gmOpts...) seed := xform.InputText("seed", "") structures := xform.InputCheckbox("structures", true) cheats := xform.InputCheckbox("cheats", false) fs := xdom.Fieldset() fs.AppendChild(xjs.SetInnerText(xdom.Legend(), "Create Map")) c.AppendChild(xjs.AppendChildren(xdom.Form(), fs)) dataParser := func(mode int) func() (data.DefaultMap, error) { return func() (data.DefaultMap, error) { data := data.DefaultMap{ Mode: mode, } var err error data.Name = name.Value si := gameMode.SelectedIndex if si < 0 || si >= len(gameModes) { return data, errors.New("invalid gamemode") } if seed.Value == "" { seed.Value = "0" } data.Seed, err = strconv.ParseInt(seed.Value, 10, 64) if err != nil { return data, err } data.Structures = structures.Checked data.Cheats = cheats.Checked return data, nil } } xjs.AppendChildren(fs, xform.Label("Name", "name"), name, xdom.Br(), xform.Label("Game Mode", "gamemode"), gameMode, xdom.Br(), xform.Label("Level Seed", "seed"), seed, xdom.Br(), xform.Label("Structures", "structures"), structures, xdom.Br(), xform.Label("Cheats", "cheats"), cheats, xdom.Br(), tabs.New([]tabs.Tab{ {"Default", createMapMode(0, o, dataParser(0))}, {"Super Flat", createSuperFlatMap(o, dataParser(1))}, {"Large Biomes", createMapMode(2, o, dataParser(2))}, {"Amplified", createMapMode(3, o, dataParser(3))}, {"Customised", createCustomisedMap(o, dataParser(4))}, }), ) } }
func generatorProfile(id int) func(dom.Element) { var d dom.Node return func(c dom.Element) { if d == nil { g, err := RPC.Generator(id) if err != nil { xjs.Alert("Error while getting generator settings: %s", err) return } tTable := xjs.AppendChildren(xdom.Table(), xjs.AppendChildren(xdom.Thead(), xjs.AppendChildren(xdom.Tr(), xjs.SetInnerText(xdom.Th(), "Colour"), xjs.SetInnerText(xdom.Th(), "Colour Code"), xjs.SetInnerText(xdom.Th(), "Name"), ))) for _, t := range g.Terrain { colour := xdom.Td() cc := fmt.Sprintf("rgb(%d, %d, %d)", t.Colour.R, t.Colour.G, t.Colour.B) colour.Style().SetProperty("background-color", cc, "") colour.Style().SetProperty("border", "1px solid #000", "") tTable.AppendChild(xjs.AppendChildren(xdom.Tr(), colour, xjs.SetInnerText(xdom.Td(), cc), xjs.SetInnerText(xdom.Td(), t.Name), )) } bTable := xjs.AppendChildren(xdom.Table(), xjs.AppendChildren(xdom.Thead(), xjs.AppendChildren(xdom.Tr(), xjs.SetInnerText(xdom.Th(), "Colour"), xjs.SetInnerText(xdom.Th(), "Colour Code"), xjs.SetInnerText(xdom.Th(), "Name"), ))) for _, b := range g.Biomes { colour := xdom.Td() cc := fmt.Sprintf("rgb(%d, %d, %d)", b.Colour.R, b.Colour.G, b.Colour.B) colour.Style().SetProperty("background-color", cc, "") colour.Style().SetProperty("border", "1px solid #000", "") bTable.AppendChild(xjs.AppendChildren(xdom.Tr(), colour, xjs.SetInnerText(xdom.Td(), cc), xjs.SetInnerText(xdom.Td(), b.Name), )) } pTable := xjs.AppendChildren(xdom.Table(), xjs.AppendChildren(xdom.Thead(), xjs.AppendChildren(xdom.Tr(), xjs.SetInnerText(xdom.Th(), "Colour"), xjs.SetInnerText(xdom.Th(), "Colour Code"), xjs.SetInnerText(xdom.Th(), "Name"), ))) for _, p := range g.Plants { colour := xdom.Td() cc := fmt.Sprintf("rgb(%d, %d, %d)", p.Colour.R, p.Colour.G, p.Colour.B) colour.Style().SetProperty("background-color", cc, "") colour.Style().SetProperty("border", "1px solid #000", "") pTable.AppendChild(xjs.AppendChildren(xdom.Tr(), colour, xjs.SetInnerText(xdom.Td(), cc), xjs.SetInnerText(xdom.Td(), p.Name), )) } d = xjs.AppendChildren(xdom.Div(), xjs.SetInnerText(xdom.H2(), "Terrain"), tTable, xjs.SetInnerText(xdom.H2(), "Biomes"), bTable, xjs.SetInnerText(xdom.H2(), "Plants"), pTable, ) } c.AppendChild(d) } }
func ServersTab() func(dom.Element) { forceUpdate := make(chan struct{}) ns := xdom.Button() ns.AddEventListener("click", false, func(dom.Event) { d := xdom.Div() o := overlay.New(d) d.AppendChild(transferFile("Server", "Upload/Download", 0, o)) o.OnClose(func() { go func() { forceUpdate <- struct{}{} }() }) xjs.Body().AppendChild(o) }) noneTd := xdom.Td() noneTd.ColSpan = 3 none := xjs.AppendChildren(xdom.Tr(), xjs.SetInnerText(noneTd, "No Servers Found")) serverList := xjs.AppendChildren(xdom.Table(), xjs.AppendChildren(xdom.Thead(), xjs.AppendChildren(xdom.Tr(), xjs.SetInnerText(xdom.Th(), "Server Name"), xjs.SetInnerText(xdom.Th(), "Status"), xjs.SetInnerText(xdom.Th(), "Controls"), )), none, ) nodes := xjs.AppendChildren(xdom.Div(), xjs.SetInnerText(xdom.H2(), "Servers"), xjs.SetInnerText(ns, "New Server"), serverList, ) servers := make(map[int]*Server) return func(c dom.Element) { c.AppendChild(nodes) updateStop := make(chan struct{}) registerUpdateStopper(c, updateStop) for { servs, err := RPC.ServerList() if err != nil { xjs.Alert("Error getting server list: %s", err) return } if none.ParentNode() != nil { serverList.RemoveChild(none) } for _, s := range servers { s.ID = -1 } for _, s := range servs { os, ok := servers[s.ID] if ok { os.Server = s } else { name := xdom.Td() status := xdom.Td() startStop := xdom.Button() os = &Server{ Server: s, row: xjs.AppendChildren(xdom.Tr(), name, status, xjs.AppendChildren(xdom.Td(), startStop), ), name: name, status: status, button: startStop, } servers[s.ID] = os serverList.AppendChild(os.row) name.Class().SetString("serverName") name.AddEventListener("click", false, func() func(dom.Event) { s := os return func(dom.Event) { go func() { d, err := RPC.ServerEULA(s.ID) if err != nil { d = "" } t := []tabs.Tab{ {"General", serverGeneral(s.Server)}, {"Properties", serverProperties(s.Server)}, {"Console", serverConsole(s.Server)}, } if d != "" { t = append(t, tabs.Tab{"EULA", serverEULA(s.Server, d)}) } div := xdom.Div() o := overlay.New(div) t = append(t, tabs.Tab{"Misc.", misc("server", s.Server.ID, o, RPC.RemoveServer)}) div.AppendChild(tabs.New(t)) o.OnClose(func() { go func() { forceUpdate <- struct{}{} }() }) xjs.Body().AppendChild(o) }() } }()) startStop.AddEventListener("click", false, func() func(dom.Event) { b := startStop s := os return func(dom.Event) { go func() { b.Disabled = true switch s.State { case data.StateStopped: err := RPC.StartServer(s.ID) if err != nil { xjs.Alert("Error starting server: %s", err) return } case data.StateRunning: err := RPC.StopServer(s.ID) if err != nil { xjs.Alert("Error stopping server: %s", err) return } default: return } go func() { forceUpdate <- struct{}{} }() }() } }()) } if os.Map >= 0 { xjs.SetInnerText(os.status, os.State.String()) switch os.State { case data.StateStopped: xjs.SetInnerText(os.button, "Start") os.button.Disabled = false case data.StateRunning: xjs.SetInnerText(os.button, "Stop") os.button.Disabled = false default: xjs.SetInnerText(os.button, "N/A") os.button.Disabled = true } } else { xjs.SetInnerText(os.status, "No Map") os.button.Disabled = true xjs.SetInnerText(os.button, "N/A") } xjs.SetInnerText(os.name, os.Name) } for id, s := range servers { if s.ID == -1 { delete(servers, id) serverList.RemoveChild(s.row) } } if len(servers) == 0 { serverList.AppendChild(none) } // Sleep until update if !updateSleep(forceUpdate, updateStop) { return } } } }