/* dcwebui.js */
//;(function() {
"use strict";
var SENTINEL_PASSWORD = "************";
var CHAT_SCROLLBACK_LIMIT = 50; // Once over 2x $limit, the first $limit will be trimmed off the list
var $ = (document.querySelectorAll ?
function(s) {
var r = document.querySelectorAll(s);
return (s[0] === '#' && r.length === 1) ? r[0] : r;
} :
function(s) {
// i'm not writing a selector engine...
if (! s.length) return [];
if (s[0] === '#') {
return document.getElementById(s.slice(1));
} else if (s[0] === '.') {
return document.getElementsByClassName(s.slice(1));
} else {
return document.getElementsByTagName(s);
}
}
);
var nmdc_escape = function(str) {
return (
(''+str).length
? (''+str).replace(/&/g,'&').replace(/\|/g,'|').replace(/\$/g,'$')
: ' '
);
};
var hesc = function(s) {
var filter = {
'&': '&', '<': '<', '>': '>', '"': '"', '\'': '''
};
return s.toString().replace(/[&<>'"]/g, function(s) { return filter[s]; });
};
var fmtBytes = function(b) {
if (b == 0) {
return '(nothing)';
}
var k = 1024;
var sizes = [' B', ' KiB', ' MiB', ' GiB', ' TiB'];
var i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(3)) + sizes[i];
};
var urldesc = function(s) {
return decodeURIComponent(s.replace(/\+/g, " "));
}
var linkify = function(str) {
// n.b. str is already hesced
return (str
.replace(
/(https?:\/\/[^\s<]+)/g,
"$1"
)
.replace(
/magnet:\?.+dn=([^\< ]+)/g,
function(match, m1) { return "[MAGNET] " + urldesc(m1) + ""; }
)
);
};
var sanitise = function(s) {
return linkify(hesc(s));
};
var toggle = function($el) {
$el.style.display = ($el.style.display === "block") ? "none" : "block";
};
var textContent = function($el) {
if ($el.textContent) return $el.textContent;
if ($el.innerText) return $el.innerText;
return "";
};
var negmod = function(l, r) {
var ret = l % r;
if (l < 0) {
return ret + r;
} else {
return ret;
}
};
// @ref https://developer.mozilla.org/en/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
var b64 = function(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
})).replace(/=/g, '');
}
// https://gist.github.com/eligrey/1276030
var appendInnerHTML = function($el, html) {
var child = document.createElement("span");
child.innerHTML = html;
var node;
while ((node = child.firstChild)) {
$el.appendChild(node);
}
};
// http://stackoverflow.com/a/5598797
function getOffsetLeft( elem ) {
var offsetLeft = 0;
do {
if (!isNaN(elem.offsetLeft)) {
offsetLeft += elem.offsetLeft;
}
} while (elem = elem.offsetParent);
return offsetLeft;
}
function getOffsetTop( elem ) {
var offsetTop = 0;
do {
if (!isNaN(elem.offsetTop)) {
offsetTop += elem.offsetTop;
}
} while (elem = elem.offsetParent);
return offsetTop;
}
/* */
var date_format = function(d, format) {
var pad = function(s) {
return (s < 10) ? '0'+s : ''+s ;
};
var ret = format;
ret = ret.replace(/H/g, pad(d.getHours()));
ret = ret.replace(/i/g, pad(d.getMinutes()));
ret = ret.replace(/s/g, pad(d.getSeconds()));
ret = ret.replace(/Y/g, d.getFullYear());
ret = ret.replace(/m/g, pad(d.getMonth() + 1));
ret = ret.replace(/d/g, pad(d.getDate()));
return ret;
};
/* */
var notify = function(title, body) {
if (!("Notification" in window)) {
return; // not supported by browser
}
if (window.Notification.permission === "granted") {
var nn = new Notification(title, {
body: body,
icon: DCWEBUI_CONF.extern + "/favicon.ico"
});
} else if (window.Notification.permission !== "denied") {
Notification.requestPermission(function(permission) {
notify(title, body);
});
}
};
/* Tab writers */
var write = function(tab) {
var $tab = $('#inner-'+tab);
return {
'cls': function() {
$tab.innerHTML = '';
return this;
},
'scroll': function() {
$tab.scrollTop = $tab.scrollHeight;
return this;
},
'raw': function(s) {
appendInnerHTML($tab, s);
return this.scroll();
},
'c': function(c, s) {
return this.raw(''+s+'');
},
'time': function() {
var d = new Date();
return this.raw('['+ date_format(new Date(), timestamp_formats[timestamp_format_index])+"] ");
},
'system': function(s) {
return this.time().c('tx-sys', sanitise(s)).raw('
');
},
'pubnick': function(u) {
return this.raw('<'+hesc(u)+'>');
},
'pub': function(u, s) {
return this.time().
pubnick(u).raw(' ').
c('tx-chat', sanitise(s)).raw('
');
}
};
};
var write_system_message_in_all_pm_tabs = function(system_message) {
for (var k in pm_tabs) {
writerFor(k).system(system_message);
}
};
/* Userlist */
var switchToPM = function(u) {
writerFor(u); // create
tab_set(pm_tabs[u]); // switch
writerFor(u).scroll(); // scroll
};
var userMenu = function(u, ev) {
usermenu.hide();
usermenu = new MenuList(ev.target);
usermenu.add("Send private message...", function() {
switchToPM(u);
});
// Usercommands
for (var i = 0; i < user_usercommands.length; i++) (function(i) {
var raw = user_usercommands[i].raw;
usermenu.add(user_usercommands[i].title, function() {
var message = usercommand_process( raw .replace(/%\[nick\]/g, u) );
sock.emit('raw', {message: message});
});
})(i);
// Show
usermenu.show();
//
ev.preventDefault();
return false;
};
var userlist = {
'add': function(u) {
if (this.has(u)) return;
var userlists = $(".userlist");
for (var l = 0, e = userlists.length; l !== e; ++l) {
var userlist = userlists[l];
var to_add = document.createElement('li');
to_add.className = "user-" + b64(u);
to_add.innerHTML = hesc(u);
to_add.onclick = function() { switchToPM(u); };
to_add.oncontextmenu = function(ev) { return userMenu(u, ev); };
var users = userlist.children;
var cmp = hesc(u).toUpperCase();
var found = false;
for (var i = 0; i < users.length; i++) {
if ((''+users[i].innerHTML).toUpperCase() > cmp) {
userlist.insertBefore(to_add, users[i]);
found = true;
break;
}
}
if (! found) {
userlist.appendChild(to_add);
}
}
return this;
},
'del': function(u) {
var userlists = $(".userlist");
for (var l = 0, e = userlists.length; l !== e; ++l) {
if (! userlists[l].children) continue;
var userlist = userlists[l];
var users = userlist.children;
var cmp = hesc(u).toUpperCase();
for (var i = 0; i < users.length; i++) {
if ((''+users[i].innerHTML).toUpperCase() === cmp) {
userlist.removeChild(users[i]);
break;
}
}
}
return this;
},
'clear': function() {
var userlists = $(".userlist");
for (var i in userlists) {
if (! userlists[i].children) continue;
var userlist = userlists[i];
var users = userlist.children;
for (var j = users.length; j --> 0;) {
userlist.removeChild(users[j]);
}
}
return this;
},
'names': function() {
var userlist = $(".userlist")[0].children;
var ret = [];
for (var i = 0, e = userlist.length; i < e; ++i) {
ret.push( textContent(userlist[i]) );
}
return ret;
},
'has': function(u) {
return $(".user-" + b64(u)).length !== 0; /* there are two - large and non-large */
},
'count': function() {
return $(".userlist")[0].children.length;
},
'setInfo': function(nick, props) {
var baseClass = "user-" + b64(nick);
var $el = $("." + baseClass);
var prop_str = [];
if (props.Description.length > 0) {
prop_str.push(props.Description);
}
if (props.Email.length > 0) {
prop_str.push(props.Email);
}
if (props.ClientTag.length > 0) {
prop_str.push(props.ClientTag + " " + props.ClientVersion);
}
prop_str.push("Sharing " + fmtBytes(props.ShareSize));
for (var i = 0; i < $el.length; ++i) {
$el[i].title = prop_str.join("\n");
if (props.IsOperator) {
$el[i].className = baseClass + " user-is-operator";
} else {
$el[i].className = baseClass; // remove op flag
}
}
}
};
var submit = function() {
var str = $("#chatbox").value;
if (! str.length) return;
if (hub_state === STATE_READY_FOR_LOGIN) {
transition(1); // disables #chatbox
hub_last_nick = str.split(":", 2)[0];
var hub_pass = "";
if (str.length > hub_last_nick.length) {
hub_pass = str.substr(hub_last_nick.length + 1);
}
if (hub_pass === SENTINEL_PASSWORD) {
// Probably not a real password. Attempt to load a better one from the saved state
var cache = persistence_get("login");
if (cache.indexOf(":") != -1) {
hub_pass = cache.substr(cache.indexOf(":") + 1);
}
}
persistence_set("login", hub_pass.length > 0 ? hub_last_nick+":"+hub_pass : hub_last_nick);
sock.emit('hello', {'nick' : hub_last_nick, 'pass' : hub_pass});
write("tab-main").system("Connecting...");
} else if (hub_state === STATE_ACTIVE) {
if (pm_target !== false) {
sock.emit('priv', {'user': pm_target, 'message': str});
writerFor(pm_target).pub(hub_last_nick, str );
} else {
sock.emit('pub', {'message' : str});
}
chat_scrollback.push( str );
chat_scrollback_index = -1;
if (chat_scrollback.length > (2*CHAT_SCROLLBACK_LIMIT)) {
chat_scrollback = chat_scrollback.slice(CHAT_SCROLLBACK_LIMIT);
}
} else {
write("tab-main").system("Invalid internal state.");
}
$("#chatbox").value = '';
};
/* page visibility */
var pagevis_currently_visible = true;
var pagevis_setup = function(fnActive, fnInactive) {
var h, visibilityChange;
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
h = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document.msHidden !== "undefined") {
h = "msHidden";
visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
h = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
// Warn if the browser doesn't support addEventListener or the Page Visibility API
if (typeof document[h] === "undefined") {
// Browser doesn't support Page Visibility API
// Behave as if the page is always visible.
pagevis_currently_visible = true
fnActive();
} else {
document.addEventListener(visibilityChange, function() {
if (document[h]) {
fnInactive();
} else {
fnActive();
}
});
}
}
/* tabs */
/**
* Switch active tab
*
* @param {String} tab Full tab ID (e.g. tab-main, tab-users, tab-ext-???)
*/
var tab_set = function(tab) {
var tabs = $(".tabpane");
for (var i in tabs) {
try {
tabs[i].style.display = (tabs[i].id === tab ? 'block' : 'none');
} catch (e) {};
}
var tabitems = $(".tabitem");
for (var i in tabitems) {
try {
// Update UNREAD/SELECTED flags for the target
var was_unread = (tabitems[i].className.indexOf("unread") !== -1);
var is_target = (tabitems[i].getAttribute('data-tab') === tab);
var is_still_unread = (was_unread && !is_target);
tabitems[i].className = "tabitem" + (is_target ? ' selected' : '') + (is_still_unread ? ' unread' : '');
} catch (e) {};
}
pm_target = false;
for (var i in pm_tabs) {
if (pm_tabs[i] === tab) {
pm_target = i;
break;
}
}
updateTitle();
write(tab).scroll();
$("#chatbox").focus();
last_tab = tab;
};
var tab_new = function(id, name) {
appendInnerHTML($("#bar"),
'