diff --git a/www/assets/css/ytsync.css b/www/assets/css/ytsync.css
index 5c768cb6..c2cc3159 100644
--- a/www/assets/css/ytsync.css
+++ b/www/assets/css/ytsync.css
@@ -1,289 +1,293 @@
-html, body {
- height: 100%;
-}
-
-.wrapper {
- min-height: 100%;
- height: auto !important;
- height: 100%;
- margin: 0 auto -90px;
-}
-
-#footer, .push {
- margin: 90px 0 0 0;
- height: 30px;
- clear: both;
-}
-
-#welcome {
- font-size: 10pt;
- color: #ffffff;
-}
-
-#usercountwrap, #userlist, #messagebuffer, #videowrap {
- background-color: #ffffff;
-}
-
-#librarytoggle, #userpltoggle, #playlisttoggle {
- background-color: #ffffff;
-}
-
-#librarywrap, #userplaylistwrap, #playlist_controls {
- display: none;
-}
-
-.videolist {
- list-style: none outside none;
- margin-left: 0;
- max-height: 500px;
- overflow-y: scroll;
-}
-
-.qe_btn {
- height: 20px;
- font-family: Monospace;
- padding: 0 5px 0 5px;
- margin: auto;
- overflow: hidden;
-}
-
-.qe_buttons {
- float: left;
-}
-
-.qe_title {
- float: left;
-}
-
-.qe_time {
- font-family: Monospace;
- float: right;
-}
-
-.qe_clear {
- clear: both;
-}
-
-#userpl_list {
- list-style: none outside none;
- margin-left: 0;
- max-height: 500px;
- overflow-y: scroll;
-}
-
-#userpl_list li {
- clear: both;
- margin: 2px 0 0 auto;
- padding: 2px;
- font-size: 8pt;
-}
-
-#usercountwrap, #currenttitle {
- border: 1px solid #aaaaaa;
- border-bottom: none;
- margin: 0;
-}
-
-#usercount {
- margin: 0;
-}
-
-.pointer {
- cursor: pointer;
-}
-
-#leftpane-inner div.span12, #rightpane-inner div.span12,
-#leftpane-inner ul, #rightpane-inner ul {
- margin-left: 0;
-}
-
-#queue {
- margin-bottom: 0;
-}
-
-.queue_entry {
- cursor: row-resize;
- background-color: #ffffff;
- margin: 2px 0 0 auto;
- padding: 2px;
- font-size: 8pt;
- border: 1px solid #aaaaaa; // [](/w21)
-}
-
-#plmeta {
- border: 1px solid #aaaaaa;
- background-color: #ffffff;
- padding: 3px;
- margin: 0;
- font-size: 12pt;
-}
-
-#plcount {
- float: left;
-}
-
-#pllength {
- float: right;
-}
-
-#userlist {
- overflow-y: scroll;
- overflow-x: hidden;
- height: 347px;
- float: left;
- width: 150px;
- border: 1px solid #aaaaaa; // [](/z13)
- border-left: none;
-}
-
-#messagebuffer {
- overflow-y: scroll;
- overflow-x: hidden;
- height: 347px;
- border: 1px solid #aaaaaa; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
- border-left: 0;
-}
-
-#messagebuffer div, #messagebuffer code {
- white-space: pre-wrap; /* css-3 */
- white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
- white-space: -pre-wrap; /* Opera 4-6 */
- white-space: -o-pre-wrap; /* Opera 7 */
- word-wrap: break-word; /* Internet Explorer 5.5+ */
-}
-
-.userlist_siteadmin {
- color: #cc0000;
- font-weight: bold;
-}
-
-.userlist_owner {
- color: #0000cc;
- font-weight: bold;
-}
-
-.userlist_op {
- color: #00aa00;
-}
-
-.userlist_guest {
- color: #888888;
-}
-
-.action {
- font-style: italic;
- color: #888888;
-}
-
-.spoiler {
- color: #000000;
- background-color: #000000;
-}
-
-.spoiler:hover {
- color: #ffffff;
-}
-
-.greentext {
- color: #789922; /* Color value directly from 4chan */
-}
-
-.shout {
- color: #ff0000;
- font-weight: bold;
- font-size: 18pt;
-}
-
-.mono {
- font-family: Monospace;
-}
-
-.server-msg-disconnect {
- border: 1px solid #ff0000;
- margin: 5px;
- padding: 5px;
- color: #ff0000;
-}
-
-.server-msg-reconnect {
- border: 1px solid #009900;
- margin: 5px;
- padding: 5px;
- color: #009900;
-}
-
-.poll-notify {
- color: #0000aa;
- font-weight: bold;
- font-size: 14pt;
-}
-
-.option button {
- margin-right: 15px;
-}
-
-.nick-highlight {
- background-color: #ddffdd;
-}
-
-.nick-hover {
- background-color: #ffff99;
-}
-
-.drink {
- margin: 10px 10px;
- padding: 10px 0px;
- border: 2px solid #0000cc;
-}
-
-#drinkbar {
- margin-left: 0;
- background-color: #000000;
- color: #ffffff;
- text-align: center;
-}
-
-#motdtext, #csstext, #jstext {
- width: 100%;
-}
-
-#csstext, #jstext {
- font-family: Monospace;
-}
-
-#queue_next, #queue_end, #library_search, #youtube_search {
- width: 50%;
-}
-
-#footer {
- background-color: #f5f5f5;
- height: 30px;
- width: 100%;
- padding: 0;
-}
-
-#footer p {
- text-align: center;
- width: 100%;
-}
-
-.timestamp {
- font-size: 8pt;
-}
-
-.profile-box {
- z-index: 9999;
- position: absolute;
- border: 1px solid #aaaaaa;
- border-radius: 5px;
- background-color: #ffffff;
- max-width: 200px;
- padding: 5px;
-}
-
-.profile-image {
- width: 80px;
- height: 80px;
- border: 1px solid #aaaaaa;
- border-radius: 5px;
-}
+html, body {
+ height: 100%;
+}
+
+.wrapper {
+ min-height: 100%;
+ height: auto !important;
+ height: 100%;
+ margin: 0 auto -90px;
+}
+
+#footer, .push {
+ margin: 90px 0 0 0;
+ height: 30px;
+ clear: both;
+}
+
+#welcome {
+ font-size: 10pt;
+ color: #ffffff;
+}
+
+#usercountwrap, #userlist, #messagebuffer, #videowrap {
+ background-color: #ffffff;
+}
+
+#librarytoggle, #userpltoggle, #playlisttoggle {
+ background-color: #ffffff;
+}
+
+#librarywrap, #userplaylistwrap, #playlist_controls {
+ display: none;
+}
+
+.videolist {
+ list-style: none outside none;
+ margin-left: 0;
+ max-height: 500px;
+ overflow-y: scroll;
+}
+
+.qe_btn {
+ height: 20px;
+ font-family: Monospace;
+ padding: 0 5px 0 5px;
+ margin: auto;
+ overflow: hidden;
+}
+
+.qe_buttons {
+ float: left;
+}
+
+.qe_title {
+ float: left;
+}
+
+.qe_time {
+ font-family: Monospace;
+ float: right;
+}
+
+.qe_clear {
+ clear: both;
+}
+
+#userpl_list {
+ list-style: none outside none;
+ margin-left: 0;
+ max-height: 500px;
+ overflow-y: scroll;
+}
+
+#userpl_list li {
+ clear: both;
+ margin: 2px 0 0 auto;
+ padding: 2px;
+ font-size: 8pt;
+}
+
+#usercountwrap, #currenttitle {
+ border: 1px solid #aaaaaa;
+ border-bottom: none;
+ margin: 0;
+}
+
+#usercount {
+ margin: 0;
+}
+
+.pointer {
+ cursor: pointer;
+}
+
+#leftpane-inner div.span12, #rightpane-inner div.span12,
+#leftpane-inner ul, #rightpane-inner ul {
+ margin-left: 0;
+}
+
+#queue {
+ margin-bottom: 0;
+}
+
+.queue_entry {
+ cursor: row-resize;
+ background-color: #ffffff;
+ margin: 2px 0 0 auto;
+ padding: 2px;
+ font-size: 8pt;
+ border: 1px solid #aaaaaa; // [](/w21)
+}
+
+.queue_temp {
+ background-image: url(../img/stripe-diagonal.png);
+}
+
+#plmeta {
+ border: 1px solid #aaaaaa;
+ background-color: #ffffff;
+ padding: 3px;
+ margin: 0;
+ font-size: 12pt;
+}
+
+#plcount {
+ float: left;
+}
+
+#pllength {
+ float: right;
+}
+
+#userlist {
+ overflow-y: scroll;
+ overflow-x: hidden;
+ height: 347px;
+ float: left;
+ width: 150px;
+ border: 1px solid #aaaaaa; // [](/z13)
+ border-left: none;
+}
+
+#messagebuffer {
+ overflow-y: scroll;
+ overflow-x: hidden;
+ height: 347px;
+ border: 1px solid #aaaaaa; // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
+ border-left: 0;
+}
+
+#messagebuffer div, #messagebuffer code {
+ white-space: pre-wrap; /* css-3 */
+ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ word-wrap: break-word; /* Internet Explorer 5.5+ */
+}
+
+.userlist_siteadmin {
+ color: #cc0000;
+ font-weight: bold;
+}
+
+.userlist_owner {
+ color: #0000cc;
+ font-weight: bold;
+}
+
+.userlist_op {
+ color: #00aa00;
+}
+
+.userlist_guest {
+ color: #888888;
+}
+
+.action {
+ font-style: italic;
+ color: #888888;
+}
+
+.spoiler {
+ color: #000000;
+ background-color: #000000;
+}
+
+.spoiler:hover {
+ color: #ffffff;
+}
+
+.greentext {
+ color: #789922; /* Color value directly from 4chan */
+}
+
+.shout {
+ color: #ff0000;
+ font-weight: bold;
+ font-size: 18pt;
+}
+
+.mono {
+ font-family: Monospace;
+}
+
+.server-msg-disconnect {
+ border: 1px solid #ff0000;
+ margin: 5px;
+ padding: 5px;
+ color: #ff0000;
+}
+
+.server-msg-reconnect {
+ border: 1px solid #009900;
+ margin: 5px;
+ padding: 5px;
+ color: #009900;
+}
+
+.poll-notify {
+ color: #0000aa;
+ font-weight: bold;
+ font-size: 14pt;
+}
+
+.option button {
+ margin-right: 15px;
+}
+
+.nick-highlight {
+ background-color: #ddffdd;
+}
+
+.nick-hover {
+ background-color: #ffff99;
+}
+
+.drink {
+ margin: 10px 10px;
+ padding: 10px 0px;
+ border: 2px solid #0000cc;
+}
+
+#drinkbar {
+ margin-left: 0;
+ background-color: #000000;
+ color: #ffffff;
+ text-align: center;
+}
+
+#motdtext, #csstext, #jstext {
+ width: 100%;
+}
+
+#csstext, #jstext {
+ font-family: Monospace;
+}
+
+#queue_next, #queue_end, #library_search, #youtube_search {
+ width: 50%;
+}
+
+#footer {
+ background-color: #f5f5f5;
+ height: 30px;
+ width: 100%;
+ padding: 0;
+}
+
+#footer p {
+ text-align: center;
+ width: 100%;
+}
+
+.timestamp {
+ font-size: 8pt;
+}
+
+.profile-box {
+ z-index: 9999;
+ position: absolute;
+ border: 1px solid #aaaaaa;
+ border-radius: 5px;
+ background-color: #ffffff;
+ max-width: 200px;
+ padding: 5px;
+}
+
+.profile-image {
+ width: 80px;
+ height: 80px;
+ border: 1px solid #aaaaaa;
+ border-radius: 5px;
+}
diff --git a/www/assets/img/stripe-diagonal.png b/www/assets/img/stripe-diagonal.png
new file mode 100644
index 00000000..ae44b914
Binary files /dev/null and b/www/assets/img/stripe-diagonal.png differ
diff --git a/www/assets/js/callbacks.js b/www/assets/js/callbacks.js
index 66fe6864..ef8702d2 100644
--- a/www/assets/js/callbacks.js
+++ b/www/assets/js/callbacks.js
@@ -1,824 +1,826 @@
-/*
-The MIT License (MIT)
-Copyright (c) 2013 Calvin Montgomery
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-Callbacks = {
-
- /* fired when socket connection completes */
- connect: function() {
- socket.emit("joinChannel", {
- name: CHANNEL.name
- });
- if(uname && session) {
- socket.emit("login", {
- name: NAME,
- session: SESSION
- });
- }
- $("
").addClass("server-msg-reconnect")
- .text("Connected")
- .appendTo($("#messagebuffer"));
- $("#messagebuffer").scrollTop($("#messagebuffer").prop("scrollHeight"));
- },
-
- disconnect: function() {
- if(KICKED)
- return;
- $("")
- .addClass("server-msg-disconnect")
- .text("Disconnected from server. Attempting reconnection...")
- .appendTo($("#messagebuffer"));
- scrollChat();
- },
-
- errorMsg: function(data) {
- alert(data.msg);
- },
-
- announcement: function(data) {
- $("#announcements").html("");
- makeAlert(data.title, data.text)
- .appendTo($("#announcements"));
- },
-
- kick: function(data) {
- KICKED = true;
- $("").addClass("server-msg-disconnect")
- .text("Kicked: " + data.reason)
- .appendTo($("#messagebuffer"));
- scrollChat();
- },
-
- noflood: function(data) {
- $("")
- .addClass("server-msg-disconnect")
- .text(data.action + ": " + data.msg)
- .appendTo($("#messagebuffer"));
- scrollChat();
- },
-
- channelNotRegistered: function() {
- var div = $("").addClass("alert alert-info")
- .attr("id", "chregnotice")
- .insertBefore($("#main"));
- $("").addClass("close pull-right").html("×")
- .appendTo(div)
- .click(function() { div.remove(); });
- $("").text("This channel isn't registered").appendTo(div);
- $("").addClass("btn btn-primary").text("Register it")
- .appendTo(div)
- .click(function() {
- socket.emit("registerChannel");
- });
- },
-
- registerChannel: function(data) {
- if(data.success) {
- $("#chregnotice").remove();
- }
- else {
- makeAlert("Error", data.error, "alert-error")
- .insertAfter($("#chregnotice"));
- }
- },
-
- unregisterChannel: function(data) {
- if(data.success) {
- alert("Channel unregistered");
- }
- else {
- alert(data.error);
- }
- },
-
- setMotd: function(data) {
- $("#motd").html(data.html);
- if(data.motd != "")
- $("#motd").show();
- else
- $("#motd").hide();
- },
-
- chatFilters: function(entries) {
- var tbl = $("#filtereditor table");
- if(tbl.children().length > 1) {
- $(tbl.children()[1]).remove();
- }
- for(var i = 0; i < entries.length; i++) {
- var f = entries[i];
- var tr = $("
").appendTo(tbl);
- var remove = $("").addClass("btn btn-mini btn-danger")
- .appendTo($(" | ").appendTo(tr));
- $("").addClass("icon-remove-circle").appendTo(remove);
- var name = $("
").text(f.name)
- .appendTo($(" | ").appendTo(tr));
- var regex = $("
").text(f.source)
- .appendTo($(" | ").appendTo(tr));
- var flags = $("
").text(f.flags)
- .appendTo($(" | ").appendTo(tr));
- var replace = $("
").text(f.replace)
- .appendTo($(" | ").appendTo(tr));
- var activetd = $(" | ").appendTo(tr);
- var active = $("").attr("type", "checkbox")
- .prop("checked", f.active).appendTo(activetd);
-
- var remcallback = (function(filter) { return function() {
- socket.emit("chatFilter", {
- cmd: "remove",
- filter: filter
- });
- } })(f);
- remove.click(remcallback);
-
- var actcallback = (function(filter) { return function() {
- // Apparently when you check a checkbox, its value is changed
- // before this callback. When you uncheck it, its value is not
- // changed before this callback
- // [](/amgic)
- var enabled = active.prop("checked");
- filter.active = (filter.active == enabled) ? !enabled : enabled;
- socket.emit("chatFilter", {
- cmd: "update",
- filter: filter
- });
- } })(f);
- active.click(actcallback);
- }
-
- var newfilt = $("
").appendTo(tbl);
- $(" | ").appendTo(newfilt);
- var name = $("").attr("type", "text")
- .appendTo($(" | ").appendTo(newfilt));
- var regex = $("").attr("type", "text")
- .appendTo($(" | ").appendTo(newfilt));
- var flags = $("").attr("type", "text")
- .val("g")
- .appendTo($(" | ").appendTo(newfilt));
- var replace = $("").attr("type", "text")
- .appendTo($(" | ").appendTo(newfilt));
- var add = $("").addClass("btn btn-primary")
- .text("Add Filter")
- .appendTo($(" | ").appendTo(newfilt));
- var cback = (function(name, regex, fg, replace) { return function() {
- if(regex.val() && replace.val()) {
- var re = regex.val();
- var flags = fg.val();
- try {
- var dummy = new RegExp(re, flags);
- }
- catch(e) {
- makeAlert("Invalid regex", e+"", "alert-error")
- .insertAfter($("#filtereditor table"));
- return;
- }
- socket.emit("chatFilter", {
- cmd: "update",
- filter: {
- name: name.val(),
- source: re,
- flags: flags,
- replace: replace.val(),
- active: true
- }
- });
- }
- } })(name, regex, flags, replace);
- add.click(cback);
- },
-
- channelOpts: function(opts) {
- // TODO update if necessary when HTML admin stuff added
- $("#opt_pagetitle").attr("placeholder", opts.pagetitle);
- document.title = opts.pagetitle;
- PAGETITLE = opts.pagetitle;
- $("#opt_customcss").val(opts.customcss);
- $("#opt_customjs").val(opts.customjs);
- $("#opt_chat_antiflood").prop("checked", opts.chat_antiflood);
- $("#opt_show_public").prop("checked", opts.show_public);
- $("#opt_enable_link_regex").prop("checked", opts.enable_link_regex);
- $("#customCss").remove();
- if(opts.customcss.trim() != "") {
- $("")
- .attr("rel", "stylesheet")
- .attr("href", opts.customcss)
- .attr("id", "customCss")
- .appendTo($("head"));
- }
- $("#opt_allow_voteskip").prop("checked", opts.allow_voteskip);
- $("#opt_voteskip_ratio").val(opts.voteskip_ratio);
- if(opts.customjs.trim() != "") {
- if(opts.customjs != CHANNEL.opts.customjs) {
- $.getScript(opts.customjs);
- }
- }
-
- CHANNEL.opts = opts;
-
- if(opts.allow_voteskip)
- $("#voteskip").attr("disabled", false);
- else
- $("#voteskip").attr("disabled", true);
- handlePermissionChange();
- },
-
- setPermissions: function(perms) {
- CHANNEL.perms = perms;
- if(CLIENT.rank >= Rank.Admin)
- genPermissionsEditor();
- handlePermissionChange();
- },
-
- channelCSSJS: function(data) {
- $("#chancss").remove();
- $("#chanjs").remove();
-
- $("#csstext").val(data.css);
- $("#jstext").val(data.js);
-
- if(data.css) {
- $("").attr("type", "text/css")
- .attr("id", "chancss")
- .text(data.css)
- .appendTo($("head"));
- }
-
- if(data.js) {
- $("").attr("type", "text/javascript")
- .attr("id", "chanjs")
- .text(data.js)
- .appendTo($("body"));
- }
- },
-
- banlist: function(entries) {
- var tbl = $("#banlist table");
- if(tbl.children().length > 1) {
- $(tbl.children()[1]).remove();
- }
- for(var i = 0; i < entries.length; i++) {
- var tr = $("
").appendTo(tbl);
- var remove = $("").addClass("btn btn-mini btn-danger")
- .appendTo($(" | ").appendTo(tr));
- $("").addClass("icon-remove-circle").appendTo(remove);
- var ip = $(" | ").text(entries[i].ip).appendTo(tr);
- var name = $(" | ").text(entries[i].name).appendTo(tr);
- var aliases = $(" | ").text(entries[i].aliases).appendTo(tr);
- var banner = $(" | ").text(entries[i].banner).appendTo(tr);
-
- var callback = (function(id, name) { return function() {
- socket.emit("unban", {
- id: id,
- name: name
- });
- } })(entries[i].id, entries[i].name);
- remove.click(callback);
- }
- },
-
- channelRanks: function(entries) {
- // TODO Edit if necessary
- entries.sort(function(a, b) {
- var x = a.name.toLowerCase();
- var y = b.name.toLowerCase();
- return y == x ? 0 : (x < y ? -1 : 1);
- });
- $("#channelranks").data("entries", entries);
- var tbl = $("#channelranks table");
- if(tbl.children().length > 1) {
- $(tbl.children()[1]).remove();
- }
- $("#acl_pagination").remove();
- if(entries.length > 20) {
- var pag = $("").addClass("pagination span12")
- .attr("id", "acl_pagination")
- .prependTo($("#channelranks"));
- var btns = $("").appendTo(pag);
- for(var i = 0; i < entries.length / 20; i++) {
- var li = $("").appendTo(btns);
- (function(i) {
- $("").attr("href", "javascript:void(0)")
- .text(i+1)
- .click(function() {
- loadACLPage(i);
- })
- .appendTo(li);
- })(i);
- }
- }
- loadACLPage(0);
- },
-
- setChannelRank: function(data) {
- var ents = $("#channelranks").data("entries");
- for(var i = 0; i < ents.length; i++) {
- if(ents[i].name == data.user) {
- ents[i].rank = data.rank;
- break;
- }
- }
- $("#channelranks").data("entries", ents);
- loadACLPage($("#channelranks").data("page"));
- },
-
- voteskip: function(data) {
- if(data.count > 0) {
- $("#voteskip").text("Voteskip ("+data.count+"/"+data.need+")");
- }
- else {
- $("#voteskip").text("Voteskip");
- }
- },
-
- /* REGION Rank Stuff */
-
- rank: function(r) {
- CLIENT.rank = r;
- handlePermissionChange();
- },
-
- /* should not be relevant since registration is on account.html */
- register: function(data) {
- if(data.error) {
- alert(data.error);
- }
- },
-
- login: function(data) {
- if(!data.success) {
- if(data.error != "Invalid session") {
- alert(data.error);
- }
- }
- else {
- $("#welcome").text("Logged in as " + data.name);
- $("#loginform").css("display", "none");
- $("#logoutform").css("display", "");
- $("#loggedin").css("display", "");
- SESSION = data.session || "";
- CLIENT.name = data.name;
- CLIENT.logged_in = true;
- if(SESSION) {
- createCookie("cytube_uname", CLIENT.name, 7);
- createCookie("cytube_session", SESSION, 7);
- }
- }
- },
-
- /* REGION Chat */
- usercount: function(count) {
- var text = count + " connected user";
- if(count != 1) {
- text += "s";
- }
- $("#usercount").text(text);
- },
-
- chatMsg: function(data) {
- addChatMessage(data);
- },
-
- clearchat: function() {
- $("#messagebuffer").html("");
- },
-
- userlist: function(data) {
- $(".userlist_item").each(function() { $(this).remove(); });
- for(var i = 0; i < data.length; i++) {
- Callbacks.addUser(data[i]);
- }
- },
-
- addUser: function(data) {
- var div = $("").attr("class", "userlist_item");
- var flair = $("").appendTo(div);
- var nametag = $("").text(data.name).appendTo(div);
- formatUserlistItem(div, data);
- addUserDropdown(div, data.name);
- var users = $("#userlist").children();
- for(var i = 0; i < users.length; i++) {
- var othername = users[i].children[1].innerHTML;
- if(othername.toLowerCase() > data.name.toLowerCase()) {
- div.insertBefore(users[i]);
- return;
- }
- }
- div.appendTo($("#userlist"));
- },
-
- updateUser: function(data) {
- if(data.name == CLIENT.name) {
- CLIENT.leader = data.leader;
- CLIENT.rank = data.rank;
- handlePermissionChange();
- if(CLIENT.leader) {
- // I'm a leader! Set up sync function
- if(LEADTMR)
- clearInterval(LEADTMR);
- LEADTMR = setInterval(function() {
- PLAYER.getTime(function(seconds) {
- socket.emit("mediaUpdate", {
- id: PLAYER.id,
- currentTime: seconds,
- paused: PLAYER.paused,
- type: PLAYER.type
- });
- });
- }, 5000);
- }
- // I'm not a leader. Don't send syncs to the server
- else {
- if(LEADTMR)
- clearInterval(LEADTMR);
- LEADTMR = false;
- }
-
- }
- var users = $("#userlist").children();
- for(var i = 0; i < users.length; i++) {
- var name = users[i].children[1].innerHTML;
- // Reformat user
- if(name == data.name) {
- formatUserlistItem($(users[i]), data);
- }
- }
-
- },
-
- userLeave: function(data) {
- var users = $("#userlist").children();
- for(var i = 0; i < users.length; i++) {
- var name = users[i].children[1].innerHTML;
- if(name == data.name) {
- $(users[i]).remove();
- // Note: no break statement here because allowing
- // the loop to continue means a free cleanup if something
- // goes wrong and there's a duplicate name
- }
- }
- },
-
- drinkCount: function(data) {
- if(data.count != 0) {
- var text = data.count + " drink";
- if(data.count != 1) {
- text += "s";
- }
- $("#drinkcount").text(text);
- $("#drinkbar").show();
- }
- else {
- $("#drinkbar").hide();
- }
- },
-
- /* REGION Playlist Stuff */
- playlist: function(data) {
- // Clear the playlist first
- var q = $("#queue");
- q.html("");
-
-
- for(var i = 0; i < data.length; i++) {
- Callbacks.queue({
- media: data[i],
- pos: q.children().length
- });
- }
- },
-
- setPlaylistMeta: function(data) {
- var c = data.count + " item";
- if(data.count != 1)
- c += "s";
- $("#plcount").text(c);
- $("#pllength").text(data.time);
- },
-
- queue: function(data) {
- var li = makeQueueEntry(data.media);
- li.hide();
- addQueueButtons(li);
- var idx = data.pos;
- var q = $("#queue");
- li.attr("title", data.media.queueby
- ? ("Added by: " + data.media.queueby)
- : "Added by: Unknown");
- if(idx < q.children().length - 1)
- li.insertBefore(q.children()[idx])
- else
- li.appendTo(q);
- li.show("blind");
- },
-
- queueFail: function(data) {
- if(!data) {
- data = "Queue failed. Check your link to make sure it is valid.";
- }
- makeAlert("Error", data, "alert-error")
- .insertAfter($("#mediaurl").parent());
- },
-
- setTemp: function(data) {
- // TODO redo this when buttons are decided
- var li = $("#queue").children()[data.idx];
- li = $(li);
- var buttons = li.find(".qe_btn");
- if(buttons.length == 5) {
- $(buttons[4]).removeClass("btn-danger btn-success");
- $(buttons[4]).addClass(data.temp ? "btn-success" : "btn-danger");
- }
- if(data.temp) {
- li.addClass("alert alert-error");
- }
- else {
- li.removeClass("alert alert-error");
- }
- },
-
- unqueue: function(data) {
- var li = $("#queue").children()[data.pos];
- $(li).remove();
- },
-
- moveVideo: function(data) {
- playlistMove(data.src, data.dest);
- },
-
- setPosition: function(data) {
- $("#queue li").each(function() {
- $(this).removeClass("queue_active");
- });
- if(data.position < 0)
- return;
- POSITION = data.position;
- var linew = $("#queue").children()[POSITION];
- $(linew).addClass("queue_active");
-
- $("#queue").scrollTop(0);
- var scroll = $(linew).position().top - $("#queue").position().top;
- $("#queue").scrollTop(scroll);
-
- if(CHANNEL.opts.allow_voteskip)
- $("#voteskip").attr("disabled", false);
- },
-
- changeMedia: function(data) {
- $("#currenttitle").text("Currently Playing: " + data.title);
- if(data.type != "sc" && PLAYER.type == "sc")
- // [](/goddamnitmango)
- fixSoundcloudShit();
- if(data.type != "jw" && PLAYER.type == "jw") {
- // Is it so hard to not mess up my DOM?
- $("").attr("id", "ytapiplayer")
- .insertBefore($("#ytapiplayer_wrapper"));
- $("#ytapiplayer_wrapper").remove();
- }
- if(data.type != PLAYER.type) {
- PLAYER = new Player(data);
- }
- if(PLAYER.update) {
- PLAYER.update(data);
- }
- },
-
- mediaUpdate: function(data) {
- if(PLAYER.update) {
- PLAYER.update(data);
- }
- },
-
- setPlaylistLocked: function(data) {
- CHANNEL.openqueue = !data.locked;
- // TODO handlePermissionsChange?
- if(CHANNEL.openqueue) {
- $("#playlist_controls").css("display", "");
- if(RANK < Rank.Moderator) {
- $("#qlockbtn").css("display", "none");
- rebuildPlaylist();
- if(!CHANNELOPTS.qopen_allow_qnext)
- $("#queue_next").attr("disabled", true);
- if(!CHANNELOPTS.qopen_allow_playnext)
- $("#play_next").attr("disabled", true);
- }
- }
- else if(RANK < Rank.Moderator && !LEADER) {
- $("#playlist_controls").css("display", "none");
- rebuildPlaylist();
- }
- if(CHANNEL.openqueue) {
- $("#qlockbtn").removeClass("btn-danger")
- .addClass("btn-success")
- .text("Lock Playlist");
- }
- else {
- $("#qlockbtn").removeClass("btn-success")
- .addClass("btn-danger")
- .text("Unlock Playlist");
- }
- },
-
- searchResults: function(data) {
- clearSearchResults();
- $("#library").data("entries", data.results);
- if(data.results.length > 100) {
- var pag = $("").addClass("pagination")
- .attr("id", "search_pagination")
- .insertAfter($("#library"));
- var btns = $("").appendTo(pag);
- for(var i = 0; i < data.results.length / 100; i++) {
- var li = $("").appendTo(btns);
- (function(i) {
- $("").attr("href", "javascript:void(0)")
- .text(i+1)
- .click(function() {
- loadSearchPage(i);
- })
- .appendTo(li);
- })(i);
- }
- }
- loadSearchPage(0);
- },
-
- /* REGION Polls */
- newPoll: function(data) {
- Callbacks.closePoll();
- var pollMsg = $("").addClass("poll-notify")
- .text(data.initiator + " opened a poll: \"" + data.title + "\"")
- .appendTo($("#messagebuffer"));
- scrollChat();
-
- var poll = $("").addClass("well active").prependTo($("#pollcontainer"));
- $("").addClass("close pull-right").html("×")
- .appendTo(poll)
- .click(function() { poll.remove(); });
- if(hasPermission("pollctl")) {
- $("").addClass("btn btn-danger pull-right").text("End Poll")
- .appendTo(poll)
- .click(function() {
- socket.emit("closePoll")
- });
- }
-
- $("").text(data.title).appendTo(poll);
- for(var i = 0; i < data.options.length; i++) {
- (function(i) {
- var callback = function() {
- socket.emit("vote", {
- option: i
- });
- poll.find(".option button").each(function() {
- $(this).attr("disabled", "disabled");
- });
- }
- $("").addClass("btn").text(data.counts[i])
- .prependTo($("").addClass("option").text(data.options[i])
- .appendTo(poll))
- .click(callback);
- })(i);
-
- }
-
- poll.find(".btn").attr("disabled", !hasPermission("pollvote"));
- },
-
- updatePoll: function(data) {
- var poll = $("#pollcontainer .active");
- var i = 0;
- poll.find(".option button").each(function() {
- $(this).text(data.counts[i]);
- i++;
- });
- },
-
- closePoll: function() {
- if($("#pollcontainer .active").length != 0) {
- var poll = $("#pollcontainer .active");
- poll.removeClass("active").addClass("muted");
- poll.find(".option button").each(function() {
- $(this).attr("disabled", true);
- });
- poll.find(".btn-danger").each(function() {
- $(this).remove()
- });
- }
- },
-
- savePlaylist: function(data) {
- if(data.success) {
- makeAlert("Success", "Playlist saved.", "alert-success");
- }
- else {
- makeAlert("Error", data.error, "alert-error")
- .addClass("span12")
- .insertBefore($("#userpl_list"));
- }
- },
-
- listPlaylists: function(data) {
- if(data.error) {
- makeAlert("Error", data.error, "alert-error")
- .addClass("span12")
- .insertBefore($("#userpl_list"));
- }
- else {
- var pls = data.pllist;
- pls.sort(function(a, b) {
- var x = a.name.toLowerCase();
- var y = b.name.toLowerCase();
- if(x < y) return -1;
- if(x > y) return 1;
- return 0;
- });
- $("#userpl_list").html("");
- for(var i = 0; i < pls.length; i++) {
- var li = $("").appendTo($("#userpl_list"))
- .addClass("well");
- li.data("pl-name", pls[i].name);
- $("").text(pls[i].name).appendTo(li)
- .css("float", "left")
- .css("margin-left", "1em");
- var metastr = pls[i].count + " item";
- if(pls[i].count != 1) {
- metastr += "s";
- }
- metastr +=", playtime " + pls[i].time;
- $("").text(metastr)
- .css("float", "right")
- .appendTo(li);
- var bg = $("").addClass("btn-group")
- .css("float", "left")
- .prependTo(li);
- var del = $("")
- .addClass("btn btn-mini btn-danger")
- .prependTo(bg);
- $("").addClass("icon-trash").appendTo(del);
- (function(li) {
- del.click(function() {
- socket.emit("deletePlaylist", {
- name: li.data("pl-name")
- });
- });
- })(li);
- if(hasPermission("playlistaddlist")) {
- (function(li) {
- $("").addClass("btn btn-mini")
- .text("End")
- .prependTo(bg)
- .click(function() {
- socket.emit("queuePlaylist", {
- name: li.data("pl-name"),
- pos: "end"
- });
- });
- })(li);
-
- if(hasPermission("playlistnext")) {
- (function(li) {
- $("").addClass("btn btn-mini")
- .text("Next")
- .prependTo(bg)
- .click(function() {
- socket.emit("queuePlaylist", {
- name: li.data("pl-name"),
- pos: "next"
- });
- });
- })(li);
- }
- }
- }
- }
- }
-}
-
-/*
-$.getScript(IO_URL+"/socket.io/socket.io.js", function() {
- try {
- socket = io.connect(IO_URL);
- for(var key in Callbacks) {
- socket.on(key, Callbacks[key]);
- }
- }
- catch(e) {
- Callbacks.disconnect();
- }
-});
-*/
-
-setupCallbacks = function() {
- for(var key in Callbacks) {
- (function(key) {
- socket.on(key, function() {
- Callbacks[key]();
- });
- })(key);
- }
-}
+/*
+The MIT License (MIT)
+Copyright (c) 2013 Calvin Montgomery
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+Callbacks = {
+
+ /* fired when socket connection completes */
+ connect: function() {
+ socket.emit("joinChannel", {
+ name: CHANNEL.name
+ });
+ if(uname && session) {
+ socket.emit("login", {
+ name: NAME,
+ session: SESSION
+ });
+ }
+ $("").addClass("server-msg-reconnect")
+ .text("Connected")
+ .appendTo($("#messagebuffer"));
+ $("#messagebuffer").scrollTop($("#messagebuffer").prop("scrollHeight"));
+ },
+
+ disconnect: function() {
+ if(KICKED)
+ return;
+ $("")
+ .addClass("server-msg-disconnect")
+ .text("Disconnected from server. Attempting reconnection...")
+ .appendTo($("#messagebuffer"));
+ scrollChat();
+ },
+
+ errorMsg: function(data) {
+ alert(data.msg);
+ },
+
+ announcement: function(data) {
+ $("#announcements").html("");
+ makeAlert(data.title, data.text)
+ .appendTo($("#announcements"));
+ },
+
+ kick: function(data) {
+ KICKED = true;
+ $("").addClass("server-msg-disconnect")
+ .text("Kicked: " + data.reason)
+ .appendTo($("#messagebuffer"));
+ scrollChat();
+ },
+
+ noflood: function(data) {
+ $("")
+ .addClass("server-msg-disconnect")
+ .text(data.action + ": " + data.msg)
+ .appendTo($("#messagebuffer"));
+ scrollChat();
+ },
+
+ channelNotRegistered: function() {
+ var div = $("").addClass("alert alert-info")
+ .attr("id", "chregnotice")
+ .insertBefore($("#main"));
+ $("").addClass("close pull-right").html("×")
+ .appendTo(div)
+ .click(function() { div.remove(); });
+ $("").text("This channel isn't registered").appendTo(div);
+ $("").addClass("btn btn-primary").text("Register it")
+ .appendTo(div)
+ .click(function() {
+ socket.emit("registerChannel");
+ });
+ },
+
+ registerChannel: function(data) {
+ if(data.success) {
+ $("#chregnotice").remove();
+ }
+ else {
+ makeAlert("Error", data.error, "alert-error")
+ .insertAfter($("#chregnotice"));
+ }
+ },
+
+ unregisterChannel: function(data) {
+ if(data.success) {
+ alert("Channel unregistered");
+ }
+ else {
+ alert(data.error);
+ }
+ },
+
+ setMotd: function(data) {
+ $("#motd").html(data.html);
+ if(data.motd != "")
+ $("#motd").show();
+ else
+ $("#motd").hide();
+ },
+
+ chatFilters: function(entries) {
+ var tbl = $("#filtereditor table");
+ if(tbl.children().length > 1) {
+ $(tbl.children()[1]).remove();
+ }
+ for(var i = 0; i < entries.length; i++) {
+ var f = entries[i];
+ var tr = $("
").appendTo(tbl);
+ var remove = $("").addClass("btn btn-mini btn-danger")
+ .appendTo($(" | ").appendTo(tr));
+ $("").addClass("icon-remove-circle").appendTo(remove);
+ var name = $("
").text(f.name)
+ .appendTo($(" | ").appendTo(tr));
+ var regex = $("
").text(f.source)
+ .appendTo($(" | ").appendTo(tr));
+ var flags = $("
").text(f.flags)
+ .appendTo($(" | ").appendTo(tr));
+ var replace = $("
").text(f.replace)
+ .appendTo($(" | ").appendTo(tr));
+ var activetd = $(" | ").appendTo(tr);
+ var active = $("").attr("type", "checkbox")
+ .prop("checked", f.active).appendTo(activetd);
+
+ var remcallback = (function(filter) { return function() {
+ socket.emit("chatFilter", {
+ cmd: "remove",
+ filter: filter
+ });
+ } })(f);
+ remove.click(remcallback);
+
+ var actcallback = (function(filter) { return function() {
+ // Apparently when you check a checkbox, its value is changed
+ // before this callback. When you uncheck it, its value is not
+ // changed before this callback
+ // [](/amgic)
+ var enabled = active.prop("checked");
+ filter.active = (filter.active == enabled) ? !enabled : enabled;
+ socket.emit("chatFilter", {
+ cmd: "update",
+ filter: filter
+ });
+ } })(f);
+ active.click(actcallback);
+ }
+
+ var newfilt = $("
").appendTo(tbl);
+ $(" | ").appendTo(newfilt);
+ var name = $("").attr("type", "text")
+ .appendTo($(" | ").appendTo(newfilt));
+ var regex = $("").attr("type", "text")
+ .appendTo($(" | ").appendTo(newfilt));
+ var flags = $("").attr("type", "text")
+ .val("g")
+ .appendTo($(" | ").appendTo(newfilt));
+ var replace = $("").attr("type", "text")
+ .appendTo($(" | ").appendTo(newfilt));
+ var add = $("").addClass("btn btn-primary")
+ .text("Add Filter")
+ .appendTo($(" | ").appendTo(newfilt));
+ var cback = (function(name, regex, fg, replace) { return function() {
+ if(regex.val() && replace.val()) {
+ var re = regex.val();
+ var flags = fg.val();
+ try {
+ var dummy = new RegExp(re, flags);
+ }
+ catch(e) {
+ makeAlert("Invalid regex", e+"", "alert-error")
+ .insertAfter($("#filtereditor table"));
+ return;
+ }
+ socket.emit("chatFilter", {
+ cmd: "update",
+ filter: {
+ name: name.val(),
+ source: re,
+ flags: flags,
+ replace: replace.val(),
+ active: true
+ }
+ });
+ }
+ } })(name, regex, flags, replace);
+ add.click(cback);
+ },
+
+ channelOpts: function(opts) {
+ // TODO update if necessary when HTML admin stuff added
+ $("#opt_pagetitle").attr("placeholder", opts.pagetitle);
+ document.title = opts.pagetitle;
+ PAGETITLE = opts.pagetitle;
+ $("#opt_customcss").val(opts.customcss);
+ $("#opt_customjs").val(opts.customjs);
+ $("#opt_chat_antiflood").prop("checked", opts.chat_antiflood);
+ $("#opt_show_public").prop("checked", opts.show_public);
+ $("#opt_enable_link_regex").prop("checked", opts.enable_link_regex);
+ $("#customCss").remove();
+ if(opts.customcss.trim() != "") {
+ $("")
+ .attr("rel", "stylesheet")
+ .attr("href", opts.customcss)
+ .attr("id", "customCss")
+ .appendTo($("head"));
+ }
+ $("#opt_allow_voteskip").prop("checked", opts.allow_voteskip);
+ $("#opt_voteskip_ratio").val(opts.voteskip_ratio);
+ if(opts.customjs.trim() != "") {
+ if(opts.customjs != CHANNEL.opts.customjs) {
+ $.getScript(opts.customjs);
+ }
+ }
+
+ CHANNEL.opts = opts;
+
+ if(opts.allow_voteskip)
+ $("#voteskip").attr("disabled", false);
+ else
+ $("#voteskip").attr("disabled", true);
+ handlePermissionChange();
+ },
+
+ setPermissions: function(perms) {
+ CHANNEL.perms = perms;
+ if(CLIENT.rank >= Rank.Admin)
+ genPermissionsEditor();
+ handlePermissionChange();
+ },
+
+ channelCSSJS: function(data) {
+ $("#chancss").remove();
+ $("#chanjs").remove();
+
+ $("#csstext").val(data.css);
+ $("#jstext").val(data.js);
+
+ if(data.css) {
+ $("").attr("type", "text/css")
+ .attr("id", "chancss")
+ .text(data.css)
+ .appendTo($("head"));
+ }
+
+ if(data.js) {
+ $("").attr("type", "text/javascript")
+ .attr("id", "chanjs")
+ .text(data.js)
+ .appendTo($("body"));
+ }
+ },
+
+ banlist: function(entries) {
+ var tbl = $("#banlist table");
+ if(tbl.children().length > 1) {
+ $(tbl.children()[1]).remove();
+ }
+ for(var i = 0; i < entries.length; i++) {
+ var tr = $("
").appendTo(tbl);
+ var remove = $("").addClass("btn btn-mini btn-danger")
+ .appendTo($(" | ").appendTo(tr));
+ $("").addClass("icon-remove-circle").appendTo(remove);
+ var ip = $(" | ").text(entries[i].ip).appendTo(tr);
+ var name = $(" | ").text(entries[i].name).appendTo(tr);
+ var aliases = $(" | ").text(entries[i].aliases).appendTo(tr);
+ var banner = $(" | ").text(entries[i].banner).appendTo(tr);
+
+ var callback = (function(id, name) { return function() {
+ socket.emit("unban", {
+ id: id,
+ name: name
+ });
+ } })(entries[i].id, entries[i].name);
+ remove.click(callback);
+ }
+ },
+
+ channelRanks: function(entries) {
+ // TODO Edit if necessary
+ entries.sort(function(a, b) {
+ var x = a.name.toLowerCase();
+ var y = b.name.toLowerCase();
+ return y == x ? 0 : (x < y ? -1 : 1);
+ });
+ $("#channelranks").data("entries", entries);
+ var tbl = $("#channelranks table");
+ if(tbl.children().length > 1) {
+ $(tbl.children()[1]).remove();
+ }
+ $("#acl_pagination").remove();
+ if(entries.length > 20) {
+ var pag = $("").addClass("pagination span12")
+ .attr("id", "acl_pagination")
+ .prependTo($("#channelranks"));
+ var btns = $("").appendTo(pag);
+ for(var i = 0; i < entries.length / 20; i++) {
+ var li = $("").appendTo(btns);
+ (function(i) {
+ $("").attr("href", "javascript:void(0)")
+ .text(i+1)
+ .click(function() {
+ loadACLPage(i);
+ })
+ .appendTo(li);
+ })(i);
+ }
+ }
+ loadACLPage(0);
+ },
+
+ setChannelRank: function(data) {
+ var ents = $("#channelranks").data("entries");
+ for(var i = 0; i < ents.length; i++) {
+ if(ents[i].name == data.user) {
+ ents[i].rank = data.rank;
+ break;
+ }
+ }
+ $("#channelranks").data("entries", ents);
+ loadACLPage($("#channelranks").data("page"));
+ },
+
+ voteskip: function(data) {
+ if(data.count > 0) {
+ $("#voteskip").text("Voteskip ("+data.count+"/"+data.need+")");
+ }
+ else {
+ $("#voteskip").text("Voteskip");
+ }
+ },
+
+ /* REGION Rank Stuff */
+
+ rank: function(r) {
+ CLIENT.rank = r;
+ handlePermissionChange();
+ },
+
+ /* should not be relevant since registration is on account.html */
+ register: function(data) {
+ if(data.error) {
+ alert(data.error);
+ }
+ },
+
+ login: function(data) {
+ if(!data.success) {
+ if(data.error != "Invalid session") {
+ alert(data.error);
+ }
+ }
+ else {
+ $("#welcome").text("Logged in as " + data.name);
+ $("#loginform").css("display", "none");
+ $("#logoutform").css("display", "");
+ $("#loggedin").css("display", "");
+ SESSION = data.session || "";
+ CLIENT.name = data.name;
+ CLIENT.logged_in = true;
+ if(SESSION) {
+ createCookie("cytube_uname", CLIENT.name, 7);
+ createCookie("cytube_session", SESSION, 7);
+ }
+ }
+ },
+
+ /* REGION Chat */
+ usercount: function(count) {
+ var text = count + " connected user";
+ if(count != 1) {
+ text += "s";
+ }
+ $("#usercount").text(text);
+ },
+
+ chatMsg: function(data) {
+ addChatMessage(data);
+ },
+
+ clearchat: function() {
+ $("#messagebuffer").html("");
+ },
+
+ userlist: function(data) {
+ $(".userlist_item").each(function() { $(this).remove(); });
+ for(var i = 0; i < data.length; i++) {
+ Callbacks.addUser(data[i]);
+ }
+ },
+
+ addUser: function(data) {
+ var div = $("").attr("class", "userlist_item");
+ var flair = $("").appendTo(div);
+ var nametag = $("").text(data.name).appendTo(div);
+ formatUserlistItem(div, data);
+ addUserDropdown(div, data.name);
+ var users = $("#userlist").children();
+ for(var i = 0; i < users.length; i++) {
+ var othername = users[i].children[1].innerHTML;
+ if(othername.toLowerCase() > data.name.toLowerCase()) {
+ div.insertBefore(users[i]);
+ return;
+ }
+ }
+ div.appendTo($("#userlist"));
+ },
+
+ updateUser: function(data) {
+ if(data.name == CLIENT.name) {
+ CLIENT.leader = data.leader;
+ CLIENT.rank = data.rank;
+ handlePermissionChange();
+ if(CLIENT.leader) {
+ // I'm a leader! Set up sync function
+ if(LEADTMR)
+ clearInterval(LEADTMR);
+ LEADTMR = setInterval(function() {
+ PLAYER.getTime(function(seconds) {
+ socket.emit("mediaUpdate", {
+ id: PLAYER.id,
+ currentTime: seconds,
+ paused: PLAYER.paused,
+ type: PLAYER.type
+ });
+ });
+ }, 5000);
+ }
+ // I'm not a leader. Don't send syncs to the server
+ else {
+ if(LEADTMR)
+ clearInterval(LEADTMR);
+ LEADTMR = false;
+ }
+
+ }
+ var users = $("#userlist").children();
+ for(var i = 0; i < users.length; i++) {
+ var name = users[i].children[1].innerHTML;
+ // Reformat user
+ if(name == data.name) {
+ formatUserlistItem($(users[i]), data);
+ }
+ }
+
+ },
+
+ userLeave: function(data) {
+ var users = $("#userlist").children();
+ for(var i = 0; i < users.length; i++) {
+ var name = users[i].children[1].innerHTML;
+ if(name == data.name) {
+ $(users[i]).remove();
+ // Note: no break statement here because allowing
+ // the loop to continue means a free cleanup if something
+ // goes wrong and there's a duplicate name
+ }
+ }
+ },
+
+ drinkCount: function(data) {
+ if(data.count != 0) {
+ var text = data.count + " drink";
+ if(data.count != 1) {
+ text += "s";
+ }
+ $("#drinkcount").text(text);
+ $("#drinkbar").show();
+ }
+ else {
+ $("#drinkbar").hide();
+ }
+ },
+
+ /* REGION Playlist Stuff */
+ playlist: function(data) {
+ // Clear the playlist first
+ var q = $("#queue");
+ q.html("");
+
+
+ for(var i = 0; i < data.length; i++) {
+ Callbacks.queue({
+ media: data[i],
+ pos: q.children().length
+ });
+ }
+ },
+
+ setPlaylistMeta: function(data) {
+ var c = data.count + " item";
+ if(data.count != 1)
+ c += "s";
+ $("#plcount").text(c);
+ $("#pllength").text(data.time);
+ },
+
+ queue: function(data) {
+ var li = makeQueueEntry(data.media);
+ li.hide();
+ addQueueButtons(li);
+ var idx = data.pos;
+ var q = $("#queue");
+ li.attr("title", data.media.queueby
+ ? ("Added by: " + data.media.queueby)
+ : "Added by: Unknown");
+ if(idx < q.children().length - 1)
+ li.insertBefore(q.children()[idx])
+ else
+ li.appendTo(q);
+ li.show("blind");
+ },
+
+ queueFail: function(data) {
+ if(!data) {
+ data = "Queue failed. Check your link to make sure it is valid.";
+ }
+ makeAlert("Error", data, "alert-error")
+ .insertAfter($("#mediaurl").parent());
+ },
+
+ setTemp: function(data) {
+ var li = $("#queue").children()[data.position];
+ li = $(li);
+ if(data.temp)
+ li.addClass("queue_temp");
+ else
+ li.removeClass("queue_temp");
+ var btn = li.find(".qbtn-tmp");
+ btn.data("temp", data.temp);
+ if(data.temp) {
+ btn.html(btn.html().replace("Make Temporary",
+ "Make Permanent"));
+ }
+ else {
+ btn.html(btn.html().replace("Make Permanent",
+ "Make Temporary"));
+ }
+ },
+
+ "delete": function(data) {
+ var li = $("#queue").children()[data.position];
+ $(li).remove();
+ },
+
+ moveVideo: function(data) {
+ playlistMove(data.src, data.dest);
+ },
+
+ setPosition: function(data) {
+ $("#queue li").each(function() {
+ $(this).removeClass("queue_active");
+ });
+ if(data.position < 0)
+ return;
+ POSITION = data.position;
+ var linew = $("#queue").children()[POSITION];
+ $(linew).addClass("queue_active");
+
+ $("#queue").scrollTop(0);
+ var scroll = $(linew).position().top - $("#queue").position().top;
+ $("#queue").scrollTop(scroll);
+
+ if(CHANNEL.opts.allow_voteskip)
+ $("#voteskip").attr("disabled", false);
+ },
+
+ changeMedia: function(data) {
+ $("#currenttitle").text("Currently Playing: " + data.title);
+ if(data.type != "sc" && PLAYER.type == "sc")
+ // [](/goddamnitmango)
+ fixSoundcloudShit();
+ if(data.type != "jw" && PLAYER.type == "jw") {
+ // Is it so hard to not mess up my DOM?
+ $("").attr("id", "ytapiplayer")
+ .insertBefore($("#ytapiplayer_wrapper"));
+ $("#ytapiplayer_wrapper").remove();
+ }
+ if(data.type != PLAYER.type) {
+ PLAYER = new Player(data);
+ }
+ if(PLAYER.update) {
+ PLAYER.update(data);
+ }
+ },
+
+ mediaUpdate: function(data) {
+ if(PLAYER.update) {
+ PLAYER.update(data);
+ }
+ },
+
+ setPlaylistLocked: function(data) {
+ CHANNEL.openqueue = !data.locked;
+ // TODO handlePermissionsChange?
+ if(CHANNEL.openqueue) {
+ $("#playlist_controls").css("display", "");
+ if(RANK < Rank.Moderator) {
+ $("#qlockbtn").css("display", "none");
+ rebuildPlaylist();
+ if(!CHANNELOPTS.qopen_allow_qnext)
+ $("#queue_next").attr("disabled", true);
+ if(!CHANNELOPTS.qopen_allow_playnext)
+ $("#play_next").attr("disabled", true);
+ }
+ }
+ else if(RANK < Rank.Moderator && !LEADER) {
+ $("#playlist_controls").css("display", "none");
+ rebuildPlaylist();
+ }
+ if(CHANNEL.openqueue) {
+ $("#qlockbtn").removeClass("btn-danger")
+ .addClass("btn-success")
+ .text("Lock Playlist");
+ }
+ else {
+ $("#qlockbtn").removeClass("btn-success")
+ .addClass("btn-danger")
+ .text("Unlock Playlist");
+ }
+ },
+
+ searchResults: function(data) {
+ clearSearchResults();
+ $("#library").data("entries", data.results);
+ if(data.results.length > 100) {
+ var pag = $("").addClass("pagination")
+ .attr("id", "search_pagination")
+ .insertAfter($("#library"));
+ var btns = $("").appendTo(pag);
+ for(var i = 0; i < data.results.length / 100; i++) {
+ var li = $("").appendTo(btns);
+ (function(i) {
+ $("").attr("href", "javascript:void(0)")
+ .text(i+1)
+ .click(function() {
+ loadSearchPage(i);
+ })
+ .appendTo(li);
+ })(i);
+ }
+ }
+ loadSearchPage(0);
+ },
+
+ /* REGION Polls */
+ newPoll: function(data) {
+ Callbacks.closePoll();
+ var pollMsg = $("").addClass("poll-notify")
+ .text(data.initiator + " opened a poll: \"" + data.title + "\"")
+ .appendTo($("#messagebuffer"));
+ scrollChat();
+
+ var poll = $("").addClass("well active").prependTo($("#pollcontainer"));
+ $("").addClass("close pull-right").html("×")
+ .appendTo(poll)
+ .click(function() { poll.remove(); });
+ if(hasPermission("pollctl")) {
+ $("").addClass("btn btn-danger pull-right").text("End Poll")
+ .appendTo(poll)
+ .click(function() {
+ socket.emit("closePoll")
+ });
+ }
+
+ $("").text(data.title).appendTo(poll);
+ for(var i = 0; i < data.options.length; i++) {
+ (function(i) {
+ var callback = function() {
+ socket.emit("vote", {
+ option: i
+ });
+ poll.find(".option button").each(function() {
+ $(this).attr("disabled", "disabled");
+ });
+ }
+ $("").addClass("btn").text(data.counts[i])
+ .prependTo($("").addClass("option").text(data.options[i])
+ .appendTo(poll))
+ .click(callback);
+ })(i);
+
+ }
+
+ poll.find(".btn").attr("disabled", !hasPermission("pollvote"));
+ },
+
+ updatePoll: function(data) {
+ var poll = $("#pollcontainer .active");
+ var i = 0;
+ poll.find(".option button").each(function() {
+ $(this).text(data.counts[i]);
+ i++;
+ });
+ },
+
+ closePoll: function() {
+ if($("#pollcontainer .active").length != 0) {
+ var poll = $("#pollcontainer .active");
+ poll.removeClass("active").addClass("muted");
+ poll.find(".option button").each(function() {
+ $(this).attr("disabled", true);
+ });
+ poll.find(".btn-danger").each(function() {
+ $(this).remove()
+ });
+ }
+ },
+
+ savePlaylist: function(data) {
+ if(data.success) {
+ makeAlert("Success", "Playlist saved.", "alert-success");
+ }
+ else {
+ makeAlert("Error", data.error, "alert-error")
+ .addClass("span12")
+ .insertBefore($("#userpl_list"));
+ }
+ },
+
+ listPlaylists: function(data) {
+ if(data.error) {
+ makeAlert("Error", data.error, "alert-error")
+ .addClass("span12")
+ .insertBefore($("#userpl_list"));
+ }
+ else {
+ var pls = data.pllist;
+ pls.sort(function(a, b) {
+ var x = a.name.toLowerCase();
+ var y = b.name.toLowerCase();
+ if(x < y) return -1;
+ if(x > y) return 1;
+ return 0;
+ });
+ $("#userpl_list").html("");
+ for(var i = 0; i < pls.length; i++) {
+ var li = $("").appendTo($("#userpl_list"))
+ .addClass("well");
+ li.data("pl-name", pls[i].name);
+ $("").text(pls[i].name).appendTo(li)
+ .css("float", "left")
+ .css("margin-left", "1em");
+ var metastr = pls[i].count + " item";
+ if(pls[i].count != 1) {
+ metastr += "s";
+ }
+ metastr +=", playtime " + pls[i].time;
+ $("").text(metastr)
+ .css("float", "right")
+ .appendTo(li);
+ var bg = $("").addClass("btn-group")
+ .css("float", "left")
+ .prependTo(li);
+ var del = $("")
+ .addClass("btn btn-mini btn-danger")
+ .prependTo(bg);
+ $("").addClass("icon-trash").appendTo(del);
+ (function(li) {
+ del.click(function() {
+ socket.emit("deletePlaylist", {
+ name: li.data("pl-name")
+ });
+ });
+ })(li);
+ if(hasPermission("playlistaddlist")) {
+ (function(li) {
+ $("").addClass("btn btn-mini")
+ .text("End")
+ .prependTo(bg)
+ .click(function() {
+ socket.emit("queuePlaylist", {
+ name: li.data("pl-name"),
+ pos: "end"
+ });
+ });
+ })(li);
+
+ if(hasPermission("playlistnext")) {
+ (function(li) {
+ $("").addClass("btn btn-mini")
+ .text("Next")
+ .prependTo(bg)
+ .click(function() {
+ socket.emit("queuePlaylist", {
+ name: li.data("pl-name"),
+ pos: "next"
+ });
+ });
+ })(li);
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+$.getScript(IO_URL+"/socket.io/socket.io.js", function() {
+ try {
+ socket = io.connect(IO_URL);
+ for(var key in Callbacks) {
+ socket.on(key, Callbacks[key]);
+ }
+ }
+ catch(e) {
+ Callbacks.disconnect();
+ }
+});
+*/
+
+setupCallbacks = function() {
+ for(var key in Callbacks) {
+ (function(key) {
+ socket.on(key, function() {
+ Callbacks[key]();
+ });
+ })(key);
+ }
+}
diff --git a/www/assets/js/data.js b/www/assets/js/data.js
index 29a28794..6cd8402a 100644
--- a/www/assets/js/data.js
+++ b/www/assets/js/data.js
@@ -1,103 +1,108 @@
-var CLIENT = {
- rank: -1,
- leader: false,
- name: "",
- logged_in: false,
- profile: {
- image: "",
- text: ""
- }
-};
-
-var CHANNEL = {
- opts: {},
- openqueue: false,
- perms: {},
- name: false // TODO load name from URL
-};
-
-var PLAYER = false;
-var VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");
-var VHEIGHT = ""+parseInt(parseInt(VWIDTH) * 9 / 16);
-var POSITION = -1;
-var socket;
-var IGNORED = [];
-var CHATHIST = [];
-var CHATHISTIDX = 0;
-var SCROLLCHAT = true;
-var LASTCHATNAME = "";
-var LASTCHATTIME = 0;
-var FOCUSED = true;
-var PAGETITLE = "CyTube";
-var TITLE_BLINK;
-var KICKED = false;
-var NAME = readCookie("cytube_uname");
-var SESSION = readCookie("cytube_session");
-var LEADTMR = false;
-
-function getOrDefault(k, def) {
- var v = localStorage.getItem(k);
- if(v === null)
- return def;
- if(v === "true")
- return true;
- if(v === "false")
- return false;
- if(v.match(/[0-9]+/))
- return parseInt(v);
- if(v.match(/[0-9\.]+/))
- return parseFloat(v);
- return v;
-}
-
-var USEROPTS = {
- theme : getOrDefault("theme", "default"),
- css : getOrDefault("css", ""),
- layout : getOrDefault("layout", "default"),
- synch : getOrDefault("synch", true),
- hidevid : getOrDefault("hidevid", false),
- show_timestamps : getOrDefault("show_timestamps", true),
- modhat : getOrDefault("modhat", false),
- blink_title : getOrDefault("blink_title", false),
- sync_accuracy : getOrDefault("sync_accuracy", 2),
- chatbtn : getOrDefault("chatbtn", false),
- altsocket : getOrDefault("altsocket", false)
-};
-
-var Rank = {
- Guest: 0,
- Member: 1,
- Leader: 1.5,
- Moderator: 2,
- Admin: 3,
- Owner: 10,
- Siteadmin: 255
-};
-
-function createCookie(name,value,days) {
- if (days) {
- var date = new Date();
- date.setTime(date.getTime()+(days*24*60*60*1000));
- var expires = "; expires="+date.toGMTString();
- }
- else var expires = "";
- document.cookie = name+"="+value+expires+"; path=/";
-}
-
-function readCookie(name) {
- var nameEQ = name + "=";
- var ca = document.cookie.split(";");
- for(var i=0;i < ca.length;i++) {
- var c = ca[i];
- while (c.charAt(0)==" ") c = c.substring(1,c.length);
- if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
- }
- return null;
-}
-
-function eraseCookie(name) {
- createCookie(name,"",-1);
-}
-
-/* to be implemented in callbacks.js */
-function setupCallbacks() { }
+var CLIENT = {
+ rank: -1,
+ leader: false,
+ name: "",
+ logged_in: false,
+ profile: {
+ image: "",
+ text: ""
+ }
+};
+
+var CHANNEL = {
+ opts: {},
+ openqueue: false,
+ perms: {},
+ name: false // TODO load name from URL
+};
+
+var PLAYER = false;
+var VWIDTH = $("#ytapiplayer").parent().css("width").replace("px", "");
+var VHEIGHT = ""+parseInt(parseInt(VWIDTH) * 9 / 16);
+var POSITION = -1;
+var socket = {
+ emit: function() {
+ console.log("socket not initialized");
+ console.log(arguments);
+ }
+};
+var IGNORED = [];
+var CHATHIST = [];
+var CHATHISTIDX = 0;
+var SCROLLCHAT = true;
+var LASTCHATNAME = "";
+var LASTCHATTIME = 0;
+var FOCUSED = true;
+var PAGETITLE = "CyTube";
+var TITLE_BLINK;
+var KICKED = false;
+var NAME = readCookie("cytube_uname");
+var SESSION = readCookie("cytube_session");
+var LEADTMR = false;
+
+function getOrDefault(k, def) {
+ var v = localStorage.getItem(k);
+ if(v === null)
+ return def;
+ if(v === "true")
+ return true;
+ if(v === "false")
+ return false;
+ if(v.match(/[0-9]+/))
+ return parseInt(v);
+ if(v.match(/[0-9\.]+/))
+ return parseFloat(v);
+ return v;
+}
+
+var USEROPTS = {
+ theme : getOrDefault("theme", "default"),
+ css : getOrDefault("css", ""),
+ layout : getOrDefault("layout", "default"),
+ synch : getOrDefault("synch", true),
+ hidevid : getOrDefault("hidevid", false),
+ show_timestamps : getOrDefault("show_timestamps", true),
+ modhat : getOrDefault("modhat", false),
+ blink_title : getOrDefault("blink_title", false),
+ sync_accuracy : getOrDefault("sync_accuracy", 2),
+ chatbtn : getOrDefault("chatbtn", false),
+ altsocket : getOrDefault("altsocket", false)
+};
+
+var Rank = {
+ Guest: 0,
+ Member: 1,
+ Leader: 1.5,
+ Moderator: 2,
+ Admin: 3,
+ Owner: 10,
+ Siteadmin: 255
+};
+
+function createCookie(name,value,days) {
+ if (days) {
+ var date = new Date();
+ date.setTime(date.getTime()+(days*24*60*60*1000));
+ var expires = "; expires="+date.toGMTString();
+ }
+ else var expires = "";
+ document.cookie = name+"="+value+expires+"; path=/";
+}
+
+function readCookie(name) {
+ var nameEQ = name + "=";
+ var ca = document.cookie.split(";");
+ for(var i=0;i < ca.length;i++) {
+ var c = ca[i];
+ while (c.charAt(0)==" ") c = c.substring(1,c.length);
+ if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
+ }
+ return null;
+}
+
+function eraseCookie(name) {
+ createCookie(name,"",-1);
+}
+
+/* to be implemented in callbacks.js */
+function setupCallbacks() { }
diff --git a/www/assets/js/util.js b/www/assets/js/util.js
index 5446ef3c..d8484112 100644
--- a/www/assets/js/util.js
+++ b/www/assets/js/util.js
@@ -1,720 +1,750 @@
-function makeAlert(title, text, klass) {
- if(!klass) {
- klass = "alert-info";
- }
-
- var al = $("").addClass("alert")
- .addClass(klass)
- .text(text);
- $("
").prependTo(al);
- $("").text(title).prependTo(al);
- $("").addClass("close pull-right").html("×")
- .click(function() {
- al.hide("blind", function() {
- al.remove();
- });
- })
- .prependTo(al);
- return al;
-}
-
-function formatUserlistItem(div, data) {
- var name = $(div.children[1]);
- name.removeClass();
- name.css("font-style", "");
- name.addClass(getNameColor(data.rank));
- div.find(".profile-box").remove();
-
- // TODO might remove this
- var profile;
- name.mouseenter(function(ev) {
- profile = $("")
- .addClass("profile-box")
- .css("top", (ev.pageY + 5) + "px")
- .css("left", ev.pageX + "px")
- .appendTo(div);
- if(data.profile.image) {
- $("").addClass("profile-image")
- .attr("src", data.profile.image)
- .appendTo(profile);
- }
- $("").text(data.name).appendTo(profile);
- $("").text(data.profile.text).appendTo(profile);
- });
- name.mousemove(function(ev) {
- profile.css("top", (ev.pageY + 5) + "px")
- .css("left", ev.pageX + "px")
- });
- name.mouseleave(function() {
- profile.remove();
- });
-
- var flair = div.children[0];
- flair.innerHTML = "";
- // denote current leader with a star
- if(data.leader) {
- $("").addClass("icon-star-empty").appendTo(flair);
- }
- if(data.meta && data.meta.afk) {
- name.css("font-style", "italic");
- $("").addClass("icon-time").appendTo(flair);
- }
-}
-
-function getNameColor(rank) {
- if(rank >= Rank.Siteadmin)
- return "userlist_siteadmin";
- else if(rank >= Rank.Owner)
- return "userlist_owner";
- else if(rank >= Rank.Moderator)
- return "userlist_op";
- else if(rank == Rank.Guest)
- return "userlist_guest";
- else
- return "";
-}
-
-function addUserDropdown(entry, name) {
- // TODO change this
- entry.find(".dropdown").remove();
- entry.unbind();
- var div = $("").addClass("dropdown").appendTo(entry);
- var ul = $("").addClass("dropdown-menu").appendTo(div);
- ul.attr("role", "menu");
- ul.attr("aria-labelledby", "dropdownMenu");
-
- var ignore = $("").appendTo(ul);
- var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(ignore);
- if(IGNORED.indexOf(name) != -1) {
- a.text("Unignore User");
- }
- else {
- a.text("Ignore User");
- }
- a.click(function() {
- if(IGNORED.indexOf(name) != -1) {
- IGNORED.splice(IGNORED.indexOf(name), 1);
- this.text("Ignore User");
- }
- else {
- IGNORED.push(name);
- this.text("Unignore User");
- }
- }.bind(a));
-
- if(hasPermission("kick")) {
- var kick = $("").appendTo(ul);
- var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(kick);
- a.text("Kick");
- a.click(function() {
- socket.emit("chatMsg", {
- msg: "/kick " + name
- });
- });
- }
-
- if(CLIENT.rank >= Rank.Moderator) {
- $("").addClass("divider").appendTo(ul);
-
- var makeLeader = $("").appendTo(ul);
- var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(makeLeader);
- a.text("Make Leader");
- a.click(function() {
- socket.emit("assignLeader", {
- name: name
- });
- });
-
- var takeLeader = $("").appendTo(ul);
- var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(takeLeader);
- a.text("Take Leader");
- a.click(function() {
- socket.emit("assignLeader", {
- name: ""
- });
- });
-
- var ban = $("").appendTo(ul);
- var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(ban);
- a.text("IP Ban");
- a.click(function() {
- socket.emit("chatMsg", {
- msg: "/ban " + name
- });
- });
-
- var nameban = $("").appendTo(ul);
- var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(nameban);
- a.text("Name Ban");
- a.click(function() {
- socket.emit("banName", {
- name: name
- });
- });
-
- $("").addClass("divider").appendTo(ul);
-
- var promote = $("").appendTo(ul);
- var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(promote);
- a.text("Promote");
- a.click(function() {
- socket.emit("promote", {
- name: name
- });
- });
-
- var demote = $("").appendTo(ul);
- var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(demote);
- a.text("Demote");
- a.click(function() {
- socket.emit("demote", {
- name: name
- });
- });
- }
-
- entry.click(function() {
- if(ul.css("display") == "none") {
- // Hide others
- $("#userlist ul.dropdown-menu").each(function() {
- if(this != ul) {
- $(this).css("display", "none");
- }
- });
- ul.css("display", "block");
- }
- else {
- ul.css("display", "none");
- }
- });
-
- return ul;
-}
-
-/* queue stuff */
-
-function makeQueueEntry(video) {
- var li = $("");
- li.addClass("queue_entry");
- li.data("media", video);
- if(video.thumb) {
- $("").attr("src", video.thumb.url)
- .css("float", "left")
- .css("clear", "both")
- .appendTo(li);
- }
- var title = $("").addClass("qe_title").appendTo(li)
- .text(video.title)
- .attr("href", "#")//formatURL(video))
- .attr("target", "_blank");
- var time = $("").addClass("qe_time").appendTo(li);
- time.text(video.duration);
- var clear = $("").addClass("qe_clear").appendTo(li);
- if(video.temp) {
- li.addClass("queue_temp");
- }
-
- // Add dropdown
- // class="dropdown dropup" lolwut
- var dd = $("").addClass("dropdown dropup").appendTo(li);
- var menu = $("").addClass("dropdown-menu")
- .attr("role", "menu")
- .appendTo(dd);
- var del = $("").appendTo($("").appendTo(menu))
- .attr("href", "javascript:void(0)")
- .attr("tabindex", "-1")
- .click(function() {
- })
- .text("Remove");
- $("").addClass("icon-trash").prependTo(del);
-
- li.contextmenu(function(ev) {
- ev.preventDefault();
- if(menu.css("display") == "none")
- menu.show();
- else
- menu.hide();
- return false;
- });
-
- menu.blur(function() {
- menu.hide();
- });
- return li;
-}
-
-function addQueueButtons(li) {
-
-}
-
-function rebuildPlaylist() {
- $("#queue li").each(function() {
- $(this).find(".btn-group").remove();
- addQueueButtons(this);
- });
-}
-
-/* menus */
-function showOptionsMenu() {
- PLAYER.hide();
- var modal = $("").addClass("modal hide fade")
- .appendTo($("body"));
- var head = $("").addClass("modal-header")
- .appendTo(modal);
- $("").addClass("close")
- .attr("data-dismiss", "modal")
- .attr("aria-hidden", "true")
- .appendTo(head)[0].innerHTML = "×";
- $("").text("User Options").appendTo(head);
- var body = $("").addClass("modal-body").appendTo(modal);
- var form = $("").addClass("form-horizontal")
- .appendTo(body);
-
- function addOption(lbl, thing) {
- var g = $("").addClass("control-group").appendTo(form);
- $("").addClass("control-label").text(lbl).appendTo(g);
- var c = $("").addClass("controls").appendTo(g);
- thing.appendTo(c);
- }
-
- var themeselect = $("");
- $("").attr("value", "default").text("Default").appendTo(themeselect);
- $("").attr("value", "assets/css/darkstrap.css").text("Dark").appendTo(themeselect);
- themeselect.val(USEROPTS.theme);
- addOption("Theme", themeselect);
-
- var usercss = $("").attr("type", "text")
- .attr("placeholder", "Stylesheet URL");
- usercss.val(USEROPTS.css);
- addOption("User CSS", usercss);
-
- var layoutselect = $("");
- $("").attr("value", "default").text("Default")
- .appendTo(layoutselect);
- $("").attr("value", "large").text("Large")
- .appendTo(layoutselect);
- $("").attr("value", "huge").text("Huge")
- .appendTo(layoutselect);
- $("").attr("value", "single").text("Single Column")
- .appendTo(layoutselect);
- $("").attr("value", "synchtube").text("Synchtube")
- .appendTo(layoutselect);
- $("").attr("value", "fluid").text("Fluid")
- .appendTo(layoutselect);
- layoutselect.val(USEROPTS.layout);
- addOption("Layout", layoutselect);
- var warn = $("").addClass("text-error")
- .text("Changing layouts may require a refresh")
- addOption("", warn);
- $("
").appendTo(form);
-
- var synchcontainer = $("").addClass("checkbox")
- .text("Synchronize Media");
- var synch = $("").attr("type", "checkbox").appendTo(synchcontainer);
- synch.prop("checked", USEROPTS.synch);
- addOption("Synch", synchcontainer);
-
- var syncacc = $("").attr("type", "text")
- .attr("placeholder", "Seconds");
- syncacc.val(USEROPTS.sync_accuracy);
- addOption("Synch Accuracy", syncacc);
-
- var vidcontainer = $("").addClass("checkbox")
- .text("Hide Video");
- var hidevid = $("").attr("type", "checkbox").appendTo(vidcontainer);
- hidevid.prop("checked", USEROPTS.hidevid);
- addOption("Hide Video", vidcontainer);
- $("
").appendTo(form);
-
- var tscontainer = $("").addClass("checkbox")
- .text("Show timestamps in chat");
- var showts = $("").attr("type", "checkbox").appendTo(tscontainer);
- showts.prop("checked", USEROPTS.show_timestamps);
- addOption("Show timestamps", tscontainer);
-
- var blinkcontainer = $("").addClass("checkbox")
- .text("Flash title on every incoming message");
- var blink = $("").attr("type", "checkbox").appendTo(blinkcontainer);
- blink.prop("checked", USEROPTS.blink_title);
- addOption("Chat Notice", blinkcontainer);
-
- var sendbtncontainer = $("").addClass("checkbox")
- .text("Add a send button to the chatbox");
- var sendbtn = $("").attr("type", "checkbox").appendTo(sendbtncontainer);
- sendbtn.prop("checked", USEROPTS.chatbtn);
- addOption("Send Button", sendbtncontainer);
-
- var altsocketcontainer = $("").addClass("checkbox")
- .text("Use alternative socket connection");
- var altsocket = $("").attr("type", "checkbox")
- .appendTo(altsocketcontainer);
- altsocket.prop("checked", USEROPTS.altsocket);
- addOption("Alternate Socket", altsocketcontainer);
-
- var profile = $("").attr("target", "_blank")
- .addClass("btn")
- .attr("href", "./account.html")
- .text("Profile has moved to the account page");
- addOption("Profile", profile);
-
- if(RANK >= Rank.Moderator) {
- $("
").appendTo(form);
- var modhatcontainer = $("").addClass("checkbox")
- .text("Show name color");
- var modhat = $("").attr("type", "checkbox").appendTo(modhatcontainer);
- modhat.prop("checked", USEROPTS.modhat);
- addOption("Modflair", modhatcontainer);
- }
-
- var footer = $("").addClass("modal-footer").appendTo(modal);
- var submit = $("").addClass("btn btn-primary pull-right")
- .text("Save")
- .appendTo(footer);
-
- submit.click(function() {
- USEROPTS.theme = themeselect.val();
- USEROPTS.css = usercss.val();
- USEROPTS.layout = layoutselect.val();
- USEROPTS.synch = synch.prop("checked");
- USEROPTS.sync_accuracy = parseFloat(syncacc.val()) || 2;
- USEROPTS.hidevid = hidevid.prop("checked");
- USEROPTS.show_timestamps = showts.prop("checked");
- USEROPTS.blink_title = blink.prop("checked");
- USEROPTS.chatbtn = sendbtn.prop("checked");
- USEROPTS.altsocket = altsocket.prop("checked");
- if(RANK >= Rank.Moderator) {
- USEROPTS.modhat = modhat.prop("checked");
- }
- saveOpts();
- modal.modal("hide");
- });
-
- modal.on("hidden", function() {
- PLAYER.unhide();
- applyOpts();
- modal.remove();
- });
- modal.modal();
-}
-
-function saveOpts() {
- for(var key in USEROPTS) {
- localStorage.setItem(key, USEROPTS[key]);
- }
-}
-
-function applyOpts() {
- $("#usertheme").remove();
- if(USEROPTS.theme != "default") {
- $("").attr("rel", "stylesheet")
- .attr("type", "text/css")
- .attr("id", "usertheme")
- .attr("href", USEROPTS.theme)
- .appendTo($("head"));
- }
-
- $("#usercss").remove();
- if(USEROPTS.css) {
- $("").attr("rel", "stylesheet")
- .attr("type", "text/css")
- .attr("id", "usercss")
- .attr("href", USEROPTS.css)
- .appendTo($("head"));
- }
-
- switch(USEROPTS.layout) {
- case "large":
- largeLayout();
- break;
- case "huge":
- hugeLayout();
- break;
- case "single":
- singleColumnLayout();
- break;
- case "synchtube":
- synchtubeLayout();
- break;
- case "fluid":
- fluidLayout();
- break;
- default:
- break;
- }
-
- if(USEROPTS.hidevid) {
- $("#videowrap").remove();
- }
-
- $("#chatbtn").remove();
- if(USEROPTS.chatbtn) {
- var btn = $("").addClass("btn btn-block")
- .text("Send")
- .attr("id", "chatbtn")
- .appendTo($("#chatwrap"));
- btn.click(function() {
- if($("#chatline").val().trim()) {
- socket.emit("chatMsg", {
- msg: $("#chatline").val()
- });
- $("#chatline").val("");
- }
- });
- }
-
- if(USEROPTS.altsocket) {
- if(socket)
- socket.disconnect();
- socket = new NotWebsocket();
- setupCallbacks();
- }
- // Switch from NotWebsocket => Socket.io
- else if(socket && typeof socket.poll !== "undefined") {
- try {
- socket = io.connect(IO_URL);
- setupCallbacks();
- }
- catch(e) {
- }
- }
-}
-
-function showLoginMenu() {
- PLAYER.hide();
- var modal = $("").addClass("modal hide fade")
- .appendTo($("body"));
- var head = $("").addClass("modal-header")
- .appendTo(modal);
- $("").addClass("close")
- .attr("data-dismiss", "modal")
- .attr("aria-hidden", "true")
- .appendTo(head)
- .html("×");
- $("").text("Login").appendTo(head);
- var body = $("").addClass("modal-body").appendTo(modal);
- var frame = $("")
- .attr("id", "loginframe")
- .attr("src", "login.html")
- .css("border", "none")
- .css("width", "100%")
- .css("height", "300px")
- .css("margin", "0")
- .appendTo(body);
- var timer = setInterval(function() {
- frame[0].contentWindow.postMessage("cytube-syn", document.location);
- }, 1000);
- var respond = function(e) {
- if(e.data == "cytube-ack") {
- clearInterval(timer);
- }
- if(e.data.indexOf(":") == -1) {
- return;
- }
- if(e.data.substring(0, e.data.indexOf(":")) == "cytube-login") {
- var data = e.data.substring(e.data.indexOf(":")+1);
- data = JSON.parse(data);
- if(data.error) {
- // Since this is the login page, invalid session implies bad credentials
- if(data.error == "Invalid session") {
- alert("Invalid username/password");
- }
- else {
- alert(data.error);
- }
- }
- else if(data.success) {
- SESSION = data.session || "";
- CLIENT.name = data.uname || "";
- socket.emit("login", {
- name: CLIENT.name,
- session: SESSION
- });
- if(window.removeEventListener) {
- window.removeEventListener("message", respond, false);
- }
- else if(window.detachEvent) {
- // If an IE dev ever reads this, please tell your company
- // to get their shit together
- window.detachEvent("onmessage", respond);
- }
- modal.modal("hide");
- }
- }
- }
- if(window.addEventListener) {
- window.addEventListener("message", respond, false);
- }
- else if(window.attachEvent) {
- // If an IE dev ever reads this, please tell your company to get
- // their shit together
- window.attachEvent("onmessage", respond);
- }
- var footer = $("").addClass("modal-footer").appendTo(modal);
- modal.on("hidden", function() {
- PLAYER.unhide();
- modal.remove();
- });
- modal.modal();
-}
-
-function showPollMenu() {
- $("#pollwrap .poll-menu").remove();
- var menu = $("").addClass("well poll-menu")
- .insertAfter($("#newpollbtn"));
-
- $("").addClass("btn btn-danger pull-right")
- .text("Cancel")
- .appendTo(menu)
- .click(function() {
- menu.remove();
- });
-
- $("").text("Title").appendTo(menu);
- $("
").appendTo(menu);
-
- var title = $("").attr("type", "text")
- .appendTo(menu);
- $("
").appendTo(menu);
-
- $("").text("Options").appendTo(menu);
- $("
").appendTo(menu);
-
- var addbtn = $("").addClass("btn")
- .text("Add Option")
- .appendTo(menu);
- $("
").appendTo(menu);
-
- function addOption() {
- $("").attr("type", "text")
- .addClass("poll-menu-option")
- .insertBefore(addbtn);
- $("
").insertBefore(addbtn);
- }
-
- addbtn.click(addOption);
- addOption();
- addOption();
-
- $("
").appendTo(menu);
- $("").addClass("btn")
- .text("Open Poll")
- .addClass("btn-block")
- .appendTo(menu)
- .click(function() {
- var opts = []
- menu.find(".poll-menu-option").each(function() {
- if($(this).val() != "")
- opts.push($(this).val());
- });
- socket.emit("newPoll", {
- title: title.val(),
- opts: opts
- });
- });
-}
-
-function scrollChat() {
- // TODO add check
- $("#messagebuffer").scrollTop($("#messagebuffer").prop("scrollheight"));
-}
-
-function hasPermission(key) {
- if(key.indexOf("playlist") == 0 && CHANNEL.openqueue) {
- var key2 = "o" + key;
- var v = CHANNEL.perms[key2];
- if(typeof v == "number" && CLIENT.rank >= v) {
- return true;
- }
- }
- var v = CHANNEL.perms[key];
- if(typeof v != "number") {
- return false;
- }
- return CLIENT.rank >= v;
-}
-
-function handlePermissionChange() {
- function setVisible(selector, bool) {
- var disp = bool ? "" : "none";
- $(selector).css("display", disp);
- }
-
- if(CLIENT.rank < 2) {
- $(".modonly").hide();
- }
-
- setVisible("#userpltoggle", CLIENT.rank >= 1);
-
- setVisible("#playlisttoggle", hasPermission("playlistadd"));
- $("#queue_next").attr("disabled", !hasPermission("playlistnext"));
- setVisible("#qlockbtn", CLIENT.rank >= 2);
-
- setVisible("#getplaylist", hasPermission("playlistgeturl"));
- setVisible("#clearplaylist", hasPermission("playlistclear"));
- setVisible("#shuffleplaylist", hasPermission("playlistshuffle"));
-
- setVisible("#modnav", CLIENT.rank >= 2);
- setVisible("#chanperms_tab", CLIENT.rank >= 3);
- setVisible("#banlist_tab", hasPermission("ban"));
- setVisible("#motdeditor_tab", hasPermission("motdedit"));
- setVisible("#csseditor_tab", CLIENT.rank >= 3);
- setVisible("#jseditor_tab", CLIENT.rank >= 3);
- setVisible("#filtereditor_tab", hasPermission("filteredit"));
- setVisible("#acl_tab", CLIENT.rank >= 3);
- setVisible("#dropchannel_tab", CLIENT.rank >= 10);
-
- setVisible("#newpollbtn", hasPermission("pollctl"));
-
- $("#pollcontainer .active").find(".btn-danger").remove();
- if(hasPermission("pollctl")) {
- var poll = $("#pollcontainer .active");
- if(poll.length > 0) {
- $("").addClass("btn btn-danger pull-right")
- .text("End Poll")
- .insertAfter(poll.find(".close"))
- .click(function() {
- socket.emit("closePoll");
- });
- }
- }
- var poll = $("#pollcontainer .active");
- if(poll.length > 0) {
- poll.find(".btn").attr("disabled", !hasPermission("pollvote"));
- }
- var users = $("#userlist").children();
- for(var i = 0; i < users.length; i++) {
- addUserDropdown($(users[i]), users[i].children[1].innerHTML);
- }
- rebuildPlaylist();
-}
-
-/* search stuff */
-
-function clearSearchResults() {
- $("#library").html("");
- $("#search_pagination").remove();
-}
-
-function loadSearchPage(page) {
- $("#library").html("");
- var results = $("#library").data("entries");
- var start = page * 100;
- for(var i = start; i < start + 100 && i < results.length; i++) {
- var li = makeQueueEntry(results[i]);
- if(hasPermission("playlistadd")) {
- if(results[i].thumb) {
- addLibraryButtons(li, results[i].id, true);
- }
- else {
- addLibraryButtons(li, results[i].id);
- }
- }
- $(li).appendTo($("#library"));
- }
- if($("#search_pagination").length > 0) {
- $("#search_pagination").find("li").each(function() {
- $(this).removeClass("active");
- });
- $($("#search_pagination").find("li")[page]).addClass("active");
- }
-}
+function makeAlert(title, text, klass) {
+ if(!klass) {
+ klass = "alert-info";
+ }
+
+ var al = $("").addClass("alert")
+ .addClass(klass)
+ .text(text);
+ $("
").prependTo(al);
+ $("").text(title).prependTo(al);
+ $("").addClass("close pull-right").html("×")
+ .click(function() {
+ al.hide("blind", function() {
+ al.remove();
+ });
+ })
+ .prependTo(al);
+ return al;
+}
+
+function formatUserlistItem(div, data) {
+ var name = $(div.children[1]);
+ name.removeClass();
+ name.css("font-style", "");
+ name.addClass(getNameColor(data.rank));
+ div.find(".profile-box").remove();
+
+ // TODO might remove this
+ var profile;
+ name.mouseenter(function(ev) {
+ profile = $("")
+ .addClass("profile-box")
+ .css("top", (ev.pageY + 5) + "px")
+ .css("left", ev.pageX + "px")
+ .appendTo(div);
+ if(data.profile.image) {
+ $("").addClass("profile-image")
+ .attr("src", data.profile.image)
+ .appendTo(profile);
+ }
+ $("").text(data.name).appendTo(profile);
+ $("").text(data.profile.text).appendTo(profile);
+ });
+ name.mousemove(function(ev) {
+ profile.css("top", (ev.pageY + 5) + "px")
+ .css("left", ev.pageX + "px")
+ });
+ name.mouseleave(function() {
+ profile.remove();
+ });
+
+ var flair = div.children[0];
+ flair.innerHTML = "";
+ // denote current leader with a star
+ if(data.leader) {
+ $("").addClass("icon-star-empty").appendTo(flair);
+ }
+ if(data.meta && data.meta.afk) {
+ name.css("font-style", "italic");
+ $("").addClass("icon-time").appendTo(flair);
+ }
+}
+
+function getNameColor(rank) {
+ if(rank >= Rank.Siteadmin)
+ return "userlist_siteadmin";
+ else if(rank >= Rank.Owner)
+ return "userlist_owner";
+ else if(rank >= Rank.Moderator)
+ return "userlist_op";
+ else if(rank == Rank.Guest)
+ return "userlist_guest";
+ else
+ return "";
+}
+
+function addUserDropdown(entry, name) {
+ // TODO change this
+ entry.find(".dropdown").remove();
+ entry.unbind();
+ var div = $("").addClass("dropdown").appendTo(entry);
+ var ul = $("").addClass("dropdown-menu").appendTo(div);
+ ul.attr("role", "menu");
+ ul.attr("aria-labelledby", "dropdownMenu");
+
+ var ignore = $("").appendTo(ul);
+ var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(ignore);
+ if(IGNORED.indexOf(name) != -1) {
+ a.text("Unignore User");
+ }
+ else {
+ a.text("Ignore User");
+ }
+ a.click(function() {
+ if(IGNORED.indexOf(name) != -1) {
+ IGNORED.splice(IGNORED.indexOf(name), 1);
+ this.text("Ignore User");
+ }
+ else {
+ IGNORED.push(name);
+ this.text("Unignore User");
+ }
+ }.bind(a));
+
+ if(hasPermission("kick")) {
+ var kick = $("").appendTo(ul);
+ var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(kick);
+ a.text("Kick");
+ a.click(function() {
+ socket.emit("chatMsg", {
+ msg: "/kick " + name
+ });
+ });
+ }
+
+ if(CLIENT.rank >= Rank.Moderator) {
+ $("").addClass("divider").appendTo(ul);
+
+ var makeLeader = $("").appendTo(ul);
+ var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(makeLeader);
+ a.text("Make Leader");
+ a.click(function() {
+ socket.emit("assignLeader", {
+ name: name
+ });
+ });
+
+ var takeLeader = $("").appendTo(ul);
+ var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(takeLeader);
+ a.text("Take Leader");
+ a.click(function() {
+ socket.emit("assignLeader", {
+ name: ""
+ });
+ });
+
+ var ban = $("").appendTo(ul);
+ var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(ban);
+ a.text("IP Ban");
+ a.click(function() {
+ socket.emit("chatMsg", {
+ msg: "/ban " + name
+ });
+ });
+
+ var nameban = $("").appendTo(ul);
+ var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(nameban);
+ a.text("Name Ban");
+ a.click(function() {
+ socket.emit("banName", {
+ name: name
+ });
+ });
+
+ $("").addClass("divider").appendTo(ul);
+
+ var promote = $("").appendTo(ul);
+ var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(promote);
+ a.text("Promote");
+ a.click(function() {
+ socket.emit("promote", {
+ name: name
+ });
+ });
+
+ var demote = $("").appendTo(ul);
+ var a = $("").attr("tabindex", "-1").attr("href", "javascript:void(0);").appendTo(demote);
+ a.text("Demote");
+ a.click(function() {
+ socket.emit("demote", {
+ name: name
+ });
+ });
+ }
+
+ entry.click(function() {
+ if(ul.css("display") == "none") {
+ // Hide others
+ $("#userlist ul.dropdown-menu").each(function() {
+ if(this != ul) {
+ $(this).css("display", "none");
+ }
+ });
+ ul.css("display", "block");
+ }
+ else {
+ ul.css("display", "none");
+ }
+ });
+
+ return ul;
+}
+
+/* queue stuff */
+
+function makeQueueEntry(video) {
+ var li = $("");
+ li.addClass("queue_entry");
+ li.data("media", video);
+ if(video.thumb) {
+ $("").attr("src", video.thumb.url)
+ .css("float", "left")
+ .css("clear", "both")
+ .appendTo(li);
+ }
+ var title = $("").addClass("qe_title").appendTo(li)
+ .text(video.title)
+ .attr("href", "#")//formatURL(video))
+ .attr("target", "_blank");
+ var time = $("").addClass("qe_time").appendTo(li);
+ time.text(video.duration);
+ var clear = $("").addClass("qe_clear").appendTo(li);
+ if(video.temp) {
+ li.addClass("queue_temp");
+ }
+
+ // TODO Permissions
+ var menu = $("").addClass("btn-group").appendTo(li);
+ // Play
+ $("").addClass("btn btn-mini qbtn-play")
+ .html("Play")
+ .click(function() {
+ var i = $("#queue").children().index(li);
+ socket.emit("jumpTo", i);
+ })
+ .appendTo(menu);
+ // Queue next
+ $("").addClass("btn btn-mini qbtn-next")
+ .html("Queue Next")
+ .click(function() {
+ var i = $("#queue").children().index(li);
+ socket.emit("moveMedia", {
+ src: i,
+ dest: i < POSITION ? POSITION : POSITION + 1
+ });
+ })
+ .appendTo(menu);
+ // Temp/Untemp
+ $("").addClass("btn btn-mini qbtn-tmp")
+ .html("Make Temporary")
+ .click(function() {
+ var i = $("#queue").children().index(li);
+ var temp = li.find(".qbtn-tmp").data("temp");
+ socket.emit("setTemp", {
+ position: i,
+ temp: !temp
+ });
+ })
+ .appendTo(menu);
+ // Delete
+ $("").addClass("btn btn-mini qbtn-delete")
+ .html("Delete")
+ .click(function() {
+ var i = $("#queue").children().index(li);
+ socket.emit("delete", i);
+ })
+ .appendTo(menu);
+
+ menu.hide();
+
+ li.contextmenu(function(ev) {
+ ev.preventDefault();
+ if(menu.css("display") == "none")
+ menu.show("blind");
+ else
+ menu.hide("blind");
+ return false;
+ });
+
+ menu.blur(function() {
+ menu.hide();
+ });
+ return li;
+}
+
+function addQueueButtons(li) {
+
+}
+
+function rebuildPlaylist() {
+ $("#queue li").each(function() {
+ $(this).find(".btn-group").remove();
+ addQueueButtons(this);
+ });
+}
+
+/* menus */
+function showOptionsMenu() {
+ PLAYER.hide();
+ var modal = $("").addClass("modal hide fade")
+ .appendTo($("body"));
+ var head = $("").addClass("modal-header")
+ .appendTo(modal);
+ $("").addClass("close")
+ .attr("data-dismiss", "modal")
+ .attr("aria-hidden", "true")
+ .appendTo(head)[0].innerHTML = "×";
+ $("").text("User Options").appendTo(head);
+ var body = $("").addClass("modal-body").appendTo(modal);
+ var form = $("").addClass("form-horizontal")
+ .appendTo(body);
+
+ function addOption(lbl, thing) {
+ var g = $("").addClass("control-group").appendTo(form);
+ $("").addClass("control-label").text(lbl).appendTo(g);
+ var c = $("").addClass("controls").appendTo(g);
+ thing.appendTo(c);
+ }
+
+ var themeselect = $("");
+ $("").attr("value", "default").text("Default").appendTo(themeselect);
+ $("").attr("value", "assets/css/darkstrap.css").text("Dark").appendTo(themeselect);
+ themeselect.val(USEROPTS.theme);
+ addOption("Theme", themeselect);
+
+ var usercss = $("").attr("type", "text")
+ .attr("placeholder", "Stylesheet URL");
+ usercss.val(USEROPTS.css);
+ addOption("User CSS", usercss);
+
+ var layoutselect = $("");
+ $("").attr("value", "default").text("Default")
+ .appendTo(layoutselect);
+ $("").attr("value", "large").text("Large")
+ .appendTo(layoutselect);
+ $("").attr("value", "huge").text("Huge")
+ .appendTo(layoutselect);
+ $("").attr("value", "single").text("Single Column")
+ .appendTo(layoutselect);
+ $("").attr("value", "synchtube").text("Synchtube")
+ .appendTo(layoutselect);
+ $("").attr("value", "fluid").text("Fluid")
+ .appendTo(layoutselect);
+ layoutselect.val(USEROPTS.layout);
+ addOption("Layout", layoutselect);
+ var warn = $("").addClass("text-error")
+ .text("Changing layouts may require a refresh")
+ addOption("", warn);
+ $("
").appendTo(form);
+
+ var synchcontainer = $("").addClass("checkbox")
+ .text("Synchronize Media");
+ var synch = $("").attr("type", "checkbox").appendTo(synchcontainer);
+ synch.prop("checked", USEROPTS.synch);
+ addOption("Synch", synchcontainer);
+
+ var syncacc = $("").attr("type", "text")
+ .attr("placeholder", "Seconds");
+ syncacc.val(USEROPTS.sync_accuracy);
+ addOption("Synch Accuracy", syncacc);
+
+ var vidcontainer = $("").addClass("checkbox")
+ .text("Hide Video");
+ var hidevid = $("").attr("type", "checkbox").appendTo(vidcontainer);
+ hidevid.prop("checked", USEROPTS.hidevid);
+ addOption("Hide Video", vidcontainer);
+ $("
").appendTo(form);
+
+ var tscontainer = $("").addClass("checkbox")
+ .text("Show timestamps in chat");
+ var showts = $("").attr("type", "checkbox").appendTo(tscontainer);
+ showts.prop("checked", USEROPTS.show_timestamps);
+ addOption("Show timestamps", tscontainer);
+
+ var blinkcontainer = $("").addClass("checkbox")
+ .text("Flash title on every incoming message");
+ var blink = $("").attr("type", "checkbox").appendTo(blinkcontainer);
+ blink.prop("checked", USEROPTS.blink_title);
+ addOption("Chat Notice", blinkcontainer);
+
+ var sendbtncontainer = $("").addClass("checkbox")
+ .text("Add a send button to the chatbox");
+ var sendbtn = $("").attr("type", "checkbox").appendTo(sendbtncontainer);
+ sendbtn.prop("checked", USEROPTS.chatbtn);
+ addOption("Send Button", sendbtncontainer);
+
+ var altsocketcontainer = $("").addClass("checkbox")
+ .text("Use alternative socket connection");
+ var altsocket = $("").attr("type", "checkbox")
+ .appendTo(altsocketcontainer);
+ altsocket.prop("checked", USEROPTS.altsocket);
+ addOption("Alternate Socket", altsocketcontainer);
+
+ var profile = $("").attr("target", "_blank")
+ .addClass("btn")
+ .attr("href", "./account.html")
+ .text("Profile has moved to the account page");
+ addOption("Profile", profile);
+
+ if(RANK >= Rank.Moderator) {
+ $("
").appendTo(form);
+ var modhatcontainer = $("").addClass("checkbox")
+ .text("Show name color");
+ var modhat = $("").attr("type", "checkbox").appendTo(modhatcontainer);
+ modhat.prop("checked", USEROPTS.modhat);
+ addOption("Modflair", modhatcontainer);
+ }
+
+ var footer = $("").addClass("modal-footer").appendTo(modal);
+ var submit = $("").addClass("btn btn-primary pull-right")
+ .text("Save")
+ .appendTo(footer);
+
+ submit.click(function() {
+ USEROPTS.theme = themeselect.val();
+ USEROPTS.css = usercss.val();
+ USEROPTS.layout = layoutselect.val();
+ USEROPTS.synch = synch.prop("checked");
+ USEROPTS.sync_accuracy = parseFloat(syncacc.val()) || 2;
+ USEROPTS.hidevid = hidevid.prop("checked");
+ USEROPTS.show_timestamps = showts.prop("checked");
+ USEROPTS.blink_title = blink.prop("checked");
+ USEROPTS.chatbtn = sendbtn.prop("checked");
+ USEROPTS.altsocket = altsocket.prop("checked");
+ if(RANK >= Rank.Moderator) {
+ USEROPTS.modhat = modhat.prop("checked");
+ }
+ saveOpts();
+ modal.modal("hide");
+ });
+
+ modal.on("hidden", function() {
+ PLAYER.unhide();
+ applyOpts();
+ modal.remove();
+ });
+ modal.modal();
+}
+
+function saveOpts() {
+ for(var key in USEROPTS) {
+ localStorage.setItem(key, USEROPTS[key]);
+ }
+}
+
+function applyOpts() {
+ $("#usertheme").remove();
+ if(USEROPTS.theme != "default") {
+ $("").attr("rel", "stylesheet")
+ .attr("type", "text/css")
+ .attr("id", "usertheme")
+ .attr("href", USEROPTS.theme)
+ .appendTo($("head"));
+ }
+
+ $("#usercss").remove();
+ if(USEROPTS.css) {
+ $("").attr("rel", "stylesheet")
+ .attr("type", "text/css")
+ .attr("id", "usercss")
+ .attr("href", USEROPTS.css)
+ .appendTo($("head"));
+ }
+
+ switch(USEROPTS.layout) {
+ case "large":
+ largeLayout();
+ break;
+ case "huge":
+ hugeLayout();
+ break;
+ case "single":
+ singleColumnLayout();
+ break;
+ case "synchtube":
+ synchtubeLayout();
+ break;
+ case "fluid":
+ fluidLayout();
+ break;
+ default:
+ break;
+ }
+
+ if(USEROPTS.hidevid) {
+ $("#videowrap").remove();
+ }
+
+ $("#chatbtn").remove();
+ if(USEROPTS.chatbtn) {
+ var btn = $("").addClass("btn btn-block")
+ .text("Send")
+ .attr("id", "chatbtn")
+ .appendTo($("#chatwrap"));
+ btn.click(function() {
+ if($("#chatline").val().trim()) {
+ socket.emit("chatMsg", {
+ msg: $("#chatline").val()
+ });
+ $("#chatline").val("");
+ }
+ });
+ }
+
+ if(USEROPTS.altsocket) {
+ if(socket)
+ socket.disconnect();
+ socket = new NotWebsocket();
+ setupCallbacks();
+ }
+ // Switch from NotWebsocket => Socket.io
+ else if(socket && typeof socket.poll !== "undefined") {
+ try {
+ socket = io.connect(IO_URL);
+ setupCallbacks();
+ }
+ catch(e) {
+ }
+ }
+}
+
+function showLoginMenu() {
+ PLAYER.hide();
+ var modal = $("").addClass("modal hide fade")
+ .appendTo($("body"));
+ var head = $("").addClass("modal-header")
+ .appendTo(modal);
+ $("").addClass("close")
+ .attr("data-dismiss", "modal")
+ .attr("aria-hidden", "true")
+ .appendTo(head)
+ .html("×");
+ $("").text("Login").appendTo(head);
+ var body = $("").addClass("modal-body").appendTo(modal);
+ var frame = $("")
+ .attr("id", "loginframe")
+ .attr("src", "login.html")
+ .css("border", "none")
+ .css("width", "100%")
+ .css("height", "300px")
+ .css("margin", "0")
+ .appendTo(body);
+ var timer = setInterval(function() {
+ frame[0].contentWindow.postMessage("cytube-syn", document.location);
+ }, 1000);
+ var respond = function(e) {
+ if(e.data == "cytube-ack") {
+ clearInterval(timer);
+ }
+ if(e.data.indexOf(":") == -1) {
+ return;
+ }
+ if(e.data.substring(0, e.data.indexOf(":")) == "cytube-login") {
+ var data = e.data.substring(e.data.indexOf(":")+1);
+ data = JSON.parse(data);
+ if(data.error) {
+ // Since this is the login page, invalid session implies bad credentials
+ if(data.error == "Invalid session") {
+ alert("Invalid username/password");
+ }
+ else {
+ alert(data.error);
+ }
+ }
+ else if(data.success) {
+ SESSION = data.session || "";
+ CLIENT.name = data.uname || "";
+ socket.emit("login", {
+ name: CLIENT.name,
+ session: SESSION
+ });
+ if(window.removeEventListener) {
+ window.removeEventListener("message", respond, false);
+ }
+ else if(window.detachEvent) {
+ // If an IE dev ever reads this, please tell your company
+ // to get their shit together
+ window.detachEvent("onmessage", respond);
+ }
+ modal.modal("hide");
+ }
+ }
+ }
+ if(window.addEventListener) {
+ window.addEventListener("message", respond, false);
+ }
+ else if(window.attachEvent) {
+ // If an IE dev ever reads this, please tell your company to get
+ // their shit together
+ window.attachEvent("onmessage", respond);
+ }
+ var footer = $("").addClass("modal-footer").appendTo(modal);
+ modal.on("hidden", function() {
+ PLAYER.unhide();
+ modal.remove();
+ });
+ modal.modal();
+}
+
+function showPollMenu() {
+ $("#pollwrap .poll-menu").remove();
+ var menu = $("").addClass("well poll-menu")
+ .insertAfter($("#newpollbtn"));
+
+ $("").addClass("btn btn-danger pull-right")
+ .text("Cancel")
+ .appendTo(menu)
+ .click(function() {
+ menu.remove();
+ });
+
+ $("").text("Title").appendTo(menu);
+ $("
").appendTo(menu);
+
+ var title = $("").attr("type", "text")
+ .appendTo(menu);
+ $("
").appendTo(menu);
+
+ $("").text("Options").appendTo(menu);
+ $("
").appendTo(menu);
+
+ var addbtn = $("").addClass("btn")
+ .text("Add Option")
+ .appendTo(menu);
+ $("
").appendTo(menu);
+
+ function addOption() {
+ $("").attr("type", "text")
+ .addClass("poll-menu-option")
+ .insertBefore(addbtn);
+ $("
").insertBefore(addbtn);
+ }
+
+ addbtn.click(addOption);
+ addOption();
+ addOption();
+
+ $("
").appendTo(menu);
+ $("").addClass("btn")
+ .text("Open Poll")
+ .addClass("btn-block")
+ .appendTo(menu)
+ .click(function() {
+ var opts = []
+ menu.find(".poll-menu-option").each(function() {
+ if($(this).val() != "")
+ opts.push($(this).val());
+ });
+ socket.emit("newPoll", {
+ title: title.val(),
+ opts: opts
+ });
+ });
+}
+
+function scrollChat() {
+ // TODO add check
+ $("#messagebuffer").scrollTop($("#messagebuffer").prop("scrollheight"));
+}
+
+function hasPermission(key) {
+ if(key.indexOf("playlist") == 0 && CHANNEL.openqueue) {
+ var key2 = "o" + key;
+ var v = CHANNEL.perms[key2];
+ if(typeof v == "number" && CLIENT.rank >= v) {
+ return true;
+ }
+ }
+ var v = CHANNEL.perms[key];
+ if(typeof v != "number") {
+ return false;
+ }
+ return CLIENT.rank >= v;
+}
+
+function handlePermissionChange() {
+ function setVisible(selector, bool) {
+ var disp = bool ? "" : "none";
+ $(selector).css("display", disp);
+ }
+
+ if(CLIENT.rank < 2) {
+ $(".modonly").hide();
+ }
+
+ setVisible("#userpltoggle", CLIENT.rank >= 1);
+
+ setVisible("#playlisttoggle", hasPermission("playlistadd"));
+ $("#queue_next").attr("disabled", !hasPermission("playlistnext"));
+ setVisible("#qlockbtn", CLIENT.rank >= 2);
+
+ setVisible("#getplaylist", hasPermission("playlistgeturl"));
+ setVisible("#clearplaylist", hasPermission("playlistclear"));
+ setVisible("#shuffleplaylist", hasPermission("playlistshuffle"));
+
+ setVisible("#modnav", CLIENT.rank >= 2);
+ setVisible("#chanperms_tab", CLIENT.rank >= 3);
+ setVisible("#banlist_tab", hasPermission("ban"));
+ setVisible("#motdeditor_tab", hasPermission("motdedit"));
+ setVisible("#csseditor_tab", CLIENT.rank >= 3);
+ setVisible("#jseditor_tab", CLIENT.rank >= 3);
+ setVisible("#filtereditor_tab", hasPermission("filteredit"));
+ setVisible("#acl_tab", CLIENT.rank >= 3);
+ setVisible("#dropchannel_tab", CLIENT.rank >= 10);
+
+ setVisible("#newpollbtn", hasPermission("pollctl"));
+
+ $("#pollcontainer .active").find(".btn-danger").remove();
+ if(hasPermission("pollctl")) {
+ var poll = $("#pollcontainer .active");
+ if(poll.length > 0) {
+ $("").addClass("btn btn-danger pull-right")
+ .text("End Poll")
+ .insertAfter(poll.find(".close"))
+ .click(function() {
+ socket.emit("closePoll");
+ });
+ }
+ }
+ var poll = $("#pollcontainer .active");
+ if(poll.length > 0) {
+ poll.find(".btn").attr("disabled", !hasPermission("pollvote"));
+ }
+ var users = $("#userlist").children();
+ for(var i = 0; i < users.length; i++) {
+ addUserDropdown($(users[i]), users[i].children[1].innerHTML);
+ }
+ rebuildPlaylist();
+}
+
+/* search stuff */
+
+function clearSearchResults() {
+ $("#library").html("");
+ $("#search_pagination").remove();
+}
+
+function loadSearchPage(page) {
+ $("#library").html("");
+ var results = $("#library").data("entries");
+ var start = page * 100;
+ for(var i = start; i < start + 100 && i < results.length; i++) {
+ var li = makeQueueEntry(results[i]);
+ if(hasPermission("playlistadd")) {
+ if(results[i].thumb) {
+ addLibraryButtons(li, results[i].id, true);
+ }
+ else {
+ addLibraryButtons(li, results[i].id);
+ }
+ }
+ $(li).appendTo($("#library"));
+ }
+ if($("#search_pagination").length > 0) {
+ $("#search_pagination").find("li").each(function() {
+ $(this).removeClass("active");
+ });
+ $($("#search_pagination").find("li")[page]).addClass("active");
+ }
+}