").text(entry.bannedby).appendTo(tr);
tr.attr("title", "Ban Reason: " + entry.reason);
return tr;
};
flat.forEach(function (person) {
var bans = person.bans;
var name = person.name;
var first = addBanRow(bans.shift());
if (bans.length > 0) {
var showmore = $("").addClass("btn btn-xs btn-default pull-right");
$("").addClass("glyphicon glyphicon-list").appendTo(showmore);
showmore.appendTo(first.find("td")[1]);
showmore.click(function () {
if (showmore.data("elems")) {
showmore.data("elems").forEach(function (e) {
e.remove();
});
showmore.data("elems", null);
} else {
var elems = [];
bans.forEach(function (b) {
elems.push(addBanRow(b, first));
});
showmore.data("elems", elems);
}
});
}
});
}
function checkEntitiesInStr(str) {
var entities = {
"&": "&",
"<": "<",
">": ">",
'"': """,
"'": "'",
"\\(": "(",
"\\)": ")"
};
var m = str.match(/([&<>"'])|(\\\()|(\\\))/);
if (m && m[1] in entities) {
return { src: m[1].replace(/^\\/, ""), replace: entities[m[1]] };
} else {
return false;
}
}
function formatCSChatFilterList() {
var tbl = $("#cs-chatfilters table");
tbl.find("tbody").remove();
tbl.find(".ui-sortable").remove();
var entries = tbl.data("entries") || [];
entries.forEach(function (f) {
var tr = $("
").appendTo(tbl);
var controlgroup = $("").addClass("btn-group")
.appendTo($("
").appendTo(tr));
var control = $("").addClass("btn btn-xs btn-default")
.attr("title", "Edit this filter")
.appendTo(controlgroup);
$("").addClass("glyphicon glyphicon-list").appendTo(control);
var del = $("").addClass("btn btn-xs btn-danger")
.appendTo(controlgroup);
$("").addClass("glyphicon glyphicon-trash").appendTo(del);
del.click(function () {
socket.emit("removeFilter", f);
});
var name = $("").text(f.name).appendTo($("
").appendTo(tr));
var activetd = $("
").appendTo(tr);
var active = $("").attr("type", "checkbox")
.prop("checked", f.active)
.appendTo(activetd)
.change(function () {
f.active = $(this).prop("checked");
socket.emit("updateFilter", f);
});
var reset = function () {
control.data("editor") && control.data("editor").remove();
control.data("editor", null);
control.parent().find(".btn-success").remove();
var tbody = $(tbl.children()[1]);
if (tbody.find(".filter-edit-row").length === 0) {
tbody.sortable("enable");
}
};
control.click(function () {
if (control.data("editor")) {
return reset();
}
$(tbl.children()[1]).sortable("disable");
var tr2 = $("
").insertAfter(tr).addClass("filter-edit-row");
var wrap = $("
").attr("colspan", "3").appendTo(tr2);
var form = $("").addClass("form-inline").attr("role", "form")
.attr("action", "javascript:void(0)")
.appendTo(wrap);
var addTextbox = function (placeholder) {
var div = $("").addClass("form-group").appendTo(form)
.css("margin-right", "10px");
var input = $("").addClass("form-control")
.attr("type", "text")
.attr("placeholder", placeholder)
.attr("title", placeholder)
.appendTo(div);
return input;
};
var regex = addTextbox("Filter regex").val(f.source);
var flags = addTextbox("Regex flags").val(f.flags);
var replace = addTextbox("Replacement text").val(f.replace);
var checkwrap = $("").addClass("checkbox").appendTo(form);
var checklbl = $("").text("Filter Links").appendTo(checkwrap);
var filterlinks = $("").attr("type", "checkbox")
.prependTo(checklbl)
.prop("checked", f.filterlinks);
var save = $("").addClass("btn btn-xs btn-success")
.attr("title", "Save changes")
.insertAfter(control);
$("").addClass("glyphicon glyphicon-floppy-save").appendTo(save);
save.click(function () {
f.source = regex.val();
var entcheck = checkEntitiesInStr(f.source);
if (entcheck) {
alert("Warning: " + entcheck.src + " will be replaced by " +
entcheck.replace + " in the message preprocessor. This " +
"regular expression may not match what you intended it to " +
"match.");
}
f.flags = flags.val();
f.replace = replace.val();
f.filterlinks = filterlinks.prop("checked");
socket.emit("updateFilter", f);
socket.once("updateFilterSuccess", function () {
reset();
});
});
control.data("editor", tr2);
});
});
$(tbl.children()[1]).sortable({
start: function(ev, ui) {
FILTER_FROM = ui.item.prevAll().length;
},
update: function(ev, ui) {
FILTER_TO = ui.item.prevAll().length;
if(FILTER_TO != FILTER_FROM) {
socket.emit("moveFilter", {
from: FILTER_FROM,
to: FILTER_TO
});
}
}
});
}
function formatTime(sec) {
var h = Math.floor(sec / 3600) + "";
var m = Math.floor((sec % 3600) / 60) + "";
var s = sec % 60 + "";
if (h.length < 2) {
h = "0" + h;
}
if (m.length < 2) {
m = "0" + m;
}
if (s.length < 2) {
s = "0" + s;
}
if (h === "00") {
return [m, s].join(":");
} else {
return [h, m, s].join(":");
}
}
function formatUserPlaylistList() {
var list = $("#userpl_list").data("entries") || [];
list.sort(function (a, b) {
var x = a.name.toLowerCase();
var y = b.name.toLowerCase();
return x == y ? 0 : (x < y ? -1 : 1);
});
$("#userpl_list").html("");
list.forEach(function (pl) {
var li = $("").addClass("queue_entry").appendTo($("#userpl_list"));
var title = $("").addClass("qe_title").appendTo(li)
.text(pl.name);
var time = $("").addClass("pull-right").appendTo(li)
.text(pl.count + " items, playtime " + formatTime(pl.duration));
var clear = $("").addClass("qe_clear").appendTo(li);
var btns = $("").addClass("btn-group pull-left").prependTo(li);
if (hasPermission("playlistadd")) {
$("").addClass("btn btn-xs btn-default")
.text("End")
.appendTo(btns)
.click(function () {
socket.emit("queuePlaylist", {
name: pl.name,
pos: "end",
temp: $(".add-temp").prop("checked")
});
});
}
if (hasPermission("playlistadd") && hasPermission("playlistnext")) {
$("").addClass("btn btn-xs btn-default")
.text("Next")
.prependTo(btns)
.click(function () {
socket.emit("queuePlaylist", {
name: pl.name,
pos: "next",
temp: $(".add-temp").prop("checked")
});
});
}
$("").addClass("btn btn-xs btn-danger")
.html("")
.attr("title", "Delete playlist")
.appendTo(btns)
.click(function () {
var really = confirm("Are you sure you want to delete" +
" this playlist? This cannot be undone.");
if (!really) {
return;
}
socket.emit("deletePlaylist", {
name: pl.name
});
});
});
}
function loadEmotes(data) {
function sanitizeText(str) {
str = str.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """);
return str;
}
CHANNEL.emotes = [];
CHANNEL.emoteMap = {};
CHANNEL.badEmotes = [];
data.forEach(function (e) {
if (e.image && e.name) {
e.regex = new RegExp(e.source, "gi");
CHANNEL.emotes.push(e);
if (/\s/g.test(e.name)) {
// Emotes with spaces can't be hashmapped
CHANNEL.badEmotes.push(e);
} else {
CHANNEL.emoteMap[sanitizeText(e.name)] = e;
}
} else {
console.error("Rejecting invalid emote: " + JSON.stringify(e));
}
});
}
function execEmotes(msg) {
if (USEROPTS.no_emotes) {
return msg;
}
if (CyTube.featureFlag && CyTube.featureFlag.efficientEmotes) {
return execEmotesEfficient(msg);
}
CHANNEL.emotes.forEach(function (e) {
msg = msg.replace(e.regex, '$1');
});
return msg;
}
function execEmotesEfficient(msg) {
CHANNEL.badEmotes.forEach(function (e) {
msg = msg.replace(e.regex, '$1');
});
msg = msg.replace(/[^\s]+/g, function (m) {
if (CHANNEL.emoteMap.hasOwnProperty(m)) {
var e = CHANNEL.emoteMap[m];
return '';
} else {
return m;
}
});
return msg;
}
function initPm(user) {
if ($("#pm-" + user).length > 0) {
return $("#pm-" + user);
}
var pm = $("").addClass("panel panel-default pm-panel")
.appendTo($("#pmbar"))
.data("last", { name: "" })
.attr("id", "pm-" + user);
var title = $("").addClass("panel-heading").text(user).appendTo(pm);
var close = $("").addClass("close pull-right")
.html("×")
.appendTo(title).click(function () {
pm.remove();
$("#pm-placeholder-" + user).remove();
});
var body = $("").addClass("panel-body").appendTo(pm).hide();
var placeholder;
title.click(function () {
body.toggle();
pm.removeClass("panel-primary").addClass("panel-default");
if (!body.is(":hidden")) {
placeholder = $("").addClass("pm-panel-placeholder")
.attr("id", "pm-placeholder-" + user)
.insertAfter(pm);
var left = pm.position().left;
pm.css("position", "absolute")
.css("bottom", "0px")
.css("left", left);
} else {
pm.css("position", "");
$("#pm-placeholder-" + user).remove();
}
});
var buffer = $("").addClass("pm-buffer linewrap").appendTo(body);
$("").appendTo(body);
var input = $("").addClass("form-control pm-input").attr("type", "text")
.attr("maxlength", 320)
.appendTo(body);
input.keydown(function (ev) {
if (ev.keyCode === 13) {
if (CHATTHROTTLE) {
return;
}
var meta = {};
var msg = input.val();
if (msg.trim() === "") {
return;
}
if (USEROPTS.modhat && CLIENT.rank >= Rank.Moderator) {
meta.modflair = CLIENT.rank;
}
if (CLIENT.rank >= 2 && msg.indexOf("/m ") === 0) {
meta.modflair = CLIENT.rank;
msg = msg.substring(3);
}
socket.emit("pm", {
to: user,
msg: msg,
meta: meta
});
input.val("");
} else if(ev.keyCode == 9) { // Tab completion
try {
chatTabComplete(ev.target);
} catch (error) {
console.error(error);
}
ev.preventDefault();
return false;
}
});
return pm;
}
function checkScriptAccess(viewSource, type, cb) {
var pref = JSPREF[CHANNEL.name.toLowerCase() + "_" + type];
if (pref === "ALLOW") {
return cb("ALLOW");
} else if (pref !== "DENY") {
var div = $("#chanjs-allow-prompt");
if (div.length > 0) {
setTimeout(function () {
checkScriptAccess(viewSource, type, cb);
}, 500);
return;
}
div = $("").attr("id", "chanjs-allow-prompt");
var close = $("").addClass("close pull-right")
.html("×")
.appendTo(div);
var form = $("")
.attr("action", "javascript:void(0)")
.attr("id", "chanjs-allow-prompt")
.attr("style", "text-align: center")
.appendTo(div);
if (type === "embedded") {
form.append("This channel has special features that require your permission to run. ");
} else {
form.append("This channel has special features that require your permission to run. This script is hosted on a third-party website and is not endorsed by the owners of the website hosting this channel. ");
}
$(viewSource).appendTo(form);
form.append("
" +
"" +
"" +
"
");
form.append("");
var dialog = chatDialog(div);
close.click(function () {
dialog.remove();
/* Implicit denial of script access */
cb("DENY");
});
$("#chanjs-allow").click(function () {
var save = $("#chanjs-save-pref").is(":checked");
dialog.remove();
if (save) {
JSPREF[CHANNEL.name.toLowerCase() + "_" + type] = "ALLOW";
setOpt("channel_js_pref", JSPREF);
}
cb("ALLOW");
});
$("#chanjs-deny").click(function () {
var save = $("#chanjs-save-pref").is(":checked");
dialog.remove();
if (save) {
JSPREF[CHANNEL.name.toLowerCase() + "_" + type] = "DENY";
setOpt("channel_js_pref", JSPREF);
}
cb("DENY");
});
}
}
function formatScriptAccessPrefs() {
var tbl = $("#us-scriptcontrol table");
tbl.find("tbody").remove();
var channels = Object.keys(JSPREF).sort();
channels.forEach(function (channel) {
var idx = String(channel).lastIndexOf("_");
if (idx < 0) {
// Invalid
console.error("Channel JS pref: invalid key '" + channel + "', deleting it");
delete JSPREF[channel];
setOpt("channel_js_pref", JSPREF);
return;
}
var channelName = channel.substring(0, idx);
var prefType = channel.substring(idx + 1);
console.log(channelName, prefType);
if (prefType !== "external" && prefType !== "embedded") {
// Invalid
console.error("Channel JS pref: invalid key '" + channel + "', deleting it");
delete JSPREF[channel];
setOpt("channel_js_pref", JSPREF);
return;
}
var pref = JSPREF[channel];
var tr = $("
").appendTo(tbl);
$("
").text(channelName).appendTo(tr);
$("
").text(prefType).appendTo(tr);
var pref_td = $("
").appendTo(tr);
var allow_label = $("").addClass("radio-inline")
.text("Allow").appendTo(pref_td);
var allow = $("").attr("type", "radio")
.prop("checked", pref === "ALLOW").
prependTo(allow_label);
allow.change(function () {
if (allow.is(":checked")) {
JSPREF[channel] = "ALLOW";
setOpt("channel_js_pref", JSPREF);
deny.prop("checked", false);
}
});
var deny_label = $("").addClass("radio-inline")
.text("Deny").appendTo(pref_td);
var deny = $("").attr("type", "radio")
.prop("checked", pref === "DENY").
prependTo(deny_label);
deny.change(function () {
if (deny.is(":checked")) {
JSPREF[channel] = "DENY";
setOpt("channel_js_pref", JSPREF);
allow.prop("checked", false);
}
});
var clearpref = $("").addClass("btn btn-sm btn-danger")
.text("Clear Preference")
.appendTo($("
").appendTo(tr))
.click(function () {
delete JSPREF[channel];
setOpt("channel_js_pref", JSPREF);
tr.remove();
});
});
}
function EmoteList(selector, emoteClickCallback) {
this.elem = $(selector);
this.initSearch();
this.initSortOption();
this.table = this.elem.find(".emotelist-table")[0];
this.paginatorContainer = this.elem.find(".emotelist-paginator-container");
this.cols = 5;
this.itemsPerPage = 25;
this.emotes = [];
this.page = 0;
this.emoteClickCallback = emoteClickCallback || function(){};
}
EmoteList.prototype.initSearch = function () {
this.searchbar = this.elem.find(".emotelist-search");
var self = this;
this.searchbar.keyup(function () {
var value = this.value.toLowerCase();
if (value) {
self.filter = function (emote) {
return emote.name.toLowerCase().indexOf(value) >= 0;
};
} else {
self.filter = null;
}
self.handleChange();
self.loadPage(0);
});
};
EmoteList.prototype.initSortOption = function () {
this.sortOption = this.elem.find(".emotelist-alphabetical");
this.sortAlphabetical = false;
var self = this;
this.sortOption.change(function () {
self.sortAlphabetical = this.checked;
self.handleChange();
self.loadPage(0);
});
};
EmoteList.prototype.handleChange = function () {
this.emotes = CHANNEL.emotes.slice();
if (this.sortAlphabetical) {
this.emotes.sort(function (a, b) {
var x = a.name.toLowerCase();
var y = b.name.toLowerCase();
if (x < y) {
return -1;
} else if (x > y) {
return 1;
} else {
return 0;
}
});
}
if (this.filter) {
this.emotes = this.emotes.filter(this.filter);
}
this.paginator = new NewPaginator(this.emotes.length, this.itemsPerPage,
this.loadPage.bind(this));
this.paginatorContainer.html("");
this.paginatorContainer.append(this.paginator.elem);
this.paginator.loadPage(this.page);
};
EmoteList.prototype.loadPage = function (page) {
var tbody = this.table.children[0];
tbody.innerHTML = "";
var row;
var start = page * this.itemsPerPage;
if (start >= this.emotes.length) return;
var end = Math.min(start + this.itemsPerPage, this.emotes.length);
var _this = this;
for (var i = start; i < end; i++) {
if ((i - start) % this.cols === 0) {
row = document.createElement("tr");
tbody.appendChild(row);
}
(function (emote) {
var td = document.createElement("td");
td.className = "emote-preview-container";
// Trick element to vertically align the emote within the container
var hax = document.createElement("span");
hax.className = "emote-preview-hax";
td.appendChild(hax);
var img = document.createElement("img");
img.src = emote.image;
img.className = "emote-preview";
img.title = emote.name;
img.onclick = _this.emoteClickCallback.bind(null, emote);
td.appendChild(img);
row.appendChild(td);
})(this.emotes[i]);
}
this.page = page;
};
function onEmoteClicked(emote) {
var val = chatline.value;
if (!val) {
chatline.value = emote.name;
} else {
if (!val.charAt(val.length - 1).match(/\s/)) {
chatline.value += " ";
}
chatline.value += emote.name;
}
window.EMOTELISTMODAL.modal("hide");
chatline.focus();
}
window.EMOTELIST = new EmoteList("#emotelist", onEmoteClicked);
window.EMOTELIST.sortAlphabetical = USEROPTS.emotelist_sort;
function CSEmoteList(selector) {
EmoteList.call(this, selector);
}
CSEmoteList.prototype = Object.create(EmoteList.prototype);
CSEmoteList.prototype.loadPage = function (page) {
var tbody = this.table.children[1];
tbody.innerHTML = "";
var start = page * this.itemsPerPage;
if (start >= this.emotes.length) {
return;
}
var end = Math.min(start + this.itemsPerPage, this.emotes.length);
var self = this;
this.page = page;
for (var i = start; i < end; i++) {
var row = document.createElement("tr");
tbody.appendChild(row);
(function (emote, row) {
// Add delete button
var tdDelete = document.createElement("td");
var btnDelete = document.createElement("button");
btnDelete.className = "btn btn-xs btn-danger";
var pennJillette = document.createElement("span");
pennJillette.className = "glyphicon glyphicon-trash";
btnDelete.appendChild(pennJillette);
tdDelete.appendChild(btnDelete);
row.appendChild(tdDelete);
btnDelete.onclick = function deleteEmote() {
document.getElementById("cs-emotes-newname").value = emote.name;
document.getElementById("cs-emotes-newimage").value = emote.image;
socket.emit("removeEmote", emote);
};
// Add emote name
var tdName = document.createElement("td");
var nameDisplay = document.createElement("code");
nameDisplay.textContent = emote.name;
tdName.appendChild(nameDisplay);
row.appendChild(tdName);
var $nameDisplay = $(nameDisplay);
$nameDisplay.click(function (clickEvent) {
$nameDisplay.detach();
var editInput = document.createElement("input");
editInput.className = "form-control";
editInput.type = "text";
editInput.value = emote.name;
tdName.appendChild(editInput);
editInput.focus();
function save() {
var val = editInput.value;
tdName.removeChild(editInput);
tdName.appendChild(nameDisplay);
// Nothing was changed
if(val === emote.name){ return }
// Emote name already exists
if( CHANNEL.emotes.filter(function(emote){ return emote.name === val }).length ){
/*
* Since we are already in a modal
* and Bootstrap doesn't have supermodals
* we will make a self destructing warning
* as a row in the table
*/
var wrow = document.createElement("tr");
var tdBlankDel = document.createElement("td"); wrow.appendChild(tdBlankDel);
var tdWarnMess = document.createElement("td"); wrow.appendChild(tdWarnMess);
var warnSpan = document.createElement("p"); tdWarnMess.appendChild(warnSpan);
warnSpan.className = "text-warning";
warnSpan.textContent = "An emote of that name already exists.";
tdWarnMess.colSpan = "2";
row.insertAdjacentElement("beforebegin", wrow)
$(wrow).delay(2500).fadeOut('slow', function(){ $(this).remove() });
return;
}
socket.emit("renameEmote", {
old: emote.name,
image: emote.image,
name: val
});
}
editInput.onblur = save;
editInput.onkeyup = function (event) {
if (event.keyCode === 13) {
save();
}
};
});
// Add emote image
var tdImage = document.createElement("td");
var urlDisplay = document.createElement("code");
urlDisplay.textContent = emote.image;
tdImage.appendChild(urlDisplay);
row.appendChild(tdImage);
// Add popover to display the image
var $urlDisplay = $(urlDisplay);
$urlDisplay.popover({
html: true,
trigger: "hover",
content: ''
});
// Change the image for an emote
$urlDisplay.click(function (clickEvent) {
$(tdImage).find(".popover").remove();
$urlDisplay.detach();
var editInput = document.createElement("input");
editInput.className = "form-control";
editInput.type = "text";
editInput.value = emote.image;
tdImage.appendChild(editInput);
editInput.focus();
function save() {
var val = editInput.value;
tdImage.removeChild(editInput);
tdImage.appendChild(urlDisplay);
socket.emit("updateEmote", {
name: emote.name,
image: val
});
}
editInput.onblur = save;
editInput.onkeyup = function (event) {
if (event.keyCode === 13) {
save();
}
};
});
})(this.emotes[i], row);
}
};
window.CSEMOTELIST = new CSEmoteList("#cs-emotes");
window.CSEMOTELIST.sortAlphabetical = USEROPTS.emotelist_sort;
function showChannelSettings() {
$("#channeloptions").modal();
}
// There is a point where this file needed to stop and we have clearly passed
// it but let's keep going and see what happens
function startQueueSpinner(data) {
if ($("#queueprogress").length > 0) {
return;
}
var id = data.id;
if (data.type === "yp") {
id = "$any";
}
var progress = $("").addClass("progress").attr("id", "queueprogress")
.data("queue-id", id);
var progressBar = $("").addClass("progress-bar progress-bar-striped active")
.attr({
role: "progressbar",
"aria-valuenow": "100",
"aria-valuemin": "0",
"aria-valuemax": "100",
}).css({
width: "100%"
}).appendTo(progress);
progress.appendTo($("#addfromurl"));
}
function stopQueueSpinner(data) {
// TODO: this is a temp hack, need to replace media ID check with
// a passthrough request ID (since media ID from API is not necessarily
// the same as the URL "ID" from the user)
if (data && data.type === "us") {
data = { id: data.title.match(/Ustream.tv - (.*)/)[1] };
} else if (data && data.type === "mx") {
data = { id: data.meta.mixer.channelToken };
}
var shouldRemove = (data !== null &&
typeof data === 'object' &&
$("#queueprogress").data("queue-id") === data.id);
shouldRemove = shouldRemove || data === null;
shouldRemove = shouldRemove || $("#queueprogress").data("queue-id") === "$any";
if (shouldRemove) {
$("#queueprogress").remove();
}
}
function maybePromptToUpgradeUserscript() {
if (document.getElementById('prompt-upgrade-drive-userscript')) {
return;
}
if (!window.hasDriveUserscript) {
return;
}
var currentVersion = GS_VERSION.toString(); // data.js
var userscriptVersion = window.driveUserscriptVersion;
if (!userscriptVersion) {
userscriptVersion = '1.0';
}
currentVersion = currentVersion.split('.').map(function (part) {
return parseInt(part, 10);
});
userscriptVersion = userscriptVersion.split('.').map(function (part) {
return parseInt(part, 10);
});
var older = false;
for (var i = 0; i < currentVersion.length; i++) {
if (userscriptVersion[i] < currentVersion[i]) {
older = true;
}
}
if (!older) {
return;
}
var alertBox = document.createElement('div');
alertBox.id = 'prompt-upgrade-drive-userscript';
alertBox.className = 'alert alert-info'
alertBox.innerHTML = 'A newer version of the Google Drive userscript is available.';
alertBox.appendChild(document.createElement('br'));
var infoLink = document.createElement('a');
infoLink.className = 'btn btn-info';
infoLink.href = '/google_drive_userscript';
infoLink.textContent = 'Click here for installation instructions';
infoLink.target = '_blank';
alertBox.appendChild(infoLink);
var closeButton = document.createElement('button');
closeButton.className = 'close pull-right';
closeButton.innerHTML = '×';
closeButton.onclick = function () {
alertBox.parentNode.removeChild(alertBox);
}
alertBox.insertBefore(closeButton, alertBox.firstChild)
document.getElementById('videowrap').appendChild(alertBox);
}
function backoffRetry(fn, cb, options) {
var jitter = options.jitter || 0;
var factor = options.factor || 1;
var isRetryable = options.isRetryable || function () { return true; };
var tries = 0;
function callback(error, result) {
tries++;
factor *= factor;
if (error) {
if (tries >= options.maxTries) {
console.log('Max tries exceeded');
cb(error, result);
} else if (isRetryable(error)) {
var offset = Math.random() * jitter;
var delay = options.delay * factor + offset;
console.log('Retrying on error: ' + error);
console.log('Waiting ' + delay + ' ms before retrying');
setTimeout(function () {
fn(callback);
}, delay);
}
} else {
cb(error, result);
}
}
fn(callback);
}
CyTube.ui.changeVideoWidth = function uiChangeVideoWidth(direction) {
var body = document.body;
if (/hd/.test(body.className)) {
throw new Error("ui::changeVideoWidth does not work with the 'hd' layout");
}
var videoWrap = document.getElementById("videowrap");
var leftControls = document.getElementById("leftcontrols");
var leftPane = document.getElementById("leftpane");
var chatWrap = document.getElementById("chatwrap");
var rightControls = document.getElementById("rightcontrols");
var rightPane = document.getElementById("rightpane");
var match = videoWrap.className.match(/col-md-(\d+)/);
if (!match) {
throw new Error("ui::changeVideoWidth: videowrap is missing bootstrap class!");
}
var videoWidth = parseInt(match[1], 10) + direction;
if (videoWidth < 3 || videoWidth > 9) {
return;
}
var chatWidth = 12 - videoWidth;
videoWrap.className = "col-md-" + videoWidth + " col-lg-" + videoWidth;
rightControls.className = "col-md-" + videoWidth + " col-lg-" + videoWidth;
rightPane.className = "col-md-" + videoWidth + " col-lg-" + videoWidth;
chatWrap.className = "col-md-" + chatWidth + " col-lg-" + chatWidth;
leftControls.className = "col-md-" + chatWidth + " col-lg-" + chatWidth;
leftPane.className = "col-md-" + chatWidth + " col-lg-" + chatWidth;
handleVideoResize();
};
CyTube._internal_do_not_use_or_you_will_be_banned.addUserToList = function (data, removePrev) {
if (removePrev) {
var user = findUserlistItem(data.name);
// Remove previous instance of user, if there was one
if(user !== null)
user.remove();
}
var div = $("")
.addClass("userlist_item");
var icon = $("").appendTo(div);
var nametag = $("").text(data.name).appendTo(div);
div.data("name", data.name);
div.data("rank", data.rank);
div.data("leader", Boolean(data.leader));
div.data("profile", data.profile);
div.data("meta", data.meta);
if (data.meta.muted || data.meta.smuted) {
div.data("icon", "glyphicon-volume-off");
} else {
div.data("icon", false);
}
formatUserlistItem(div);
addUserDropdown(div, data);
div.appendTo($("#userlist"));
};