to output window (HTML format) */
screenWrite: function (str) {
var lastIndex = -1;
var i;
while ((i = str.indexOf("
", lastIndex + 1)) != -1) {
this.updateLineCount(this.lineCount + 1);
lastIndex = i + 4; /* 4 =
length */
}
var dummy = document.createElement("span");
dummy.innerHTML = str;
var l = dummy.childNodes.length;
for (i = 0; i < l; ++i)
this.output.appendChild(dummy.childNodes[0]);
if (!this.focus)
this.startTitleAlert();
if (!this.scrollLock)
this.scrollBottom();
},
clearScreen: function(l) {
if (l == "all") {
var cl = this.output.childNodes.length;
for (var i = 0; i < cl; i++)
/* childNodes is "live", so always index 0 for the next element */
this.output.removeChild(this.output.childNodes[0]);
this.updateLineCount(1);
return;
}
var cLines;
if (l == "half")
cLines = (this.lineCount / 2) | 0; // (int) cast
else if (this.lineCount >= l)
cLines = this.lineCount - l;
else
return;
cLines = this.removeLines(this.output, cLines);
this.updateLineCount(this.lineCount - cLines);
},
removeLines: function(root, num) {
var linesRemoved = 0;
var cl = root.childNodes.length;
for (var i = 0; i < cl; ++i) {
if (linesRemoved == num)
return linesRemoved;
var n = root.childNodes[0];
if (n.nodeType == 1) { /* it's an Element */
if (n.nodeName.toLowerCase() == "br") { /* line break found */
root.removeChild(n);
++linesRemoved;
} else {
linesRemoved += this.removeLines(n, num - linesRemoved);
if (n.childNodes.length == 0) {
root.removeChild(n); /* the element is empty, get rid of it */
}
}
} else {
root.removeChild(n);
}
}
return linesRemoved;
},
updateLineCount: function(l) {
this.lineCount = l | 0; // yes, this casts to an integer...
var nl = document.getElementById("numLinesInScreen");
if (nl)
nl.innerHTML = this.lineCount;
return this.lineCount;
},
/* Rearrange UI elements.
Elements that are dynamically positioned should be treated here */
rearrange: function() {
var d = getViewportDimensions();
var p;
/* commandline */
var c = this.cmdline;
c.style.width = (d.width - 20 - (this.numIconsVisible * this.iconWidth)) + "px";
/* icons bar */
var ib = document.getElementById("iconsBar");
p = findPos(c);
ib.style.top = (p[1]) + "px";
/* output window */
var o = this.output;
o.style.height = (d.height - (c.offsetHeight + 1) - 40) + "px";
o.style.width = (d.width - 40) + "px";
/* optionsMenu */
var ic = document.getElementById("i-clear");
var cs = document.getElementById("optionsMenu");
p = findPos(ic);
cs.style.left = (p[0] - cs.offsetWidth + ic.offsetWidth) + "px";
cs.style.top = (p[1] + 1 - cs.offsetHeight) + "px";
/* connectionMenu */
var icn = this.getActiveConnectionIcon();
var cm = document.getElementById("connectionMenu");
p = findPos(icn);
cm.style.left = (p[0] - cm.offsetWidth + icn.offsetWidth) + "px";
cm.style.top = (p[1] + 1 - cm.offsetHeight) + "px";
/* fixing fieldset elements inside menus */
var fields = document.getElementsByTagName("fieldset");
for (var i = 0; i < fields.length; ++i) {
if (fields[i].lastChild.className != "fsSpacer") {
var sp = document.createElement("div");
sp.className = "fsSpacer";
sp.style.height = "0px";
sp.style.width = (fields[i].parentNode.offsetWidth - 45) + "px";
fields[i].appendChild(sp);
}
}
/* command guide */
var guide = document.getElementById("cmdGuide");
if (guide.style.display != "none") {
p = findPos(c);
guide.style.top = (p[1] - guide.offsetHeight - 20) + "px";
}
},
selectFont: function(name, save) {
document.body.className = name;
if (save)
createCookie("font", name, 30);
},
bodyOnClick: function(e) {
var rightclick;
if (!e) e = window.event;
if (e.which) rightclick = (e.which == 3);
else if (e.button) rightclick = (e.button == 2);
/* If there's a selection, let's not change the focus */
/* http://www.quirksmode.org/dom/range_intro.html */
var userSelection;
if (window.getSelection)
userSelection = window.getSelection();
else if (document.selection) // should come last; Opera!
userSelection = document.selection.createRange();
var selectedText = userSelection;
if (userSelection.text)
selectedText = userSelection.text;
else if (selectedText.toString)
selectedText = selectedText.toString();
else
selectedText = "";
/* If it's not a right click and there's no text selected,
let's automatically focus the command line */
if (!rightclick && (!selectedText || selectedText.length < 1)) {
if (!window.disableCmdFocus)
this.cmdline.focus();
var o;
o = document.getElementById("optionsMenu");
if (o.style.display != "none")
o.style.display = "none";
o = document.getElementById("connectionMenu");
if (o.style.display != "none")
o.style.display = "none";
o = document.getElementById("logSave");
if (o.style.display != "none") {
o.style.display = "none";
window.disableCmdFocus = false;
}
}
},
/*
* Title alert
*/
stopTitleAlert: function() {
if (window.titleIId) {
clearInterval(window.titleIId);
window.titleIId = null;
document.title = m.windowTitle;
}
},
startTitleAlert: function() {
document.title = document.title == m.windowTitleAlert ? m.windowTitle : m.windowTitleAlert;
if (window.titleIId == null) {
var that = this;
window.titleIId = setInterval(function(){that.startTitleAlert();}, 1000);
document.body.onmousemove = function() {
that.stopTitleAlert();
document.body.onmousemove = function(){};
};
}
},
/*
* UI State
*/
setEcho: function (b) {
b = b ? true : false;
if (this.echo == b)
return;
this.echo = b;
// Replacing input text by password or password by text
var newc = document.getElementById("cmdline-swap");
newc.setAttribute("id", "cmdline");
newc.style.display = "inline";
this.cmdline.setAttribute("id", "cmdline-swap");
this.cmdline.style.display = "none";
this.cmdline = newc;
this.initCmdLine();
this.rearrange(); // it will resize the cmdline properly
},
setFocus: function (b) {
this.focus = b ? true : false;
},
setConnectionState: function(state) {
if (state == "connecting") {
this.connState = "connecting";
this.setIconConnecting();
this.screenWrite(m.connecting);
} else if (state == "connected") {
this.connState = "connected";
this.setIconConnected();
this.screenWrite(m.connected);
} else if (state == "disconnected") {
this.connState = "disconnected";
this.setIconDisconnected();
this.screenWrite(m.disconnected);
} else {
alert("Invalid connection state!");
return;
}
this.rearrange();
},
setIconConnecting: function () {
clearInterval(this.connectingIId);
var that = this;
this.connectingIId = setInterval(function(){that.swapIconConnected}, 300);
},
/* helper for setIconConnecting */
swapIconConnected: function () {
if (this.iConnOn.style.display == "none") {
this.iConnOn.style.display = "inline";
this.iConnOff.style.display = "none";
} else {
this.iConnOn.style.display = "none";
this.iConnOff.style.display = "inline";
}
},
setIconConnected: function () {
clearInterval(this.connectingIId);
this.iConnOn.style.display = "inline";
this.iConnOff.style.display = "none";
},
setIconDisconnected: function () {
clearInterval(this.connectingIId);
this.iConnOn.style.display = "none";
this.iConnOff.style.display = "inline";
},
getActiveConnectionIcon: function() {
if (this.iConnOn.style.display == "none")
return this.iConnOff;
else
return this.iConnOn;
},
/* Messages from HMUD_Client */
handleMessage: function(msg, info) {
switch (msg) {
case "loaded":
this.screenWrite(m.clientLoaded);
break;
case "connecting":
this.setConnectionState("connecting");
break;
case "connected":
this.setConnectionState("connected");
break;
case "disconnected":
this.setConnectionState("disconnected");
break;
case "ioError":
this.screenWrite(m.ioError); /* no change in state, I guess */
break;
case "securityError":
this.screenWrite(m.securityError);
this.setConnectionState("disconnected");
break;
case "receive":
this.screenWrite(info);
break;
case "echoOn":
this.setEcho(true);
break;
case "echoOff":
this.setEcho(false);
break;
case "usingIE":
return BrowserDetect.browser == "Explorer";
default:
return false;
}
return true;
}
};
/*
* History navigation
*/
var HMUD_History = {
commands: [],
pointer: -1, // -1 means the user is out of the history navigation
/* previous = true, next = false */
get: function(previous) {
if (this.commands.length < 1)
return "";
if (previous) {
if (this.pointer == -1)
return this.commands[this.pointer = this.commands.length - 1];
else if (this.pointer == 0)
return this.commands[0];
else
return this.commands[--this.pointer];
} else {
if (this.pointer == -1)
return "";
else if (this.pointer == this.commands.length - 1) { // out of range
this.pointer = -1;
return "";
} else
return this.commands[++this.pointer];
}
},
previous: function() { return this.get(true); },
next: function() { return this.get(false); },
add: function(cmd) {
// adding to history always clears the pointer
this.pointer = -1;
if (cmd.length < c.historyMinLength)
return;
/* if the command is the same as the previous one, let's not repeat it in the history */
if (cmd == this.commands[this.commands.length - 1]) {
return;
}
if (this.commands.push(cmd) > c.maxHistorySize)
this.commands.shift();
}
};
var HMUD_Menu = {
connection: function () {
var d = document;
var cm = d.getElementById("connectionMenu");
if (cm.style.display == "none") {
cm.innerHTML = "";
var ul = d.createElement("ul");
var li = d.createElement("li");
if (HMUD_UI.connState == "disconnected") {
li.appendChild(d.createTextNode(m.connect));
li.onclick = function(){HMUD_Client.connect();};
ul.appendChild(li);
} else {
li.appendChild(d.createTextNode(m.reconnect));
li.onclick = function(){HMUD_Client.disconnect();HMUD_Client.connect();};
ul.appendChild(li);
var li2 = d.createElement("li");
li2.appendChild(d.createTextNode(m.disconnect));
li2.onclick = function(){HMUD_Client.disconnect();};
ul.appendChild(li2);
}
cm.appendChild(ul);
cm.style.display = "block";
HMUD_UI.rearrange();
} else {
cm.style.display = "none";
}
},
options: function () {
var om = document.getElementById("optionsMenu");
if (om.style.display == "none") {
this.updateOptionsMenu();
om.style.display = "block";
HMUD_UI.rearrange();
} else {
om.style.display = "none";
}
},
/* will create menu if it still does not exist */
updateOptionsMenu: function () {
var d = document;
var om = d.getElementById("optionsMenu");
if (om.alreadyCreated) {
return;
}
/* Command guide */
if (HMUD_Guide.length > 0) {
var g_fs = d.createElement("fieldset");
var g_lg = d.createElement("legend");
g_lg.appendChild(d.createTextNode("?"));
g_fs.appendChild(g_lg);
var g_ul = d.createElement("ul");
g_fs.appendChild(g_ul);
var g_li1 = d.createElement("li");
g_li1.onclick = function(){HMUD_Menu.showGuide(true);};
g_li1.appendChild(d.createTextNode(m.cmdGuide));
g_ul.appendChild(g_li1);
om.appendChild(g_fs);
}
/* font fieldset */
var f_fs = d.createElement("fieldset");
var f_lg = d.createElement("legend");
f_lg.appendChild(d.createTextNode(m.selectFont));
f_fs.appendChild(f_lg);
var f_ul = d.createElement("ul");
var f_li1 = d.createElement("li");
f_li1.onclick = function(){HMUD_UI.selectFont('font-fixed', true);};
f_li1.appendChild(d.createTextNode("Fixedsys"));
f_ul.appendChild(f_li1);
var f_li2 = d.createElement("li");
f_li2.onclick = function(){HMUD_UI.selectFont('font-courier', true);};
f_li2.appendChild(d.createTextNode("Courier New"));
f_ul.appendChild(f_li2);
var f_li3 = d.createElement("li");
f_li3.onclick = function(){HMUD_UI.selectFont('font-courier-b', true);};
f_li3.appendChild(d.createTextNode("Courier New Bold"));
f_ul.appendChild(f_li3);
var f_li4 = d.createElement("li");
f_li4.onclick = function(){HMUD_UI.selectFont('font-monospace', true);};
f_li4.appendChild(d.createTextNode("Monospace"));
f_ul.appendChild(f_li4);
var f_li5 = d.createElement("li");
f_li5.onclick = function(){HMUD_UI.selectFont('font-terminal', true);};
f_li5.appendChild(d.createTextNode("Terminal"));
f_ul.appendChild(f_li5);
f_fs.appendChild(f_ul);
/* clear screen fieldset */
var c_fs = d.createElement("fieldset");
var c_lg = d.createElement("legend");
c_lg.appendChild(d.createTextNode(m.clearOutput + " ("));
var c_st = d.createElement("strong");
var nlis = d.getElementById("numLinesInScreen");
nlis.style.display = "inline";
c_st.appendChild(nlis);
c_lg.appendChild(c_st);
c_lg.appendChild(d.createTextNode(" " + m.lines + ")"));
c_fs.appendChild(c_lg);
var c_ul = d.createElement("ul");
var c_li1 = d.createElement("li");
c_li1.onclick = function(){HMUD_UI.clearScreen(1000);};
c_li1.appendChild(d.createTextNode(m.preserve1000));
c_ul.appendChild(c_li1);
var c_li2 = d.createElement("li");
c_li2.onclick = function(){HMUD_UI.clearScreen("half");};
c_li2.appendChild(d.createTextNode(m.half));
c_ul.appendChild(c_li2);
var c_li3 = d.createElement("li");
c_li3.onclick = function(){HMUD_UI.clearScreen("all");};
c_li3.appendChild(d.createTextNode(m.all));
c_ul.appendChild(c_li3);
c_fs.appendChild(c_ul);
om.appendChild(f_fs);
om.appendChild(c_fs);
om.alreadyCreated = true;
},
saveLog: function () {
var ls = document.getElementById("logSave");
var lt = document.getElementById("logSaveTA");
if (ls.style.display == "none") {
var bodyClass = document.body.className.length
? " class=\"" + document.body.className + "\"" : "";
window.disableCmdFocus = true;
lt.value = "hMUD Log"
+ HMUD_UI.output.innerHTML + "
";
ls.style.display = "block";
} else {
window.disableCmdFocus = false;
lt.value = "";
ls.style.display = "none";
}
},
showGuide: function (setCookie) {
if (HMUD_Guide.length < 1)
return;
if (setCookie)
createCookie("showGuide", "yes", 30);
var d = document;
var g = d.getElementById("cmdGuide");
if (g.guideAlreadyCreated) {
g.style.display = "block";
return;
}
/* creating table */
var cap = d.createElement("div");
cap.className = "caption";
cap.appendChild(d.createTextNode(m.cmdGuide));
g.appendChild(cap);
var table = d.createElement("table");
g.appendChild(table);
var tbody = d.createElement("tbody");
table.appendChild(tbody);
for (var i = 0; i < HMUD_Guide.length; ++i) {
var tr1 = d.createElement("tr");
tbody.appendChild(tr1);
var th = d.createElement("th");
tr1.appendChild(th);
/* section */
th.appendChild(d.createTextNode(HMUD_Guide[i][0]));
/* commands in this section */
var commands = HMUD_Guide[i][1];
var tr2 = d.createElement("tr");
tbody.appendChild(tr2);
var td = d.createElement("td");
tr2.appendChild(td);
for (var j = 0; j < commands.length; ++j) {
var sp1 = d.createElement("span");
sp1.appendChild(d.createTextNode(commands[j][0]));
sp1.id = "cmd-name-" + i + "-" + j;
sp1.className = "command-name";
sp1.onmouseover = function() {
var e = document.getElementById(this.id.replace("cmd-name", "cmd-desc"));
e.style.display = "block";
var p = findPos(this, g);
var top = p[1] + this.offsetHeight;
e.style.top = (p[1] + this.offsetHeight) + "px";
if ((findPos(e)[1] + e.offsetHeight) > (findPos(HMUD_UI.output)[1] + HMUD_UI.output.offsetHeight))
e.style.top = (p[1] - e.offsetHeight) + "px";
};
sp1.onmouseout = function() {
var e = document.getElementById(this.id.replace("cmd-name", "cmd-desc"));
e.style.display = "none";
};
sp1.onclick = function() { HMUD_UI.cmdline.value += this.firstChild.nodeValue + " "; };
td.appendChild(sp1);
td.appendChild(d.createTextNode(" "));
var sp2 = d.createElement("span");
sp2.appendChild(d.createTextNode(commands[j][1]));
sp2.id = "cmd-desc-" + i + "-" + j;
sp2.style.display = "none";
sp2.className = "command-description";
td.appendChild(sp2);
td.appendChild(d.createTextNode(" "));
}
}
g.guideAlreadyCreated = true;
g.style.display = "block";
HMUD_UI.rearrange();
},
hideGuide: function(setCookie) {
document.getElementById("cmdGuide").style.display = "none";
if (setCookie)
createCookie("showGuide", "no", 30);
}
};
function getViewportDimensions() {
var intH = 0, intW = 0;
if(self.innerHeight) {
intH = window.innerHeight;
intW = window.innerWidth;
}
else {
if(document.documentElement && document.documentElement.clientHeight) {
intH = document.documentElement.clientHeight;
intW = document.documentElement.clientWidth;
}
else {
if(document.body) {
intH = document.body.clientHeight;
intW = document.body.clientWidth;
}
}
}
return {
height: parseInt(intH, 10),
width: parseInt(intW, 10)
};
}
function findPos(obj, stopAt)
{
var curleft = 0;
var curtop = 0;
if (obj.offsetParent)
do
{
if (obj == stopAt)
break;
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
}
while (obj = obj.offsetParent);
return [curleft,curtop];
}