/* window focus/blur */ $(window).focus(function() { FOCUSED = true; clearInterval(TITLE_BLINK); TITLE_BLINK = false; document.title = PAGETITLE; }).blur(function() { FOCUSED = false; }); $("#togglemotd").click(function () { var hidden = $("#motd").css("display") === "none"; $("#motd").toggle(); if (hidden) { $("#togglemotd").find(".glyphicon-plus") .removeClass("glyphicon-plus") .addClass("glyphicon-minus"); } else { $("#togglemotd").find(".glyphicon-minus") .removeClass("glyphicon-minus") .addClass("glyphicon-plus"); } }); /* chatbox */ $("#modflair").click(function () { var m = $("#modflair"); if (m.hasClass("label-success")) { USEROPTS.modhat = false; m.removeClass("label-success") .addClass("label-default"); } else { USEROPTS.modhat = true; m.removeClass("label-default") .addClass("label-success"); } }); $("#adminflair").click(function () { var m = $("#adminflair"); if (m.hasClass("label-danger")) { USEROPTS.adminhat = false; m.removeClass("label-danger") .addClass("label-default"); } else { USEROPTS.adminhat = true; m.removeClass("label-default") .addClass("label-danger"); } }); $("#usercount").mouseenter(function (ev) { var breakdown = calcUserBreakdown(); // re-using profile-box class for convenience var popup = $("
") .addClass("profile-box") .css("top", (ev.clientY + 5) + "px") .css("left", (ev.clientX) + "px") .appendTo($("#usercount")); var contents = ""; for(var key in breakdown) { contents += "" + key + ": " + breakdown[key]; contents += "
" } popup.html(contents); }); $("#usercount").mousemove(function (ev) { var popup = $("#usercount").find(".profile-box"); if(popup.length == 0) return; popup.css("top", (ev.clientY + 5) + "px"); popup.css("left", (ev.clientX) + "px"); }); $("#usercount").mouseleave(function () { $("#usercount").find(".profile-box").remove(); }); $("#messagebuffer").mouseenter(function() { SCROLLCHAT = false; }); $("#messagebuffer").mouseleave(function() { SCROLLCHAT = true; }); $("#guestname").keydown(function (ev) { if (ev.keyCode === 13) { socket.emit("login", { name: $("#guestname").val() }); } }); function chatTabComplete() { var words = $("#chatline").val().split(" "); var current = words[words.length - 1].toLowerCase(); if (!current.match(/^[\w-]{1,20}$/)) { return; } var __slice = Array.prototype.slice; var usersWithCap = __slice.call($("#userlist").children()).map(function (elem) { return elem.children[1].innerHTML; }); var users = __slice.call(usersWithCap).map(function (user) { return user.toLowerCase(); }).filter(function (name) { return name.indexOf(current) === 0; }); // users now contains a list of names that start with current word if (users.length === 0) { return; } // trim possible names to the shortest possible completion var min = Math.min.apply(Math, users.map(function (name) { return name.length; })); users = users.map(function (name) { return name.substring(0, min); }); // continually trim off letters until all prefixes are the same var changed = true; var iter = 21; while (changed) { changed = false; var first = users[0]; for (var i = 1; i < users.length; i++) { if (users[i] !== first) { changed = true; break; } } if (changed) { users = users.map(function (name) { return name.substring(0, name.length - 1); }); } // In the event something above doesn't generate a break condition, limit // the maximum number of repetitions if (--iter < 0) { break; } } current = users[0].substring(0, min); for (var i = 0; i < usersWithCap.length; i++) { if (usersWithCap[i].toLowerCase() === current) { current = usersWithCap[i]; break; } } if (users.length === 1) { if (words.length === 1) { current += ":"; } current += " "; } words[words.length - 1] = current; $("#chatline").val(words.join(" ")); } $("#chatline").keydown(function(ev) { // Enter/return if(ev.keyCode == 13) { if (CHATTHROTTLE) { return; } var msg = $("#chatline").val(); if(msg.trim()) { var meta = {}; if (USEROPTS.adminhat && CLIENT.rank >= 255) { msg = "/a " + msg; } else if (USEROPTS.modhat && CLIENT.rank >= Rank.Moderator) { meta.modflair = CLIENT.rank; } // The /m command no longer exists, so emulate it clientside if (CLIENT.rank >= 2 && msg.indexOf("/m ") === 0) { meta.modflair = CLIENT.rank; msg = msg.substring(3); } socket.emit("chatMsg", { msg: msg, meta: meta }); CHATHIST.push($("#chatline").val()); CHATHISTIDX = CHATHIST.length; $("#chatline").val(""); } return; } else if(ev.keyCode == 9) { // Tab completion chatTabComplete(); ev.preventDefault(); return false; } else if(ev.keyCode == 38) { // Up arrow (input history) if(CHATHISTIDX == CHATHIST.length) { CHATHIST.push($("#chatline").val()); } if(CHATHISTIDX > 0) { CHATHISTIDX--; $("#chatline").val(CHATHIST[CHATHISTIDX]); } ev.preventDefault(); return false; } else if(ev.keyCode == 40) { // Down arrow (input history) if(CHATHISTIDX < CHATHIST.length - 1) { CHATHISTIDX++; $("#chatline").val(CHATHIST[CHATHISTIDX]); } ev.preventDefault(); return false; } }); /* poll controls */ $("#newpollbtn").click(showPollMenu); /* search controls */ $("#library_search").click(function() { if (!hasPermission("seeplaylist")) { $("#searchcontrol .alert").remove(); var al = makeAlert("Permission Denied", "This channel does not allow you to search its library", "alert-danger"); al.find(".alert").insertAfter($("#library_query").parent()); return; } socket.emit("searchMedia", { source: "library", query: $("#library_query").val().toLowerCase() }); }); $("#library_query").keydown(function(ev) { if(ev.keyCode == 13) { if (!hasPermission("seeplaylist")) { $("#searchcontrol .alert").remove(); var al = makeAlert("Permission Denied", "This channel does not allow you to search its library", "alert-danger"); al.find(".alert").insertAfter($("#library_query").parent()); return; } socket.emit("searchMedia", { source: "library", query: $("#library_query").val().toLowerCase() }); } }); $("#youtube_search").click(function () { var query = $("#library_query").val().toLowerCase(); if(parseMediaLink(query).type !== null) { makeAlert("Media Link", "If you already have the link, paste it " + "in the 'Media URL' box under Playlist Controls. This "+ "searchbar works like YouTube's search function.", "alert-danger") .insertBefore($("#library")); } socket.emit("searchMedia", { source: "yt", query: query }); }); /* user playlists */ $("#userpl_save").click(function() { if($("#userpl_name").val().trim() == "") { makeAlert("Invalid Name", "Playlist name cannot be empty", "alert-danger") .insertAfter($("#userpl_save").parent()); return; } socket.emit("clonePlaylist", { name: $("#userpl_name").val() }); }); /* video controls */ $("#mediarefresh").click(function() { PLAYER.mediaType = ""; PLAYER.mediaId = ""; // playerReady triggers the server to send a changeMedia. // the changeMedia handler then reloads the player socket.emit("playerReady"); }); /* playlist controls */ $("#queue").sortable({ start: function(ev, ui) { PL_FROM = ui.item.data("uid"); }, update: function(ev, ui) { var prev = ui.item.prevAll(); if(prev.length == 0) PL_AFTER = "prepend"; else PL_AFTER = $(prev[0]).data("uid"); socket.emit("moveMedia", { from: PL_FROM, after: PL_AFTER }); $("#queue").sortable("cancel"); } }); $("#queue").disableSelection(); function queue(pos, src) { if (!src) { src = "url"; } if (src === "customembed") { var title = $("#customembed-title").val(); if (!title) { title = false; } var content = $("#customembed-content").val(); socket.emit("queue", { id: content, title: title, pos: pos, type: "cu", temp: $(".add-temp").prop("checked") }); } else { var links = $("#mediaurl").val().split(","); if (pos === "next") links = links.reverse(); if (pos === "next" && $("#queue li").length === 0) links.unshift(links.pop()); var emitQueue = []; var addTemp = $(".add-temp").prop("checked"); var notification = document.getElementById("addfromurl-queue"); if (!notification) { notification = document.createElement("div"); notification.id = "addfromurl-queue"; document.getElementById("addfromurl").appendChild(notification); } links.forEach(function (link) { var data = parseMediaLink(link); var duration = undefined; var title = undefined; if (data.type === "fi") { title = $("#addfromurl-title-val").val(); } if (data.id == null || data.type == null) { makeAlert("Error", "Failed to parse link " + link + ". Please check that it is correct", "alert-danger") .insertAfter($("#addfromurl")); } else { emitQueue.push({ id: data.id, type: data.type, pos: pos, duration: duration, title: title, temp: addTemp, link: link }); } }); var nextQueueDelay = 1020; function next() { var data = emitQueue.shift(); if (!data) { $("#mediaurl").val(""); $("#addfromurl-title").remove(); return; } var link = data.link; delete data.link; socket.emit("queue", data); if (emitQueue.length > 0) { notification.textContent = "Waiting to queue " + emitQueue[0].link; } else { notification.textContent = ""; } setTimeout(next, nextQueueDelay); } next(); } } $("#queue_next").click(queue.bind(this, "next", "url")); $("#queue_end").click(queue.bind(this, "end", "url")); $("#ce_queue_next").click(queue.bind(this, "next", "customembed")); $("#ce_queue_end").click(queue.bind(this, "end", "customembed")); $("#mediaurl").keyup(function(ev) { if (ev.keyCode === 13) { queue("end", "url"); } else { var url = $("#mediaurl").val().split("?")[0]; if (url.match(/^https?:\/\/(.*)?\.(flv|mp4|og[gv]|webm|mp3|mov)$/)) { var title = $("#addfromurl-title"); if (title.length === 0) { title = $("
") .attr("id", "addfromurl-title") .appendTo($("#addfromurl")); $("").text("Title (optional)") .appendTo(title); $("").addClass("form-control") .attr("type", "text") .attr("id", "addfromurl-title-val") .keydown(function (ev) { if (ev.keyCode === 13) { queue("end", "url"); } }) .appendTo($("#addfromurl-title")); } } else { $("#addfromurl-title").remove(); } } }); $("#customembed-content").keydown(function(ev) { if (ev.keyCode === 13) { queue("end", "customembed"); } }); $("#qlockbtn").click(function() { socket.emit("togglePlaylistLock"); }); $("#voteskip").click(function() { socket.emit("voteskip"); $("#voteskip").attr("disabled", true); }); $("#getplaylist").click(function() { var callback = function(data) { hidePlayer(); socket.listeners("playlist").splice( socket.listeners("playlist").indexOf(callback) ); var list = []; for(var i = 0; i < data.length; i++) { var entry = formatURL(data[i].media); list.push(entry); } var urls = list.join(","); var outer = $("
").addClass("modal fade") .appendTo($("body")); modal = $("
").addClass("modal-dialog").appendTo(outer); modal = $("
").addClass("modal-content").appendTo(modal); var head = $("
").addClass("modal-header") .appendTo(modal); $("