]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/standalone.html
update standalone web to more complete version
[taylor/freespace2.git] / src / network / standalone.html
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="utf-8" http-equiv="Content-Language" content="en"/>
5 <title>FreeSpace Standalone</title>
6
7 <script>
8 var standalone_socket = new WebSocket("ws://" + document.URL.substr(7).split('/')[0], "standalone");
9
10 try {
11   standalone_socket.onmessage = function got_packet(msg) {
12     if (msg.data == "reset") {
13       reset_ui();
14     } else if (msg.data == "popup ") {
15       popup(msg.data.substr(7));
16     } else if (msg.data[0] == 'D') {
17       document.getElementById("debug").textContent = msg.data.substr(2);
18     } else if (msg.data[0] == 'T') {
19       document.title = msg.data.substr(2);
20     } else if (msg.data[0] == 'S') {
21       do_server_tab(msg.data.substr(2));
22     } else if (msg.data[0] == 'M') {
23       do_multi_tab(msg.data.substr(2));
24     } else if (msg.data[0] == 'P') {
25       do_player_tab(msg.data.substr(2));
26     } else if (msg.data[0] == 'G') {
27       do_gs_tab(msg.data.substr(2));
28     }
29   };
30 } catch (exception) {
31   alert('<p>Error ' + exception);
32 }
33
34 function shutdown() {
35   standalone_socket.send("shutdown");
36   standalone_socket.close();
37   reset_ui();
38   popup("Shutdown;Shutdown complete");
39 }
40
41 function popup(msg) {
42   var modal = document.getElementById("popup");
43   var content = [ document.getElementById("modal-title"), document.getElementById("field1"), document.getElementById("field2") ];
44   var x;
45
46   if (msg.length) {
47     var fields = msg.split(';');
48
49     for (x = 0; x < fields.length; x++) {
50       if (fields[x].length) {
51         content[x].textContent = fields[x];
52       }
53     }
54
55     modal.style.display = "block";
56   } else {
57     modal.style.display = "none";
58   }
59 }
60
61 function reset_ui() {
62   var table;
63   var len;
64   var j;
65
66   /* hide popup */
67   document.getElementById("popup").style.display = "none";
68
69   /* server tab */
70   document.getElementById("n_conn").textContent = "0";
71   table = document.getElementById("connections");
72   len = table.rows.length;
73
74   for (j = 1; j < len; j++) {
75     table.rows[j].id = '';
76     table.rows[j].onclick = '';
77     table.rows[j].cells[0].innerHTML = '&nbsp;';
78     table.rows[j].cells[1].innerHTML = "";
79   }
80
81   /* multi-player tab */
82   document.getElementById("fps_rel").textContent = "0.0";
83   document.getElementById("mission_name").textContent = "";
84   document.getElementById("mission_time").textContent = "";
85
86   document.getElementById("max_players").textContent = "";
87   document.getElementById("max_observers").textContent = "";
88   document.getElementById("security").textContent = "";
89   document.getElementById("respawns").textContent = "";
90
91   table = document.getElementById("mgoals");
92   len = table.rows.length;
93
94   for (j = 1; j < len; j++) {
95     var cell = table.rows[j].cells[0];
96
97     if (cell.childNodes.length > 1) {
98       cell.removeChild(cell.childNodes[1]);
99     }
100   }
101
102   /* player info tab */
103   document.getElementById("players").selectedIndex = -1;
104   document.getElementById("ship_type").textContent = "";
105   document.getElementById("player_ping").textContent = "";
106
107   table = document.getElementById("stats");
108   len = table.rows.length;
109
110   for (j = 1; j < len; j++) {
111     table.rows[j].cells[1].innerHTML = "";
112     table.rows[j].cells[2].innerHTML = "";
113   }
114
115   /* gs tab */
116   document.getElementById("gs_players").selectedIndex = -1;
117   document.getElementById("smsg_box").value = "";
118 }
119
120 function do_server_tab(msg) {
121   var table;
122   var row;
123   var j;
124   var len;
125
126   if (msg.substring(0, 5) == "name ") {
127     document.getElementById("server_name").value = msg.substr(5);
128   } else if (msg.substring(0, 5) == "pass ") {
129     document.getElementById("host_pass").value = msg.substr(5);
130   } else if (msg.substring(0, 5) == "ping ") {
131     table = document.getElementById("connections");
132     var ping_list = msg.substr(5).split(';', 12);
133     len = ping_list.length;
134
135     for (j = 0; j < len; j++) {
136       var ping = ping_list[j].split(',');
137       row = table.rows.namedItem(ping[0]);
138
139       if (Boolean(row)) {
140           row.cells[1].innerHTML = ping[1];
141       }
142     }
143   } else if (msg.substring(0, 5) == "conn ") {
144     table = document.getElementById("connections");
145     var players = document.getElementById("players");
146     var cur_player;
147     var gs_players = document.getElementById("gs_players");
148     var connections = msg.substr(5).split(';', 12);
149     len = connections.length - 1;
150
151     if (players.selectedIndex != -1) {
152       cur_player = players.value;
153     }
154
155     while (players.options.length) {
156       players.remove(0);
157       gs_players.remove(0);
158     }
159
160     for (j = 0; j < len; j++) {
161       var conn = connections[j].split(',');
162       row = table.rows[j+1];
163
164       var option = document.createElement("option");
165       option.text = conn[0];
166       gs_players.add(option);
167
168       option = document.createElement("option");
169       option.text = conn[0];
170       players.add(option);
171
172       row.id = conn[1];
173       row.cells[0].innerHTML = conn[1];
174
175       if (Boolean(conn[2])) {
176         row.cells[1].innerHTML = conn[2];
177       }
178
179       row.onclick = function() { kick_conn(conn[0], conn[1]); };
180     }
181
182     gs_players.selectedIndex = -1;
183     players.value = cur_player;
184     document.getElementById("n_conn").textContent = j;
185
186     len = table.rows.length;
187
188     for (j = j+1; j < len; j++) {
189       row = table.rows[j];
190
191       row.id = '';
192       row.onclick = '';
193       row.cells[0].innerHTML = "&nbsp;"
194       row.cells[1].innetHTML = "";
195     }
196   }
197 }
198
199 function do_multi_tab(msg) {
200   if (msg.substring(0, 4) == "fps ") {
201     document.getElementById("fps_rel").textContent = msg.substr(4);
202   } else if (msg.substring(0, 5) == "name ") {
203     document.getElementById("mission_name").textContent = msg.substr(5);
204   } else if (msg.substring(0, 5) == "time ") {
205     document.getElementById("mission_time").textContent = msg.substr(5);
206   } else if (msg.substring(0, 5) == "info ") {
207     var nginfo = msg.substr(5).split(',');
208     document.getElementById("max_players").textContent = nginfo[0];
209     document.getElementById("max_observers").textContent = nginfo[1];
210     document.getElementById("security").textContent = nginfo[2];
211     document.getElementById("respawns").textContent = nginfo[3];
212   } else if (msg.substring(0, 5) == "goal ") {
213     var objectives = msg.substr(5).split(';');
214     var gtable = document.getElementById("mgoals");
215     var j;
216     var j_len;
217     var x;
218     var x_len;
219
220     j_len = objectives.length;
221
222     for (j = 0; j < j_len; j++) {
223       var goals = objectives[j].split(',');
224       var cell = gtable.rows[j+1].cells[0];
225
226       if (cell.childNodes.length > 1) {
227         cell.removeChild(cell.childNodes[1]);
228       }
229
230       var list = document.createElement("ul");
231  
232       x_len = goals.length;
233
234       for (x = 0; x < x_len; x++) {
235         var item = document.createElement("li");
236         item.innerHTML = goals[x].substr(2);
237
238         var status = goals[x].substring(0, 2);
239         if (status == "c ") {
240           item.style.color = "green";
241         } else if (status == "f ") {
242           item.style.color = "red";
243         } else {
244           item.style.color = "#555";
245         }
246
247         list.appendChild(item);
248       }
249
250       cell.appendChild(list);
251     }
252   }
253 }
254
255 function do_player_tab(msg) {
256   if (msg.substring(0, 5) == "info ") {
257     var pinfo = msg.substr(5).split(';');
258
259     document.getElementById("ship_type").textContent = pinfo[0];
260     document.getElementById("player_ping").textContent = pinfo[1];
261
262     var all_stats = pinfo[2].split(',');
263     var mission_stats = pinfo[3].split(',');
264     var table = document.getElementById("stats");
265     var j;
266     var len = table.rows.length;
267
268     for (j = 1; j < len; j++) {
269       var row = table.rows[j];
270
271       row.cells[1].innerHTML = all_stats[j-1];
272       row.cells[2].innerHTML = mission_stats[j-1];
273     }
274   }
275 }
276
277 function do_gs_tab(msg) {
278   if (msg.substring(0, 5) == "mesg ") {
279     document.getElementById("smsg_box").value += msg.substr(5);
280   }
281 }
282
283 function change_server_name() {
284   standalone_socket.send("S:name " + document.getElementById("server_name").value);
285 }
286
287 function change_host_pass() {
288   standalone_socket.send("S:pass " + document.getElementById("host_pass").value);
289 }
290
291 function kick_conn(name, addr) {
292   var kick = confirm("Kick player? \n\n" + name + "@" + addr);
293
294   if (kick) {
295     standalone_socket.send("S:kick " + addr);
296   }
297 }
298
299 function send_server_message() {
300   var smsg = document.getElementById("server_message");
301   standalone_socket.send("G:smsg " + smsg.value);
302   smsg.value = "";
303 }
304
305 function refresh_missions() {
306   standalone_socket.send("G:mrefresh");
307 }
308
309 function switch_tab(tab) {
310   var tabbox = document.getElementById("tab-box");
311   var topnav = document.getElementById("topnav");
312   var x;
313
314   for (x = 0; x < 4; x++) {
315     if (tab == x) {
316       topnav.children[x].children[0].className = "active";
317       tabbox.children[x].className = "tab-visible";
318     } else {
319       topnav.children[x].children[0].className = '';
320       tabbox.children[x].className = "tab-hidden";
321     }
322   }
323 }
324
325 function smsg_submit(e) {
326   e = e || window.event;
327
328   if (e.keyCode == 13) {
329     document.getElementById("smsg_submit").click();
330     return false;
331   }
332
333   return true;
334 }
335
336 function get_player_info() {
337   var n = document.getElementById("players").selectedIndex;
338
339   if (n != -1) {
340     standalone_socket.send("P:info " + document.getElementById("players").options[n].text);
341   }
342 }
343
344 function set_fps() {
345   var fps = document.getElementById("multi_fps").value;
346   document.getElementById("fps_cap").textContent = fps;
347
348   standalone_socket.send("M:fps " + fps);
349 }
350 </script>
351
352 <style type="text/css">
353 body {
354   font-family: Arial, Helvetica, sans-serif
355 }
356
357 .container {
358   width: 565px;
359   margin: 0 auto
360 }
361
362 .tab-box {
363   background-color: #ddd;
364   padding: 10px 25px
365 }
366
367 .tab-hidden {
368   display: none
369 }
370
371 .tab-visible {
372   display: inline-block;
373   width: 100%
374 }
375
376 .button {
377   border: none;
378   border-radius: 4px;
379   background-color: #444;
380   color: #eee;
381   padding: 5px 10px;
382   text-align: center;
383   text-decoration: none;
384   display: inline-block;
385   font-size: 14px;
386   cursor: pointer
387 }
388
389 .button:hover {
390   background-color: #111;
391   color: #fff
392 }
393
394 ul.topnav {
395   list-style-type: none;
396   margin: 0;
397   padding: 0;
398   overflow: hidden;
399   background-color: #3a3a3a
400 }
401
402 ul.topnav li {
403   float: left
404 }
405
406 ul.topnav a {
407   display: inline-block;
408   color: #e2e2e2;
409   text-align: center;
410   padding: 14px 16px;
411   text-decoration: none;
412   transition: .3s;
413   font-size: 17px;
414   cursor: pointer;
415   outline: 0
416 }
417
418 a:hover,
419 ul.topnav a.active {
420   background-color: #111;
421   color: #fff
422 }
423
424 ul.topnav li.shutdown {
425   float: right;
426   padding-left: 40px
427 }
428
429 ul.topnav li.shutdown a {
430   background-color: #8b0000
431 }
432
433 ul.topnav li.shutdown a:hover {
434   background-color: red;
435   color: #fff
436 }
437
438 .debug_state {
439   font-size: smaller;
440   color: #696969;
441   float: right;
442   padding: 2px 4px
443 }
444
445 #server_name,
446 #host_pass {
447   width: 20em;
448   border: none;
449   padding: 5px 10px
450 }
451
452 #connections,
453 #stats {
454   border: 1px solid #444;
455   border-spacing: 0;
456   border-collapse: collapse;
457   width: 100%;
458   min-height: 13em
459 }
460
461 #connections th,
462 #stats th {
463   background-color: #444;
464   color: #fff;
465   padding: 5px 10px;
466   text-align: left;
467   font-size: small
468 }
469
470 #connections td,
471 #stats td {
472   padding: 5px 15px;
473   text-align: left;
474   font-family: Courier New, Courier, monospace;
475   font-size: small
476 }
477
478 #connections tr:nth-child(odd),
479 #stats tr:nth-child(odd) {
480   background-color: #d5d5d5
481 }
482
483 #connections tr:hover,
484 #connections tr:hover:nth-child(odd) {
485   background-color: #eaeaea
486 }
487
488 table.name_pass td {
489   padding: 5px 0
490 }
491
492 table.name_pass label {
493   padding-right: 10px
494 }
495
496 #server_message {
497   margin-top: 10px;
498   padding: 5px 10px;
499   border: none;
500   width: 100%;
501   box-sizing: border-box
502 }
503
504 .players,
505 .players option {
506   min-width: 20em;
507   padding: 2px 8px;
508   margin-left: 10px
509 }
510
511 #smsg_box {
512   width: 100%;
513   box-sizing: border-box;
514   resize: none;
515   background-color: #fff;
516   border: 1px solid #bbb;
517   border-radius: 2px
518 }
519
520 table.minfo,
521 table.pinfo {
522   margin-top: 30px;
523   margin-bottom: 30px;
524   border: none;
525   border-collapse: collapse
526 }
527
528 table.minfo td,
529 table.pinfo td {
530   padding: 5px 0
531 }
532
533 table.minfo span,
534 table.pinfo span {
535   font-family: Courier New, Courier, monospace;
536   font-size: small;
537   padding: 5px 10px;
538   min-width: 12em;
539   margin-left: 10px
540 }
541
542 .player_sel {
543   margin-top: 10px
544 }
545
546 .fps_block {
547   display: inline-block;
548   width: 100%;
549   margin-bottom: 20px
550 }
551
552 #multi_fps {
553   width: 100%;
554   margin: 10px 0;
555   box-sizing: border-box
556 }
557
558 .fps_cap {
559   display: block;
560   float: left
561 }
562
563 .fps_rel {
564   display: block;
565   float: right
566 }
567
568 .fps_cap span,
569 .fps_rel span {
570   font-family: Courier New, Courier, monospace;
571   padding: 5px 0 5px 10px
572 }
573
574 .mgoals,
575 .nginfo {
576   border: none;
577   border-collapse: collapse;
578   display: inline-block
579 }
580
581 .nginfo {
582   float: right
583 }
584
585 .mgoals {
586   float: left;
587   min-width: 15em;
588   min-height: 17em;
589   background-color: #fff;
590   margin-bottom: 15px
591 }
592
593 .mgoals th,
594 .nginfo th {
595   padding: 5px;
596   text-align: left
597 }
598
599 .nginfo th {
600   border-bottom: 1px solid #444
601 }
602
603 .mgoals th {
604   background-color: #ddd;
605   width: 15em
606 }
607
608 .mgoals td,
609 .nginfo td {
610   padding: 5px 10px;
611   font-size: small
612 }
613
614 .mgoals ul {
615   padding: 0 1.5em;
616   margin: 0
617 }
618
619 .modal {
620   display: none;
621   position: fixed;
622   z-index: 1;
623   left: 0;
624   top: 0;
625   width: 100%;
626   height: 100%;
627   overflow: auto;
628   background-color: #000;
629   background-color: rgba(0, 0, 0, .4)
630 }
631
632 .modal-content {
633   background-color: #fefefe;
634   margin: 10em auto;
635   border: 2px solid #111;
636   width: 25em
637 }
638
639 .modal-title {
640   background-color: #444;
641   color: #fff;
642   padding: 10px;
643   font-weight: 700
644 }
645
646 .modal-body {
647   padding: 20px;
648   margin-top: 2em;
649   height: 4em
650 }
651 </style>
652 </head>
653
654 <body>
655
656 <div class="container">
657   <ul class="topnav" id="topnav">
658     <li><a onclick="switch_tab(0);" href="javascript:void(0);" class="active">Server</a></li>
659     <li><a onclick="switch_tab(1);" href="javascript:void(0);">Multi-Player</a></li>
660     <li><a onclick="switch_tab(2);" href="javascript:void(0);">Player Info</a></li>
661     <li><a onclick="switch_tab(3);" href="javascript:void(0);">God Stuff</a></li>
662     <li class="shutdown"><a onclick="shutdown();" href="javascript:void(0);">Shutdown</a></li>
663   </ul>
664
665   <div class="tab-box" id="tab-box">
666     <div id="server_tab" class="tab-visible">
667       <table class="name_pass">
668         <tr><td><label for="server_name">Server Name </label></td><td><input id="server_name" type="text" value="" maxlength="31" onchange="change_server_name();"></td></tr>
669         <tr><td><label for="host_pass">Host Password </label></td><td><input id="host_pass" type="text" value="" maxlength="15" onchange="change_host_pass();"></td></tr>
670       </table>
671       <hr>
672       <p>Connections : <span id="n_conn">0</span></p>
673       <p>
674         <table id="connections">
675           <tr><th style="min-width:20em;">IP Address</th><th style="min-width:5em;">Ping</th></tr>
676           <tr><td>&nbsp;</td><td></td></tr>
677           <tr><td>&nbsp;</td><td></td></tr>
678           <tr><td>&nbsp;</td><td></td></tr>
679           <tr><td>&nbsp;</td><td></td></tr>
680           <tr><td>&nbsp;</td><td></td></tr>
681           <tr><td>&nbsp;</td><td></td></tr>
682           <tr><td>&nbsp;</td><td></td></tr>
683           <tr><td>&nbsp;</td><td></td></tr>
684           <tr><td>&nbsp;</td><td></td></tr>
685           <tr><td>&nbsp;</td><td></td></tr>
686           <tr><td>&nbsp;</td><td></td></tr>
687           <tr><td>&nbsp;</td><td></td></tr>
688         </table>
689       </p>
690     </div>
691
692     <div id="multi_tab" class="tab-hidden">
693       <div class="fps_block">
694         <input type="range" id="multi_fps" min="15" max="60" value="30" step="1" oninput="set_fps();">
695         <div class="fps_cap">
696           Frame Cap: <span id="fps_cap">30</span>
697         </div>
698         <div class="fps_rel">
699           Realiazed FPS: <span id="fps_rel">0.0</span>
700         </div>
701       </div>
702       <hr>
703       <table class="minfo">
704         <tr><td>Mission Name: </td><td><span id="mission_name"></span></td></tr>
705         <tr><td>Mission Time: </td><td><span id="mission_time"></span></td></tr>
706       </table>
707       <table class="mgoals" id="mgoals">
708         <tr><th>Mission Goals</th></tr>
709         <tr><td>Primary Objectives</td></tr>
710         <tr><td>Secondary Objectives</td></tr>
711         <tr><td>Bonus Objectives</td></tr>
712       </table>
713       <table class="nginfo">
714         <tr><th colspan="2">Netgame Information</th></tr>
715         <tr><td>Max Players</td><td><span id="max_players"></span></td></tr>
716         <tr><td>Max Observers</td><td><span id="max_observers"></span></td></tr>
717         <tr><td>Security</td><td><span id="security"></span></td></tr>
718         <tr><td>Respawns</td><td><span id="respawns"></span></td></tr>
719       </table>
720     </div>
721
722     <div id="pilot_tab" class="tab-hidden">
723       <div class="player_sel">
724         <label for="players">Player</label>
725         <select id="players" class="players" onchange="get_player_info();">
726         </select>
727       </div>
728       <table class="pinfo">
729         <tr><td>Ship Type: </td><td><span id="ship_type"></span></td></tr>
730         <tr><td>Avg Ping: </td><td><span id="player_ping"></span></td></tr>
731       </table>
732       <p>
733         <table id="stats">
734           <tr><th>Stats</th><th>All Time</th><th>Mission</th></tr>
735           <tr><td>Primary Shots</td><td></td><td></td></tr>
736           <tr><td>Primary Hits</td><td></td><td></td></tr>
737           <tr><td>Primary BH Hits</td><td></td><td></td></tr>
738           <tr><td>Primary Hit %</td><td></td><td></td></tr>
739           <tr><td>Primary BH Hit %</td><td></td><td></td></tr>
740           <tr><td>Secondary Shots</td><td></td><td></td></tr>
741           <tr><td>Secondary Hits</td><td></td><td></td></tr>
742           <tr><td>Secondary BH Hits</td><td></td><td></td></tr>
743           <tr><td>Secondary Hit %</td><td></td><td></td></tr>
744           <tr><td>Secondary BH Hit %</td><td></td><td></td></tr>
745           <tr><td>Assists</td><td></td><td></td></tr>
746         </table>
747       </p>
748     </div>
749
750     <div id="godstuff_tab" class="tab-hidden">
751       <div class="player_sel">
752         <label for="gs_players">Player</label>
753         <select id="gs_players" class="players">
754         </select>
755       </div>
756       <div style="margin-top: 30px;">
757           <p>
758           <label for="server_message">Server Message</label>
759           <br>
760           <input id="server_message" type="text" value="" onkeypress="return smsg_submit(event);">
761           <input id="smsg_submit" type="button" onclick="send_server_message();" style="display:none;">
762         </p>
763         <textarea readonly rows="20" id="smsg_box" autocomplete="off"></textarea>
764       </div>
765       <p>
766         <input class="button" type="button" value="Refresh Missions" onclick="refresh_missions();">
767       </p>
768     </div>
769   </div>
770
771   <div id="debug" class="debug_state"></div>
772 </div>
773
774 <div id="popup" class="modal">
775   <div class="modal-content">
776     <div class="modal-title" id="modal-title"></div>
777     <div class="modal-body">
778       <span id="field1"></span>&nbsp;<span id="field2"></span>
779     </div>
780   </div>
781 </div>
782
783 </body>
784 </html>