mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 02:16:05 +00:00
316 lines
10 KiB
Plaintext
316 lines
10 KiB
Plaintext
<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> |