quick temporary UI for the web client.

This commit is contained in:
ririchiyo
2015-02-11 21:47:06 -05:00
parent 18e8059942
commit ac1452d391
3 changed files with 412 additions and 0 deletions

View File

@@ -1650,6 +1650,8 @@
#include "code\ZAS\Zone.dm" #include "code\ZAS\Zone.dm"
#include "interface\interface.dm" #include "interface\interface.dm"
#include "interface\skin.dmf" #include "interface\skin.dmf"
#include "interface\web\info.dms"
#include "interface\web\interface.dms"
#include "maps\_map.dm" #include "maps\_map.dm"
#include "maps\tgstation.dm" #include "maps\tgstation.dm"
#include "maps\RandomZLevels\Academy.dm" #include "maps\RandomZLevels\Academy.dm"

316
interface/web/info.dms Normal file
View File

@@ -0,0 +1,316 @@
<byondclass name="info">
<style type="text/css">
.byond_info {
overflow: hidden;
position: relative;
z-index: 0;
}
.byond_info_tabbar {
max-width: 80% !important;
}
.byond_info_tab {
border-top-left-radius: 0px !important;
border-top-right-radius: 0px !important;
border-bottom-right-radius: 0px !important;
border-bottom-left-radius: 0px !important;
border: 1px solid #000000;
margin-top: 0;
margin-right: 5px;
margin-bottom: -1px;
margin-left: -2px;
width: 85px;
height: 21px;
text-align: center;
}
.byond_info_tab.selected {
font-weight: normal !important;
}
.byond_info_contents {
}
.byond_info table {
}
.byond_info td {vertical-align: top;}
.byond_info td img {vertical-align: middle;}
.byond_info table td {
cursor: default;
}
.byond_info table.verbs {
table-layout: fixed;
}
.byond_info table.verbs td[verb]:hover {
font-weight: bold;
cursor: pointer;
}
</style>
<script type="text/javascript">
{
config: {
onShow: '',
onHide: '',
onTab: '',
rightClick: false,
_tabNames: [],
_tabs: {},
_tabInfo: {},
_tabInfoPending: {},
_curTab: null,
_updateTimer: {},
_clicked: false
},
fn: {
content: function() {return this.top;},
create: function() {
this.top.removeChild(this.ui.tab);
byond.css(this.ui.tabbar,'display','none');
},
stats: function(stats, verbs) {
var t=this, tb=t.ui.tabbar, tbc=tb.childNodes, e=t.ui.contents, c=t.config, tabs=c._tabs, tabNames=c._tabNames, info=c._tabInfo, pending=c._tabInfoPending;
if(!stats || !stats.length) stats = verbs;
else if(verbs) stats = stats.concat(verbs);
if(!stats || !(np=stats.length)) {
if(tabs.length) {tb.innerHTML = ''; tabs.splice(0,tabs.length); c._tabInfo={};}
if(this.shown) {this.shown=false; this.onhide();}
return;
}
if(!this.shown) {this.shown=true; this.onshow();}
var ih=byond.innerSize(e).height;
var i,j,l=stats.length,change,n,panel,curIdx=-1,tab,newIdx=-1;
for(i=0,l=stats.length; i<l; ++i) {
panel = stats[i];
panel.type = panel.items?'stats':'verbs';
n = panel.type+':'+panel.name;
if(c._curTab == n) {
curIdx = i;
delete pending[n];
if(panel.changed!=false) {panel.changed=false; t._updatePanel(panel, n);}
}
else if(panel.changed!=false) {pending[n] = panel; panel.changed=false;}
if(c._pendingTab == panel.name.toLowerCase()) {delete c._pendingTab; newIdx=i;}
if(i>=tabNames.length || n!=tabNames[i]) {
// prefer stats panel if nothing was clicked yet
if(!c._clicked && newIdx<0 && c._curTab && n.match(/^stats/) && c._curTab.match(/^verbs/)) newIdx = i;
change = true;
tab = tabs[n];
if(!tab) {
tabs[n] = tab = t.ui.tab.cloneNode();
tab.innerHTML = byond.htmlEncode(panel.name);
tab.onclick = t._tabClick.bind(t,n);
}
if(i >= tbc.length) tb.appendChild(tab);
else tb.insertBefore(tab,tbc[i]);
j = tabNames.indexOf(n);
if(j>=0) tabNames.splice(j,1);
tabNames.splice(i,0,n);
}
}
while(tabNames.length > l) {
change = true;
n = tabNames.pop();
tab = tabs[n];
tab.onclick = null;
if(tab.parentNode) tab.parentNode.removeChild(tab);
delete tabs[n];
if(tabInfo[n] && (j=tabInfo[n].table)) {
if(j.parentNode) j.parentNode.removeChild(j);
}
if(n == c._curTab && newIdx < 0) {
curIdx = Math.min(curIdx,l-1);
if(curIdx >= 0) setTimeout(t._tabClick.bind(t,tabNames[curIdx]),100);
}
}
if(change) t._recalcTabs();
if(curIdx < 0 && l) newIdx = 0;
if(newIdx >= 0) setTimeout(t._tabClick.bind(t,tabNames[newIdx]),100);
delete c._pendingTab;
e.scrollTop = Math.max(0, Math.min(e.scrollTop,e.scrollHeight-ih));
},
postLoad: function() {
byond.css(this.ui.tabbar,'display','');
if(!this.shown) this.onhide();
else this._recalcTabs();
},
_mouse: function(p,e) {
// call preventDefault() to stop browser's normal drag behavior (which we don't handle)
if(e) {
if(e.type.match(/(down|start)$/i)) {this.captureMouse(e); e.preventDefault();}
if(e.type.match(/(down|start|click)$/i)) {
var m = byond(':map');
if(m) m._getCoords(e);
}
if(e.type.match(/menu$/i)) e.preventDefault();
}
this.mouse(p,e);
},
dragTarget: function(e) {
// this will fail to get a panel name if dragging between cells, but it isn't a big deal
var t=this, c=t.config, i=c._tabInfo[c._curTab];
return (i && i.panel && i.panel.items) ? {panel:i.panel.name} : {};
},
_innerHeight: function(e) {
var bh=0, n, pads=['paddingTop','paddingBottom','borderTopWidth','borderBottomWidth'];
for(var j=0,l=pads.length; j<l; ++j) {
n=byond.cssPx(e,pads[j]); if(!isNaN(n)) bh += n;
}
return e.offsetHeight-bh;
},
_tabClick: function(n, ev) {
var t=this, c=t.config, tb=t.ui.tabbar, e=t.ui.contents, tab, conts, i, l, a, pend;
if(ev) c._clicked = true;
try {
c._curTab = n;
tab = c._tabs[n];
pend = c._tabInfoPending[n];
if(pend) {pend.now=true; t._updatePanel(pend,n);}
conts = c._tabInfo[n].table;
for(i=0,a=tb.querySelectorAll('.selected'),l=a.length; i<l; ++i) {
if(a[i] == tab) continue;
a[i].classList.remove('selected');
}
tab.classList.add('selected');
while(e.firstChild && e.firstChild != conts) e.removeChild(e.firstChild);
if(!e.firstChild) e.appendChild(conts);
t._recalcTabs();
} catch(_){console.log(''+_);}
if(c.onTab) t.input(c.onTab.replace(/\[\[\*\]\]/g, (c._curTab||'').replace(/^\w+:/,'')));
},
_recalcTabs: function(timed) {
var t=this, tb=t.ui.tabbar, e=t.ui.contents, c=t.config, tm;
byond.css(e,'height',t.loading?'100%':'calc(100% - '+tb.offsetHeight+'px)');
if(!timed) {
if((tm=c._tabTimer)) clearTimeout(tm);
c._tabTimer = setTimeout(t._recalcTabs.bind(t,1), 100);
}
else c._tabTimer = 0;
},
onsize: function() {
this._recalcTabs();
return byond.fn.onsize.call(this);
},
_sameItem: function(o1, o2) {
if(!o1) return !o2 || o2.null;
if(!o2) return o1.null;
return (o1.text == o2.text && o1.atom == o2.atom && o1.null == o2.null && o1.icon == o2.icon);
},
_sameAtom: function(o1, o2) {return o1.atom == o2.atom;},
_updatePanel: function(p, n) {
var t=this, oldp, cf=t.config, ti, newp, table, lst, oldlst, i, j, l, c, r, nc, nr, oldrows, obj, oldobj, re, ce, html, newrow, hasAtom;
if(typeof p == 'string') { // timer fired
ti = cf._updateTimer[n=p];
p = ti.info;
p.now = true;
ti = null;
delete cf._updateTimer[n];
}
else ti=cf._updateTimer[n];
oldp = cf._tabInfo[n];
if(!oldp) {
table = document.createElement('table');
byond.backstage().appendChild(table);
table.className=p.items?'stats':'verbs';
}
else {
if(!p.now) {
if(!ti) cf._updateTimer[n] = ti = {timer:setTimeout(t._updatePanel.bind(t, n), 500)};
ti.info = p;
return oldp;
}
table = oldp.table;
oldp = oldp.panel;
}
if(ti) {clearTimeout(ti.timer); delete cf._updateTimer[n];}
oldrows = table.rows.length;
newp = {table:table, panel:p};
if(lst=p.items) {
oldlst = oldp ? (oldp.items||[]) : [];
nr = p.rows;
newrow = '<td class=prefix></td><td></td><td class=suffix></td>';
while(oldrows > nr) table.deleteRow(--oldrows);
while(oldrows < nr) {
re = table.insertRow(oldrows++);
re.innerHTML = newrow;
}
for(i=r=0; r<nr; ++r) {
re = table.rows[r];
for(c=0; c<3; ++i,++c) {
if(t._sameItem(obj=lst[i], oldlst[i])) continue;
ce = re.cells[c];
html = '';
if(obj && obj.null) obj = null;
if(obj) {
if(obj.icon!=null && obj.icon!=undefined) {
hasAtom = typeof obj.atom == 'number';
html = '<img'+(hasAtom?' atom='+obj.atom:'')+' src="'+(hasAtom?t.atomIcon(obj.atom):byond.iconUrl(obj.icon))+'" />';
if(obj.text) html += ' '+byond.htmlEncode(obj.text);
if(hasAtom) byond.fillAtomIcons();
}
else if(obj.text) html = byond.htmlEncode(obj.text);
byond.attr(ce,'title',obj.text||'');
byond.attr(ce,'atom',obj.atom);
ce.onclick = ce.ondblclick = ce.onmouseover = ce.onmouseout = ce.onmousemove = ce.onmousedown = ce.onmouseup = ce.oncontextmenu = (typeof obj.atom == 'number') && c==1 && t._mouse.bind(t,{element:ce,atom:obj.atom,panel:p.name,id:t.id});
}
else {
ce.onclick = ce.ondblclick = ce.onmouseover = ce.onmouseout = ce.onmousemove = ce.onmousedown = ce.onmouseup = ce.oncontextmenu = null;
byond.attr(ce,'atom',null);
byond.attr(ce,'title','');
}
ce.innerHTML = html;
}
}
}
else if(lst=p.verbs) {
oldlst = oldp ? (oldp.verbs||[]) : [];
nc = 4; // eventually add more nuance
nr = Math.ceil((l = lst.length) / nc);
nc = Math.ceil(l / nr);
newp.cols = nc;
html = '';
for(c=r=j=0,i=nc*nr; i--;) {
if(!c) html += '<tr>';
obj = lst[j];
html += obj ? '<td title="'+byond.htmlEncode(obj.desc||'')+'" verb="'+byond.htmlEncode(obj.name)+'" onclick="byond(\''+t.id+'\').input(\''+byond.htmlEncode(obj.name.trim().replace(/\s+/g,'-'))+'\');return false">'+byond.htmlEncode(obj.name)+'</td>' : '<td></td>';
if(++c>=nc) {c=0; html += '</tr>'; j=++r;}
else j += nr;
}
table.innerHTML = html;
}
cf._tabInfo[n] = newp;
return newp;
}
},
winsetfn: {
onTab: function(v) {
var t=this,c=t.config;
if(typeof v == 'string') c.onTab = v;
else return c.onTab;
},
currentTab: function(v) {
var t=this,c=t.config,ct,a,i,l,n;
if(typeof v == 'string') {
v = v.toLowerCase();
for(a=c._tabNames,l=a.length,i=0; i<l; ++i) {
n = a[i].replace(/^\w+:/i,'').toLowerCase();
if(n == v) {t._tabClick(a[i],true); return;}
}
c._pendingTab = v; // can't find it; look in the next update
return;
}
if(!c._curTab) return null;
return c._curTab.replace(/^\w+:/i,'');
},
rightClick: function(v) {
var c=this.config;
v = byond.winset2bool(v);
if(v===undefined || v==null) return c.rightClick;
c.rightClick = v;
}
}
}
</script>
<div id=tabbar class="byond_info_tabbar"></div><div id=tab class="byond_info_tab byond_border byond_buttonbk"></div><div id=contents class="byond_info_contents byond_border1"></div>
</byondclass>

View File

@@ -0,0 +1,94 @@
<style>
body {
font-family: sans-serif;
font-size: 10pt;
}
* {
border-color: currentColor;
}
#skin {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
text-align: left;
}
#mainvsplit {
width: 100%;
height: calc(100% - 1.5em);
}
.byond_map canvas {
color: black;
}
#input {
width: 100%;
height: 1.5em;
}
.byond_input input {
border-width: 1px;
border-style: solid;
}
#rbuttons {
text-align: center;
padding: 10px;
}
#rbuttons div[byondclass=button] {
display: inline-block;
margin: 5px; 10px;
background-color:#000000;
}
</style>
<script>
var defaultSkin = (function(){
var panesShown = {};
var npanes = 0;
return {
show: function(id) {
if(panesShown[id]) return;
panesShown[id] = true;
byond('rbutton_'+id).winset({'isVisible':true,'isChecked':true});
++npanes;
byond('rside').winset({left:'rbuttons'});
byond('rpane').winset({left:id});
},
hide: function(id) {
if(!panesShown[id]) return;
delete panesShown[id];
var button = byond('rbutton_'+id);
button.winset({'isVisible':false});
if(''+button.winget('isChecked') ==' true') byond('rbutton_text').winset({isChecked:true});
var rpane = byond('rpane');
if(rpane.winget('left') == id) rpane.winset({left:''});
if(!--npanes) byond('rside').winset({left:''});
}
};
})();
</script>
<body>
<div id="mainvsplit" byondclass="child" skinparams="is-vertical=true">
<div id="map" byondclass='map'></div>
<div id="rside" byondclass="child" skinparams="right=rpane;fit=left">
<div id="rpane" byondclass="child" style="width:100%;height:100%;" skinparams="right=output">
<div id="output" byondclass='output' isdefault=1></div>
</div>
</div>
</div>
<div id="input" byondclass='input' isdefault=1></div>
<div id="rbuttons" byondclass="pane">
<div id="rbutton_text" byondclass="button" skinparams="text=Text;command='.skin byond(\'rpane\').winset({left:\'\'})';group=rbutton;isChecked=true"></div>
<div id="rbutton_browser" byondclass="button" skinparams="text=Browser;command='.skin byond(\'rpane\').winset({left:\'browser\'})';group=rbutton" style="display:none"></div>
<div id="rbutton_info" byondclass="button" skinparams="text=Info;command='.skin byond(\'rpane\').winset({left:\'info\'})';group=rbutton" style="display:none"></div>
<div id="rbutton_special" byondclass="button" skinparams="text=Special;command='.skin byond(\'rpane\').winset({left:\'window1\'})';group=rbutton" style="display:none"></div>
</div>
<div byondclass="pane">
<div id="browser" byondclass='browser' isdefault=1 skinparams="on-show='.skin defaultSkin.show(\'browser\')';on-hide='.skin defaultSkin.hide(\'browser\')'"></div>
<div id="info" byondclass='info' isdefault=1 skinparams="on-show='.skin defaultSkin.show(\'info\')';on-hide='.skin defaultSkin.show(\'info\')'"></div>
</div>
<div byondclass="status" id="status" isdefault=1></div>
<div byondclass="dpad" id="dpad" isdefault=1></div>
<div byondclass="hotbar" id="hotbar" isdefault=1></div>
</body>