/* window focus/blur */ CyTube.ui.onPageFocus = function () { FOCUSED = true; clearInterval(TITLE_BLINK); TITLE_BLINK = false; document.title = PAGETITLE; }; CyTube.ui.onPageBlur = function (event) { FOCUSED = false; }; $(window).on('focus', CyTube.ui.onPageFocus).on('blur', CyTube.ui.onPageBlur); // See #783 $(".modal").on('focus', CyTube.ui.onPageFocus); $("#togglemotd").on('click', function () { var hidden = $("#motd")[0].style.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").on('click', function () { var m = $("#modflair"); if (m.hasClass("label-success")) { USEROPTS.modhat = false; m.removeClass("label-success"); if (SUPERADMIN) { USEROPTS.adminhat = true; m.addClass("label-danger"); } else { m.addClass("label-default"); } } else if (m.hasClass("label-danger")) { USEROPTS.adminhat = false; m.removeClass("label-danger") .addClass("label-default"); } else { USEROPTS.modhat = true; m.removeClass("label-default") .addClass("label-success"); } $("#us-modflair").prop("checked", USEROPTS.modhat); setOpt('modhat', USEROPTS.modhat); }); $("#usercount").on('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").on('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").on('mouseleave', function () { $("#usercount").find(".profile-box").remove(); }); $("#messagebuffer").on('scroll', function (ev) { if (IGNORE_SCROLL_EVENT) { // Skip event, this was triggered by scrollChat() and not by a user action. // Reset for next event. IGNORE_SCROLL_EVENT = false; return; } var m = $("#messagebuffer"); var lastChildHeight = 0; var messages = m.children(); if (messages.length > 0) { lastChildHeight = messages[messages.length - 1].clientHeight || 0; } var isCaughtUp = m.height() + m.scrollTop() >= m.prop("scrollHeight") - lastChildHeight; if (isCaughtUp) { SCROLLCHAT = true; $("#newmessages-indicator").remove(); } else { SCROLLCHAT = false; } }); $("#guestname").on('keydown', function (ev) { if (ev.keyCode === 13) { socket.emit("login", { name: $("#guestname").val() }); } }); CyTube.chatTabCompleteData = { context: {} }; function chatTabComplete(chatline) { if (!CyTube.tabCompleteMethods) { console.error('Missing CyTube.tabCompleteMethods!'); return; } var currentText = chatline.value; var currentPosition = chatline.selectionEnd; if (typeof currentPosition !== 'number' || !chatline.setSelectionRange) { // Bail, we're on IE8 or something similarly dysfunctional return; } var firstWord = !/\s/.test(currentText.trim()); var options = []; var userlistElems = document.getElementById("userlist").children; for (var i = 0; i < userlistElems.length; i++) { var username = userlistElems[i].children[1].textContent; if (firstWord) { username += ':'; } options.push(username); } CHANNEL.emotes.forEach(function (emote) { options.push(emote.name); }); var method = USEROPTS.chat_tab_method; if (!CyTube.tabCompleteMethods[method]) { console.error("Unknown chat tab completion method '" + method + "', using default"); method = "Cycle options"; } var result = CyTube.tabCompleteMethods[method]( currentText, currentPosition, options, CyTube.chatTabCompleteData.context ); chatline.value = result.text; chatline.setSelectionRange(result.newPosition, result.newPosition); } $("#chatline").on('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 try { chatTabComplete(ev.target); } catch (error) { console.error(error); } 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").on('click', showPollMenu); /* search controls */ $("#library_search").on('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").on('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").on('click', function () { var query = $("#library_query").val().toLowerCase(); try { parseMediaLink(query); 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")); } catch (e) {} socket.emit("searchMedia", { source: "yt", query: query }); }); /* user playlists */ $("#userpl_save").on('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").on('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 linkList = $("#mediaurl").val(); var links = linkList.split(",http").map(function (link, i) { if (i > 0) { return "http" + link; } else { return link; } }); 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; try { data = parseMediaLink(link); } catch (error) { Callbacks.queueFail({ link: link, msg: error.message }); return; } var duration = undefined; var title = undefined; if (data.type === "fi") { if (data.id.match(/^http:/)) { Callbacks.queueFail({ link: data.id, msg: "Raw files must begin with 'https'. Plain http is not supported." }); return; } // Explicit checks for kissanime and mega.nz since everyone // asks about them if (data.id.match(/kissanime|kimcartoon|kisscartoon/i)) { Callbacks.queueFail({ link: data.id, msg: "Kisscartoon and Kissanime are not supported. See https://git.io/vxS9n" + " for more information about why these cannot be supported." }); return; } else if (data.id.match(/mega\.nz/)) { Callbacks.queueFail({ link: data.id, msg: "Mega.nz is not supported. See https://git.io/fx6fz" + " for more information about why mega.nz cannot be supported." }); return; } // Raw files allow title overrides since the ffprobe tag data // is not always correct. 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", true) .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); startQueueSpinner(data); if (emitQueue.length > 0) { notification.textContent = "Waiting to queue " + emitQueue[0].link; } else { notification.textContent = ""; } setTimeout(next, nextQueueDelay); } next(); } } $("#queue_next").on('click', queue.bind(this, "next", "url")); $("#queue_end").on('click', queue.bind(this, "end", "url")); $("#ce_queue_next").on('click', queue.bind(this, "next", "customembed")); $("#ce_queue_end").on('click', queue.bind(this, "end", "customembed")); $("#mediaurl").on('keyup', function(ev) { if (ev.keyCode === 13) { queue("end", "url"); } else { var editTitle = false; try { if (parseMediaLink($("#mediaurl").val()).type === "fi") { editTitle = true; } } catch (error) { } if (editTitle) { var title = $("#addfromurl-title"); if (title.length === 0) { title = $("
") .attr("id", "addfromurl-title") .appendTo($("#addfromurl")); $("").text("Title (optional; for raw files only)") .appendTo(title); $("").addClass("form-control") .attr("type", "text") .attr("id", "addfromurl-title-val") .on('keydown', function (ev) { if (ev.keyCode === 13) { queue("end", "url"); } }) .appendTo($("#addfromurl-title")); } } else { $("#addfromurl-title").remove(); } } }); $("#customembed-content").on('keydown', function(ev) { if (ev.keyCode === 13) { queue("end", "customembed"); } }); $("#qlockbtn").on('click', function() { socket.emit("togglePlaylistLock"); }); $("#voteskip").on('click', function() { socket.emit("voteskip"); $("#voteskip").attr("disabled", true); }); $("#getplaylist").on('click', function() { var callback = function(data) { var idx = socket.listeners("errorMsg").indexOf(errCallback); if (idx >= 0) { socket.listeners("errorMsg").splice(idx); } idx = socket.listeners("playlist").indexOf(callback); if (idx >= 0) { socket.listeners("playlist").splice(idx); } 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); $("