diff --git a/dark.css b/dark.css index e7a651ce..1273e549 100644 --- a/dark.css +++ b/dark.css @@ -54,10 +54,14 @@ border-color: rgba(255, 255, 255, 0.35) transparent transparent!important;; } /* hovering buttons */ -.ffz-dark .button:hover{ +.ffz-dark .button:not(.primary):not(.ffz-donate):hover{ color:rgb(222,222,222)!important; } +.ffz-dark .moderation-card .button:not(.glyph-only):hover { + color: #fff !important; +} + /* stats */ .ffz-dark #channel .player-column .stats-and-actions .channel-stats .stat svg:not(.svg-glyph_live) path{ fill:rgba(255,255,255,0.35)!important; @@ -100,23 +104,65 @@ border-color: rgba(255, 255, 255, 0.35) transparent transparent!important;; color:rgb(255,255,255)!important; } +/* Right Column */ + +.ffz-dark #right_col { + background-color: rgb(25,25,31); + color: #fff; +} + + +/* Popups */ + +.ffz-dark .card, +.ffz-dark #flyout .content, +.ffz-dark .dropmenu, +.ffz-dark form.js-new_panel_form, +.ffz-dark .js-new_panel_btn, +.ffz-dark .manager .videos-grid .video .meta, +.ffz-dark .ember-chat .chat-room-list { + background-color: rgb(16,16,16); + color: rgb(195,195,195); /*#acacbf;*/ + border-color: #32323e; +} + +.ffz-dark #flyout .point::before { + border-right-color: rgb(16,16,16); /*rgb(25,25,31);*/ +} + +.ffz-dark #flyout .point::after { + border-right-color: #32323e; +} + +.ffz-dark .change-banner .banner-preview, +.ffz-dark form.js-new_panel_form input, +.ffz-dark form.js-new_panel_form textarea, +.ffz-dark .card input, +.ffz-dark .card textarea, +.ffz-dark .dropmenu input, +.ffz-dark input.text, +.ffz-dark input.string, +.ffz-dark textarea, +.ffz-dark .directory_header #custom_filter input { + background-color: rgba(255,255,255,0.05); + border-color: rgba(255,255,255,0.1); + color: #fff; +} + + /* Other stuff */ .ffz-dark .panel-formatting .panel { color: #8c8c9c; } -.ffz-dark a { +.ffz-dark .manager .videos-grid .video:hover .meta .actions li a, +.ffz-dark .ember-chat .chat-room-list .room:not(:hover) p.room-title, +.ffz-dark .dropmenu_action:not(:hover) span, +.ffz-dark a:not(.switch):not(.follow) { color: #a68ed2; } -.ffz-dark #flyout a, -.ffz-dark .dropmenu a, -.ffz-dark .ember-chat-container a, -.ffz-dark .chat-container a { - color: #6441a5; -} - .ffz-dark .panel-formatting .panel h3 { color: inherit; } @@ -150,8 +196,77 @@ border-color: rgba(255, 255, 255, 0.35) transparent transparent!important;; color: #fff; } +.ffz-dark .ember-chat .moderation-card img.channel_logo { + border-color: rgb(16,16,16); +} + +/* Video Manager */ + +.ffz-dark .manager .videos-grid .video .meta .actions { + border-top-color: rgba(255,255,255,0.25); +} + +.ffz-dark #highlighter .highlight-content .form-container li label { + color: #fff; +} + + +/* Subscriptions Page */ + +.ffz-dark .tickets .ticket .benefits { + background-color: rgb(16,16,16); + color: rgb(195,195,195); /*#acacbf;*/ + border-color: #32323e; +} + + +/* Directory Pages */ + +.ffz-dark .following-col .col-header .search-contain .search .search-button svg path { + fill: rgba(255,255,255,0.25); +} + +.ffz-dark .following-col .col-header .search-contain .search .search-button:hover svg path { + fill: rgba(255,255,255,0.5); +} + +.ffz-dark .following-col .col-header, +.ffz-dark .following-col .header { + border-color: #32323e; +} + +.ffz-dark .following-col .following-list .load-more span, +.ffz-dark .viewall a { + background-color: rgb(25,25,31); +} + +.ffz-dark .following-col .following-list .load-more:hover span { + color: #fff; +} + +.ffz-dark .following-col .following-list .load-more:hover span, +.ffz-dark .viewall a:hover { + background-color: rgb(35,35,41); +} + +.ffz-dark .viewall a .text span:first-child { + color: #a68ed2; +} + + /* Profile page fixes */ +.ffz-dark .streams .stream .content .thumb .boxart, +.ffz-dark .videos .video .content .thumb .boxart { + border-color: rgb(16,16,16); +} + +.ffz-dark .ember-chat .moderation-card img.channel_logo, +.ffz-dark .channel-link .profile-photo { + background-color: rgb(16,16,16); +} + +.ffz-dark .items-grid .meta .title, .ffz-dark .items-grid .meta p a { color: #9c9c9c; } @@ -160,10 +275,74 @@ border-color: rgba(255, 255, 255, 0.35) transparent transparent!important;; color: #6c6c6c; } -.ffz-dark ul.tabs li>a:hover, .ffz-dark .directory_header .nav li>a:hover, .ffz-dark ul.tabs_fake li>a:hover, .ffz-dark ul.tabs li>a.active, .ffz-dark .directory_header .nav li>a.active, .ffz-dark ul.tabs_fake li>a.active { - color: #aaa; - border-color: #ccc !important; +.ffz-dark ul.tabs li > a, +.ffz-dark .directory_header .nav li > a, +.ffz-dark ul.tabs_fake li > a { + color: #a68ed2; +} + +.ffz-dark ul.tabs:before, +.ffz-dark .direcotry_header .nav:before, +.ffz-dark ul.tabs_fake:before { + border-color: #32323e; +} + +.ffz-dark ul.tabs li.selected a, +.ffz-dark .directory_header .nav li.selected a, +.ffz-dark ul.tabs_fake li.selected a, +.ffz-dark ul.tabs li>a:hover, +.ffz-dark .directory_header .nav li>a:hover, +.ffz-dark ul.tabs_fake li>a:hover, +.ffz-dark ul.tabs li>a.active, +.ffz-dark .directory_header .nav li>a.active, +.ffz-dark ul.tabs_fake li>a.active { + color: #aaa; + border-color: #ccc !important; } /* Hide the chat Dark Mode control */ -.ffz-dark .toggle-darkmode { display: none; } \ No newline at end of file +.ffz-dark .toggle-darkmode { display: none; } + +/* Chat Text Contrast */ +.ffz-dark .ember-chat-container.dark .chat-line, +.ffz-dark .chat-container.dark .chat-line { + color: #acacbf; +} + +.ffz-dark .ember-chat .chat-settings .chat-colors .chat-colors-swatch:hover, +.ffz-dark .ember-chat .chat-settings .chat-colors .chat-colors-switch.selected { + border-color: #777; + box-shadow: inset 0 0 0 1px #32323e; +} + +/* FrankerFaceZ Menu */ + +.ffz-dark .chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading, +.ffz-dark .chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid .heading, +.ffz-dark .ffz-ui-popup ul.menu, +.ffz-dark .ffz-ui-popup ul.menu a { + border-color: #32323e; +} + +.ffz-dark .ffz-ui-popup ul.menu { + background-color: rgb(33,33,33); +} + +.ffz-dark .ffz-ui-popup ul.menu li.active { + background-color: rgb(16,16,16); +} + +.ffz-dark .ffz-ui-popup ul.menu li.active a { + border-top-color: rgb(16,16,16); +} + +/* New User Prompt */ + +.ffz-dark #new-user-prompt { + background-color: rgb(25,25,31); + color: #acacbf; +} + +.ffz-dark #new-user-prompt .message .title { + color: #fff; +} \ No newline at end of file diff --git a/script.js b/script.js index 3484f421..b2c5d590 100644 --- a/script.js +++ b/script.js @@ -4,6 +4,20 @@ var FFZ = window.FrankerFaceZ, utils = require('./utils'); +// -------------------- +// Settings +// -------------------- + +FFZ.settings_info.bot_badges = { + type: "boolean", + value: true, + + category: "Chat", + name: "Bot Badges", + help: "Give special badges to known bots." + }; + + // -------------------- // Initialization // -------------------- @@ -39,7 +53,8 @@ FFZ.prototype.bttv_badges = function(data) { var user_id = data.sender, user = this.users[user_id], badges_out = [], - insert_at = -1; + insert_at = -1, + alpha = BetterTTV.settings.get('alphaTags'); if ( ! user || ! user.badges ) return; @@ -53,7 +68,6 @@ FFZ.prototype.bttv_badges = function(data) { } } - for (var slot in user.badges) { if ( ! user.badges.hasOwnProperty(slot) ) continue; @@ -61,8 +75,16 @@ FFZ.prototype.bttv_badges = function(data) { var badge = user.badges[slot], full_badge = this.badges[badge.id] || {}, desc = badge.title || full_badge.title, - style = "", - alpha = BetterTTV.settings.get('alphaTags'); + style = ""; + + if ( full_badge.visible !== undefined ) { + var visible = full_badge.visible; + if ( typeof visible == "function" ) + visible = visible.bind(this)(null, user_id); + + if ( ! visible ) + continue; + } if ( badge.image ) style += 'background-image: url(\\"' + badge.image + '\\"); '; @@ -117,12 +139,21 @@ FFZ.prototype.render_badge = function(view) { if ( full_badge.visible !== undefined ) { var visible = full_badge.visible; if ( typeof visible == "function" ) - try { visible = visible.bind(this)(room_id, user); } catch(err) { } + visible = visible.bind(this)(room_id, user); if ( ! visible ) continue; } + if ( full_badge.replaces ) { + var el = badges[0].querySelector('.badge.' + full_badge.replaces); + if ( el ) { + el.style.backgroundImage = 'url("' + (badge.image || full_badge.image) + '")'; + el.title += ", " + (badge.title || full_badge.title); + return; + } + } + var el = document.createElement('div'); el.className = 'badge float-left tooltip ffz-badge-' + badge.id; el.setAttribute('title', badge.title || full_badge.title); @@ -155,24 +186,33 @@ FFZ.prototype.render_badge = function(view) { // Legacy Support // -------------------- -FFZ.known_bots = ["quoteconut", "quoconut", "zenwan", "nightbot", "moobot", "xanbot"]; +FFZ.bttv_known_bots = ["nightbot","moobot","sourbot","xanbot","manabot","mtgbot","ackbot","baconrobot","tardisbot","deejbot","valuebot","stahpbot"]; +FFZ.known_bots = ["quoteconut", "quoconut", "zenwan", "triiharder", "wobblerbot", "theroflbotr", "acebot"]; + FFZ.prototype._legacy_add_donors = function(tries) { this.badges[1] = {id: 1, title: "FFZ Donor", color: "#755000", image: "//cdn.frankerfacez.com/channel/global/donoricon.png"}; utils.update_css(this._badge_style, 1, badge_css(this.badges[1])); - // Developer Badges + // Developer Badge this.badges[0] = {id: 0, title: "FFZ Developer", color: "#FAAF19", image: "//cdn.frankerfacez.com/channel/global/devicon.png"}; utils.update_css(this._badge_style, 0, badge_css(this.badges[0])); - this.users.sirstendec = {badges: {0: {id:0}}}; - // Bot Badges - /*this.badges[2] = {id: 2, title: "Bot", color: "#595959", image: "//cdn.frankerfacez.com/channel/global/boticon.png", - visible: function(r,user) { return !(this.has_bttv && FFZ.bttv_known_bots[user]); }}; + // Bot Badge + this.badges[2] = {id: 2, title: "Bot", color: "#595959", image: "//cdn.frankerfacez.com/channel/global/boticon.png", + replaces: 'moderator', + visible: function(r,user) { return this.settings.bot_badges && !(this.has_bttv && FFZ.bttv_known_bots.indexOf(user)!==-1); }}; utils.update_css(this._badge_style, 2, badge_css(this.badges[2])); + for(var i=0;i", - set = data.set, + var set = data.set, set_type = data.set_type; if ( set_type === undefined ) @@ -457,12 +496,7 @@ var FFZ = window.FrankerFaceZ, set_type = null; } - if ( ! set_type ) - output += '' + set + ''; - else - output += "" + set_type + "" + set + ""; - - return '' + output + '
'; + return "Emoticon: " + data.code + "\n" + (set_type ? set_type + ": " : "") + set; }, build_tooltip = function(id) { @@ -578,7 +612,7 @@ FFZ.settings_info.keywords = { FFZ.settings_info.fix_color = { type: "boolean", - value: false, + value: true, category: "Chat", visible: function() { return ! this.has_bttv }, @@ -647,6 +681,7 @@ FFZ.prototype.setup_line = function() { var tokens = this._super(); try { + var start = performance.now(); tokens = f._remove_banned(tokens); tokens = f._emoticonize(this, tokens); var user = f.get_user(); @@ -654,6 +689,10 @@ FFZ.prototype.setup_line = function() { if ( ! user || this.get("model.from") != user.login ) tokens = f._mentionize(this, tokens); + var end = performance.now(); + if ( end - start > 5 ) + f.log("Tokenizing Message Took Too Long - " + (end-start) + "ms - " + JSON.stringify(tokens)); + } catch(err) { try { f.error("LineController tokenizedMessage: " + err); @@ -673,6 +712,8 @@ FFZ.prototype.setup_line = function() { didInsertElement: function() { this._super(); try { + var start = performance.now(); + var el = this.get('element'), controller = this.get('context'), user = controller.get('model.from'), @@ -715,7 +756,7 @@ FFZ.prototype.setup_line = function() { if ( mentioned ) { el.classList.add("ffz-mentioned"); - if ( ! document.hasFocus() && ! this.get('context.model.ffz_notified') && f.settings.highlight_notifications ) { + if ( f.settings.highlight_notifications && !document.hasFocus() && !this.get('context.model.ffz_notified') ) { var cap_room = FFZ.get_capitalization(room), cap_user = FFZ.get_capitalization(user), room_name = cap_room, @@ -746,7 +787,7 @@ FFZ.prototype.setup_line = function() { // Banned Links var bad_links = el.querySelectorAll('a.deleted-link'); for(var i=0; i < bad_links.length; i++) { - var link = bad_links[i]; + var link = bad_links[i]; link.addEventListener("click", function(e) { if ( ! this.classList.contains("deleted-link") ) @@ -783,7 +824,7 @@ FFZ.prototype.setup_line = function() { // Enhanced Emotes - var images = el.querySelectorAll('img'); + var images = el.querySelectorAll('img.emoticon'); for(var i=0; i < images.length; i++) { var img = images[i], name = img.alt, @@ -806,8 +847,6 @@ FFZ.prototype.setup_line = function() { f.ws_send("twitch_emote", id, load_emote_data.bind(f, id, img.alt)); } - jQuery(img).tipsy({html:true}); - } else if ( img.getAttribute('data-ffz-emote') ) { var data = JSON.parse(decodeURIComponent(img.getAttribute('data-ffz-emote'))), id = data && data[0] || null, @@ -835,13 +874,15 @@ FFZ.prototype.setup_line = function() { set: set_name, set_type: set_type }); - - jQuery(img).tipsy({html:true}); - - } else - jQuery(img).tipsy(); + } } + jQuery(images).tipsy(); + + + var duration = performance.now() - start; + if ( duration > 5 ) + f.log("Line Took Too Long - " + duration + "ms - " + el.innerHTML); } catch(err) { try { @@ -887,7 +928,7 @@ FFZ.prototype._handle_color = function(color) { // Color Too Bright. We need a lum of 0.3 or less. matched = true; - var s = 255, + var s = 127, nc = rgb; while(s--) { nc = utils.darken(nc); @@ -899,15 +940,15 @@ FFZ.prototype._handle_color = function(color) { } else output += '.ffz-chat-colors .ember-chat-container:not(.dark) .chat-line ' + rule + ', .ffz-chat-colors .chat-container:not(.dark) .chat-line ' + rule + ' { color: ' + color + ' !important; }\n'; - if ( lum < 0.1 ) { + if ( lum < 0.15 ) { // Color Too Dark. We need a lum of 0.1 or more. matched = true; - var s = 255, + var s = 127, nc = rgb; while(s--) { nc = utils.brighten(nc); - if ( utils.get_luminance(nc) >= 0.1 ) + if ( utils.get_luminance(nc) >= 0.15 ) break; } @@ -962,8 +1003,11 @@ FFZ.get_capitalization = function(name, callback) { FFZ.prototype.capitalize = function(view, user) { var name = FFZ.get_capitalization(user, this.capitalize.bind(this, view)); - if ( name && view ) - view.$('.from').text(name); + if ( !name || !view ) + return; + + var from = view.$('.from'); + from && from.text(name); } @@ -1396,7 +1440,7 @@ var FFZ = window.FrankerFaceZ, if ( ! room.moderator_badge ) return ""; - return '.chat-line[data-room="' + room.id + '"] .badges .moderator { background-image:url("' + room.moderator_badge + '") !important; }'; + return '.chat-line[data-room="' + room.id + '"] .badges .moderator { background-image:url("' + room.moderator_badge + '"); }'; } @@ -2052,8 +2096,6 @@ var FFZ = window.FrankerFaceZ, SENDER_REGEX = /(\sdata-sender="[^"]*"(?=>))/; -FFZ.bttv_known_bots = ["nightbot","moobot","sourbot","xanbot","manabot","mtgbot","ackbot","baconrobot","tardisbot","deejbot","valuebot","stahpbot"]; - // -------------------- // Initialization // -------------------- @@ -2291,7 +2333,7 @@ FFZ.get = function() { return FFZ.instance; } // Version var VER = FFZ.version_info = { - major: 3, minor: 2, revision: 1, + major: 3, minor: 2, revision: 2, toString: function() { return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); } @@ -3051,7 +3093,10 @@ FFZ.prototype.ws_create = function() { } else { var success = cmd === 'True', callback = f._ws_callbacks[request]; - f.log("Socket Reply to " + request + " - " + (success ? "SUCCESS" : "FAIL"), data); + + if ( ! success || ! callback ) + f.log("Socket Reply to " + request + " - " + (success ? "SUCCESS" : "FAIL"), data); + if ( callback ) { delete f._ws_callbacks[request]; callback(success, data); @@ -3623,6 +3668,22 @@ var FFZ = window.FrankerFaceZ, TWITCH_BASE = "http://static-cdn.jtvnw.net/emoticons/v1/", BANNED_SETS = {"00000turbo":true}, + KNOWN_CODES = { + "B-?\\)": "B-)", + "\\:-?[z|Z|\\|]": ":-Z", + "\\:-?\\)": ":-)", + "\\:-?\\(": ":-(", + "\\:-?(p|P)": ":-P", + "\\;-?(p|P)": ";-P", + "\\<\\;3": "<3", + "\\:-?(?:\\/|\\\\)(?!\\/)": ":-/", + "\\;-?\\)": ";-)", + "R-?\\)": "R-)", + "[o|O](_|\\.)[o|O]": "O.o", + "\\:-?D": ":-D", + "\\:-?(o|O)": ":-O", + "\\>\\;\\(": ">(", + }, get_emotes = function(ffz) { var Chat = App.__container__.lookup('controller:chat'), @@ -3637,6 +3698,9 @@ var FFZ = window.FrankerFaceZ, // Remove the 'default' set. set_ids = set_ids.split(",").removeObject("0") + if ( ffz.settings.global_emotes_in_menu ) + set_ids.push("0"); + return [set_ids, user_sets]; }; @@ -3645,6 +3709,15 @@ var FFZ = window.FrankerFaceZ, // Initialization // ------------------- +FFZ.settings_info.global_emotes_in_menu = { + type: "boolean", + value: false, + + name: "Display Global Emotes in My Emotes", + help: "Display the global Twitch emotes in the My Emoticons menu." + }; + + FFZ.prototype.setup_my_emotes = function() { this._twitch_emote_sets = {}; this._twitch_set_to_channel = {}; @@ -3654,6 +3727,8 @@ FFZ.prototype.setup_my_emotes = function() { this._twitch_set_to_channel = JSON.parse(localStorage.ffzTwitchSets); } catch(err) { } } + + this._twitch_set_to_channel[0] = "twitch_global"; } @@ -3715,6 +3790,13 @@ FFZ.menu_pages.my_emotes = { if ( !name || BANNED_SETS[name] ) return; + if ( name == "twitch_global" ) { + FFZ.capitalization["global emoticons"] = ["Global Emoticons", Date.now()]; + set.channel = "Global Emoticons"; + set.badge = "//cdn.frankerfacez.com/channel/global/twitch_logo.png"; + return; + } + if ( name == "turbo" ) { set.channel = "Twitch Turbo"; set.badge = "//cdn.frankerfacez.com/script/turbo_badge.png"; @@ -3839,10 +3921,10 @@ FFZ.menu_pages.my_emotes = { var an = a[1].toLowerCase(), bn = b[1].toLowerCase(); - if ( an === "twitch turbo" ) + if ( an === "twitch turbo" || an === "global emoticons" ) an = "zzz" + an; - if ( bn === "twitch turbo" ) + if ( bn === "twitch turbo" || bn === "global emoticons" ) bn = "zzz" + bn; if ( an < bn ) return -1; @@ -3864,7 +3946,8 @@ FFZ.menu_pages.my_emotes = { menu.appendChild(heading); for(var x=0; x < set.emotes.length; x++) { - var emote = set.emotes[x]; + var emote = set.emotes[x], + code = KNOWN_CODES[emote.code] || emote.code; var s = document.createElement('span'); s.className = 'emoticon tooltip'; @@ -3876,8 +3959,8 @@ FFZ.menu_pages.my_emotes = { s.style.backgroundImage = '-ms-' + img_set; s.style.backgroundImage = img_set; - s.title = emote.code; - s.addEventListener('click', f._add_emote.bind(f, view, emote.code)); + s.title = code; + s.addEventListener('click', f._add_emote.bind(f, view, code)); menu.appendChild(s); } diff --git a/script.min.js b/script.min.js index ad96a0a3..8064ad97 100644 --- a/script.min.js +++ b/script.min.js @@ -1,3 +1,3 @@ -!function(e){!function t(e,n,o){function i(s,a){if(!n[s]){if(!e[s]){var l="function"==typeof require&&require;if(!a&&l)return l(s,!0);if(r)return r(s,!0);throw new Error("Cannot find module '"+s+"'")}var c=n[s]={exports:{}};e[s][0].call(c.exports,function(t){var n=e[s][1][t];return i(n?n:t)},c,c.exports,t,e,n,o)}return n[s].exports}for(var r="function"==typeof require&&require,s=0;se?this._legacy_add_donors(e):void 0):void 0})},n.prototype._legacy_parse_donors=function(e){var t=0;if(null!=e)for(var n=e.trim().split(/\W+/),o=0;o50)return"Each user you unmod counts as a single message. To avoid being globally banned, please limit yourself to 50 at a time and wait between uses.";for(var o=t.length;t.length;){var i=t.shift();e.room.tmiRoom.sendMessage("/unmod "+i)}return"Sent unmod command for "+o+" users."},t.ffz_commands.massunmod.help="Usage: /ffz massunmod \nBroadcaster only. Unmod all the users in the provided list.",t.ffz_commands.massmod=function(e,t){if(t=t.join(" ").trim(),!t.length)return"You must provide a list of users to mod.";t=t.split(/\W*,\W*/);var n=this.get_user();if(!n||!n.login==e.id)return"You must be the broadcaster to use massmod.";if(t.length>50)return"Each user you mod counts as a single message. To avoid being globally banned, please limit yourself to 50 at a time and wait between uses.";for(var o=t.length;t.length;){var i=t.shift();e.room.tmiRoom.sendMessage("/mod "+i)}return"Sent mod command for "+o+" users."},t.ffz_commands.massmod.help="Usage: /ffz massmod \nBroadcaster only. Mod all the users in the provided list."},{}],3:[function(e,t){var n='',o="true"==localStorage.ffzDebugMode&&document.body.classList.contains("ffz-dev");t.exports={DEBUG:o,SERVER:o?"//localhost:8000/":"//cdn.frankerfacez.com/",SVGPATH:n,ZREKNARF:''+n+"",CHAT_BUTTON:''+n+"",GEAR:'',HEART:'',EMOTE:''}},{}],4:[function(){var t=e.FrankerFaceZ;t.settings_info.developer_mode={type:"boolean",value:!1,storage_key:"ffzDebugMode",visible:function(){return this.settings.developer_mode||Date.now()-parseInt(localStorage.ffzLastDevMode||"0")<6048e5},category:"Debugging",name:"Developer Mode",help:"Load FrankerFaceZ from the local development server instead of the CDN. Please refresh after changing this setting.",on_update:function(){localStorage.ffzLastDevMode=Date.now()}},t.ffz_commands.developer_mode=function(e,t){var n,t=t&&t.length?t[0].toLowerCase():null;return"y"==t||"yes"==t||"true"==t||"on"==t?n=!0:("n"==t||"no"==t||"false"==t||"off"==t)&&(n=!1),void 0===n?"Developer Mode is currently "+(this.settings.developer_mode?"enabled.":"disabled."):(this.settings.set("developer_mode",n),"Developer Mode is now "+(n?"enabled":"disabled")+". Please refresh your browser.")},t.ffz_commands.developer_mode.help="Usage: /ffz developer_mode \nEnable or disable Developer Mode. When Developer Mode is enabled, the script will be reloaded from //localhost:8000/script.js instead of from the CDN."},{}],5:[function(){var t=e.FrankerFaceZ;t.prototype.setup_chatview=function(){this.log("Hooking the Ember Chat view.");var e=App.__container__.resolve("view:chat");this._modify_cview(e);try{e.create().destroy()}catch(t){}for(var n in Ember.View.views)if(Ember.View.views.hasOwnProperty(n)){var o=Ember.View.views[n];if(o instanceof e){this.log("Adding UI link manually to Chat view.",o);try{o.$(".textarea-contain").append(this.build_ui_link(o))}catch(t){this.error("setup: build_ui_link: "+t)}}}},t.prototype._modify_cview=function(e){var t=this;e.reopen({didInsertElement:function(){this._super();try{this.$()&&this.$(".textarea-contain").append(t.build_ui_link(this))}catch(e){t.error("didInsertElement: build_ui_link: "+e)}},willClearRender:function(){this._super();try{this.$(".ffz-ui-toggle").remove()}catch(e){t.error("willClearRender: remove ui link: "+e)}},ffzUpdateLink:Ember.observer("controller.currentRoom",function(){try{t.update_ui_link()}catch(e){t.error("ffzUpdateLink: update_ui_link: "+e)}})})}},{}],6:[function(t){var n=e.FrankerFaceZ,o=t("../utils"),i=function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},r="[\\s`~<>!-#%-\\x2A,-/:;\\x3F@\\x5B-\\x5D_\\x7B}\\u00A1\\u00A7\\u00AB\\u00B6\\u00B7\\u00BB\\u00BF\\u037E\\u0387\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061E\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u0AF0\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166D\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u2329\\u232A\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E3B\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uAAF0\\uAAF1\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65]",s=new RegExp(r+"*,"+r+"*"),a=function(e){return(e+"").replace(/&/g,"&").replace(/'/g,"'").replace(/"/g,""").replace(//g,">")},l="http://static-cdn.jtvnw.net/emoticons/v1/",c=function(e){return l+e+"/1.0 1x, "+l+e+"/2.0 2x, "+l+e+"/3.0 4x"},u=function(e){var t="Emoticon"+e.code+"",n=e.set,o=e.set_type;return void 0===o&&(o="Channel"),n?(("00000turbo"==n||"turbo"==n)&&(n="Twitch Turbo",o=null),t+=o?""+o+""+n+"":''+n+"",''+t+"
"):e.code},d=function(e){{var t=this._twitch_emotes[e];t?t.set:null}return t?"string"==typeof t?t:t.tooltip?t.tooltip:t.tooltip=u(t):"???"},h=function(e,t,n,o){if(n){t&&(o.code=t),this._twitch_emotes[e]=o;for(var i=d.bind(this)(e),r=document.querySelectorAll('img[emote-id="'+e+'"]'),s=0;s-1&&(-1===t.indexOf("/")||t.indexOf("@")>16,t>>8&255,255&t],i=o.get_luminance(n),r="",s='span[style="color:'+e+'"]',a=!1;if(i>.3){a=!0;for(var l=255,c=n;l--&&(c=o.darken(c),!(o.get_luminance(c)<=.3)););r+=".ffz-chat-colors .ember-chat-container:not(.dark) .chat-line "+s+", .ffz-chat-colors .chat-container:not(.dark) .chat-line "+s+" { color: "+o.rgb_to_css(c)+" !important; }\n"}else r+=".ffz-chat-colors .ember-chat-container:not(.dark) .chat-line "+s+", .ffz-chat-colors .chat-container:not(.dark) .chat-line "+s+" { color: "+e+" !important; }\n";if(.1>i){a=!0;for(var l=255,c=n;l--&&(c=o.brighten(c),!(o.get_luminance(c)>=.1)););r+=".ffz-chat-colors .theatre .chat-container .chat-line "+s+", .ffz-chat-colors .chat-container.dark .chat-line "+s+", .ffz-chat-colors .ember-chat-container.dark .chat-line "+s+" { color: "+o.rgb_to_css(c)+" !important; }\n"}else r+=".ffz-chat-colors .theatre .chat-container .chat-line "+s+", .ffz-chat-colors .chat-container.dark .chat-line "+s+", .ffz-chat-colors .ember-chat-container.dark .chat-line "+s+" { color: "+e+" !important; }\n";a&&(this._fix_color_style.innerHTML+=r)}},n.capitalization={},n._cap_fetching=0,n.get_capitalization=function(t,o){if(e.BetterTTV&&BetterTTV.chat&&BetterTTV.chat.helpers.lookupDisplayName)return BetterTTV.chat.helpers.lookupDisplayName(t);if(!t)return t;if(t=t.toLowerCase(),"jtv"==t||"twitchnotify"==t)return t;var i=n.capitalization[t];return i&&Date.now()-i[1]<36e5?i[0]:(n._cap_fetching<25&&(n._cap_fetching++,n.get().ws_send("get_display_name",t,function(e,i){var r=e?i:t;n.capitalization[t]=[r,Date.now()],n._cap_fetching--,"function"==typeof o&&o(r)})),i?i[0]:t)},n.prototype.capitalize=function(e,t){var o=n.get_capitalization(t,this.capitalize.bind(this,e));o&&e&&e.$(".from").text(o)},n._regex_cache={},n._get_regex=function(e){return n._regex_cache[e]=n._regex_cache[e]||RegExp("\\b"+i(e)+"\\b","ig")},n._words_to_regex=function(e){var t=n._regex_cache[e];if(!t){for(var o="",s=0;s<banned link>',own:!0}:s)}return i},n.prototype._emoticonize=function(e,t){var n=e.get("parentController.model.id"),o=e.get("model.from"),i=this,r=this.getEmotes(o,n),s=[];return _.each(r,function(e){var n=i.emote_sets[e];n&&_.each(n.emotes,function(e){_.any(t,function(t){return _.isString(t)&&t.match(e.regex)})&&s.push(e)})}),s.length?("string"==typeof t&&(t=[t]),_.each(s,function(e){var n={isEmoticon:!0,cls:e.klass,emoticonSrc:e.url+'" data-ffz-emote="'+encodeURIComponent(JSON.stringify([e.id,e.set_id])),altText:e.hidden?"???":e.name};t=_.compact(_.flatten(_.map(t,function(t){if(_.isObject(t))return t;var o=t.split(e.regex),i=[];return o.forEach(function(e,t){i.push(e),t!==o.length-1&&i.push(n)}),i})))}),t):t}},{"../utils":27}],7:[function(t){var n=e.FrankerFaceZ,o=t("../utils"),i={ESC:27,P:80,B:66,T:84},r=[["5m",300],["10m",600],["1hr",3600],["12hr",43200],["24hr",86400]],s='',a='';n.settings_info.enhanced_moderation={type:"boolean",value:!1,visible:function(){return!this.has_bttv},category:"Chat",name:"Enhanced Moderation",help:"Use /p, /t, /u and /b in chat to moderate chat, or use hotkeys with moderation cards."},n.prototype.setup_mod_card=function(){this.log("Hooking the Ember Moderation Card view.");var e=App.__container__.resolve("view:moderation-card"),t=this;e.reopen({didInsertElement:function(){this._super();try{if(t.has_bttv||!t.settings.enhanced_moderation)return;var e=this.get("element"),n=this.get("context");if(e.classList.add("ffz-moderation-card"),n.get("parentController.model.isModeratorOrHigher")){e.classList.add("ffz-is-mod"),e.setAttribute("tabindex",1),e.addEventListener("keyup",function(e){var t=e.keyCode||e.which,o=n.get("model.user.id"),r=n.get("parentController.model");if(t==i.P)r.send("/timeout "+o+" 1");else if(t==i.B)r.send("/ban "+o);else if(t==i.T)r.send("/timeout "+o+" 600");else if(t!=i.ESC)return;n.send("hideModOverlay")});var l=document.createElement("div");l.className="interface clearfix";var c=function(e){var t=n.get("model.user.id"),o=n.get("parentController.model");o.send(-1===e?"/unban "+t:"/timeout "+t+" "+e)},u=function(e,t){var n=document.createElement("button");return n.className="button",n.innerHTML=e,n.title="Timeout User for "+o.number_commas(t)+" Second"+(1!=t?"s":""),600===t?n.title="(T)"+n.title.substr(1):1===t&&(n.title="(P)urge - "+n.title),jQuery(n).tipsy(),n.addEventListener("click",c.bind(this,t)),n};l.appendChild(u("Purge",1));var d=document.createElement("span");d.className="right",l.appendChild(d);for(var h=0;h button");v&&"button"==v.className&&(v.innerHTML=s,v.classList.add("glyph-only"),v.classList.add("message"),v.title="Message User",jQuery(v).tipsy()),this.$().draggable({start:function(){e.focus()}}),e.focus()}catch(b){try{t.error("ModerationCardView didInsertElement: "+b)}catch(b){}}}})},n.chat_commands.purge=n.chat_commands.p=function(e,t){if(!t||!t.length)return"Purge Usage: /p username [more usernames separated by spaces]";if(t.length>10)return"Please only purge up to 10 users at once.";for(var n=0;n10)return"Please only ban up to 10 users at once.";for(var n=0;n10)return"Please only unban up to 10 users at once.";for(var n=0;nn?this._legacy_add_room(e,t,n):void 0)})},n.prototype._legacy_load_room_css=function(e,t,n){var s=e,a=s.match(r);a&&a[1]&&(s=a[1]);var l={id:e,menu_sets:[s],sets:[s],moderator_badge:null,css:null};return n&&(n=n.replace(o,"").trim()),n&&(n=n.replace(i,function(e,t){return l.moderator_badge||"modicon.png"!==t.substr(-11)?e:(l.moderator_badge=t,"")})),l.css=n||null,this._load_room_json(e,t,l)}},{"../constants":3,"../utils":27}],9:[function(){var t=e.FrankerFaceZ;t.prototype.setup_viewers=function(){this.log("Hooking the Ember Viewers controller.");var e=App.__container__.resolve("controller:viewers");this._modify_viewers(e)},t.prototype._modify_viewers=function(e){var n=this;e.reopen({lines:function(){var e=this._super();try{var o=[],i={},r=null,s=App.__container__.lookup("controller:channel"),a=this.get("parentController.model.id"),l=s&&s.get("id");if(l){var c=s.get("display_name");c&&(t.capitalization[l]=[c,Date.now()])}a!=l&&(l=null);for(var u=0;un?this._legacy_load_set(e,t,n):"function"==typeof t&&t(!1))})},n.prototype._legacy_load_css=function(e,t,n){var r={},s={id:e,emotes:r,extra_css:null},a=this;n=n.replace(o,function(t,n,o,i,s,c,u,d){s=parseInt(s),c=parseInt(c),u=l(u,s);var h="."===i.substr(i.lastIndexOf("/")+1,1),p=++a._last_emote_id,m={id:p,set_id:e,hidden:h,name:o,height:s,width:c,url:i,margins:u,extra_css:d};return r[p]=m,""}).trim(),n&&n.replace(i,function(e,t){s.icon||"modicon.png"!==t.substr(-11)||(s.icon=t)}),this._load_set_json(e,t,s)}},{"./constants":3,"./utils":27}],11:[function(){var t=e.FrankerFaceZ,n=/(\sdata-sender="[^"]*"(?=>))/;t.bttv_known_bots=["nightbot","moobot","sourbot","xanbot","manabot","mtgbot","ackbot","baconrobot","tardisbot","deejbot","valuebot","stahpbot"],t.prototype.find_bttv=function(t,n){return this.has_bttv=!1,e.BTTVLOADED?this.setup_bttv(n||0):void(n>=6e4?this.log("BetterTTV was not detected after 60 seconds."):setTimeout(this.find_bttv.bind(this,t,(n||0)+t),t))},t.prototype.setup_bttv=function(e){this.log("BetterTTV was detected after "+e+"ms. Hooking."),this.has_bttv=!0,document.body.classList.remove("ffz-dark"),this._dark_style&&(this._dark_style.parentElement.removeChild(this._dark_style),delete this._dark_style),document.body.classList.remove("ffz-chat-colors"),document.body.classList.remove("ffz-chat-background");var t=BetterTTV.chat.helpers.sendMessage,o=this;BetterTTV.chat.helpers.sendMessage=function(e){var n=e.split(" ",1)[0].toLowerCase();return"/ffz"!==n?t(e):void o.run_ffz_command(e.substr(5),BetterTTV.chat.store.currentRoom)};var i,r=BetterTTV.chat.handlers.privmsg;BetterTTV.chat.handlers.privmsg=function(e,t){i=e;var n=r(e,t);return i=null,n};var s=BetterTTV.chat.templates.privmsg;BetterTTV.chat.templates.privmsg=function(e,t,r,a,l){o.bttv_badges(l);var c=s(e,t,r,a,l);return c.replace(n,'$1 data-room="'+i+'"')};var a,l=BetterTTV.chat.templates.message;BetterTTV.chat.templates.message=function(e,t,n,o){a=e;var i=l(e,t,n,o);return a=null,i};var c=BetterTTV.chat.templates.emoticonize;BetterTTV.chat.templates.emoticonize=function(e,t){var n=c(e,t),r=o.getEmotes(a,i),t=[];return _.each(r,function(e){var i=o.emote_sets[e];i&&_.each(i.emotes,function(e){_.any(n,function(t){return _.isString(t)&&t.match(e.regex)})&&t.push(e)})}),t.length?(_.each(t,function(e){var t=[''+e.name+''],o=n;if(n=[],!o||!o.length)return n;for(var i=0;i=6e4?this.log("Emote Menu for Twitch was not detected after 60 seconds."):setTimeout(this.find_emote_menu.bind(this,t,(n||0)+t),t))},t.prototype.setup_emote_menu=function(e){this.log("Emote Menu for Twitch was detected after "+e+"ms. Registering emote enumerator."),emoteMenu.registerEmoteGetter("FrankerFaceZ",this._emote_menu_enumerator.bind(this))},t.prototype._emote_menu_enumerator=function(){for(var e=this.get_user(),n=e?e.login:null,o=App.__container__.lookup("controller:chat"),i=o?o.get("currentRoom.id"):null,r=this.getEmotes(n,i),s=[],a=0;a=6e4?this.log('Twitch application not detected in "'+location.toString()+'". Aborting.'):setTimeout(this.initialize.bind(this,t,(n||0)+t),t)))},n.prototype.setup_ember=function(t){var o=e.performance&&performance.now?performance.now():Date.now();this.log("Found Twitch application after "+(t||0)+' ms in "'+location+'". Initializing FrankerFaceZ version '+n.version_info),this.users={},this.load_settings(),this.setup_dark(),this.ws_create(),this.setup_emoticons(),this.setup_badges(),this.setup_room(),this.setup_line(),this.setup_chatview(),this.setup_viewers(),this.setup_mod_card(),this.setup_notifications(),this.setup_css(),this.setup_menu(),this.setup_my_emotes(),this.setup_races(),this.find_bttv(10),this.find_emote_menu(10),this.check_ff();var i=e.performance&&performance.now?performance.now():Date.now(),r=i-o;this.log("Initialization complete in "+r+"ms")}},{"./badges":1,"./commands":2,"./debug":4,"./ember/chatview":5,"./ember/line":6,"./ember/moderation-card":7,"./ember/room":8,"./ember/viewers":9,"./emoticons":10,"./ext/betterttv":11,"./ext/emote_menu":12,"./featurefriday":14,"./settings":15,"./shims":16,"./socket":17,"./ui/about_page":18,"./ui/dark":19,"./ui/menu":20,"./ui/menu_button":21,"./ui/my_emotes":22,"./ui/notifications":23,"./ui/races":24,"./ui/styles":25,"./ui/viewer_count":26}],14:[function(t){var n=e.FrankerFaceZ,o=t("./constants");n.prototype.feature_friday=null,n.prototype.check_ff=function(e){e||this.log("Checking for Feature Friday data..."),jQuery.ajax(o.SERVER+"script/event.json",{cache:!1,dataType:"json",context:this}).done(function(e){return this._load_ff(e)}).fail(function(t){return 404==t.status?this._load_ff(null):(e=e||0,e++,10>e?setTimeout(this.check_ff.bind(this,e),250):this._load_ff(null))})},n.ws_commands.reload_ff=function(){this.check_ff()},n.prototype._feature_friday_ui=function(e,t,n){if(this.feature_friday&&this.feature_friday.channel!=e){this._emotes_for_sets(t,n,[this.feature_friday.set],"Feature Friday");var o=App.__container__.lookup("controller:channel");if(!o||o.get("id")!=this.feature_friday.channel){var i=this.feature_friday,r=document.createElement("div"),s=document.createElement("a");r.className="chat-menu-content",r.style.textAlign="center";var a=i.display_name+(i.live?" is live now!":"");s.className="button primary",s.classList.toggle("live",i.live),s.classList.toggle("blue",this.has_bttv&&BetterTTV.settings.get("showBlueButtons")),s.href="http://www.twitch.tv/"+i.channel,s.title=a,s.target="_new",s.innerHTML=""+a+"",r.appendChild(s),t.appendChild(r)}}},n.prototype._load_ff=function(e){if(this.feature_friday){this.global_sets.removeObject(this.feature_friday.set);var t=this.emote_sets[this.feature_friday.set];t&&(t.global=!1),this.feature_friday=null,this.update_ui_link()}e&&e.set&&e.channel&&(this.feature_friday={set:e.set,channel:e.channel,live:!1,display_name:n.get_capitalization(e.channel,this._update_ff_name.bind(this))},this.global_sets.push(e.set),this.load_set(e.set,this._update_ff_set.bind(this)),this._update_ff_live())},n.prototype._update_ff_live=function(){if(this.feature_friday){var e=this;Twitch.api.get("streams/"+this.feature_friday.channel).done(function(t){e.feature_friday.live=null!=t.stream,e.update_ui_link()}).always(function(){e.feature_friday.timer=setTimeout(e._update_ff_live.bind(e),12e4)})}},n.prototype._update_ff_set=function(e,t){t&&(t.global=!0)},n.prototype._update_ff_name=function(e){this.feature_friday&&(this.feature_friday.display_name=e)}},{"./constants":3}],15:[function(t){var n=e.FrankerFaceZ,o=t("./constants");make_ls=function(e){return"ffz_setting_"+e},toggle_setting=function(e,t){var n=!this.settings.get(t);this.settings.set(t,n),e.classList.toggle("active",n)},n.settings_info={},n.prototype.load_settings=function(){this.log("Loading settings."),this.settings={};for(var t in n.settings_info)if(n.settings_info.hasOwnProperty(t)){var o=n.settings_info[t],i=o.storage_key||make_ls(t),r=o.hasOwnProperty("value")?o.value:void 0;if(localStorage.hasOwnProperty(i))try{r=JSON.parse(localStorage.getItem(i))}catch(s){this.log('Error loading value for "'+t+'": '+s)}this.settings[t]=r}this.settings.get=this._setting_get.bind(this),this.settings.set=this._setting_set.bind(this),this.settings.del=this._setting_del.bind(this),e.addEventListener("storage",this._setting_update.bind(this),!1)},n.menu_pages.settings={render:function(e,t){var o={},i=[];for(var r in n.settings_info)if(n.settings_info.hasOwnProperty(r)){var s=n.settings_info[r],a=s.category||"Miscellaneous",l=o[a];if(void 0!==s.visible&&null!==s.visible){var c=s.visible;if("function"==typeof s.visible&&(c=s.visible.bind(this)()),!c)continue}l||(i.push(a),l=o[a]=[]),l.push([r,s])}i.sort(function(e,t){var e=e.toLowerCase(),t=t.toLowerCase();return"debugging"===e&&(e="zzz"+e),"debugging"===t&&(t="zzz"+t),t>e?-1:e>t?1:0});for(var u=0;un?-1:n>o?1:r>i?-1:i>r?1:0});for(var _=0;_",b.className="switch-label",b.innerHTML=s.name,f.appendChild(v),f.appendChild(b),v.addEventListener("click",toggle_setting.bind(this,v,r))}else{f.classList.add("option");var y=document.createElement("a");y.innerHTML=s.name,y.href="#",f.appendChild(y),y.addEventListener("click",s.method.bind(this))}if(s.help){var w=document.createElement("span");w.className="help",w.innerHTML=s.help,f.appendChild(w)}p.appendChild(f)}t.appendChild(p)}},name:"Settings",icon:o.GEAR,sort_order:99999},n.prototype._setting_update=function(t){if(t||(t=e.event),this.log("Storage Event",t),t.key&&"ffz_setting_"===t.key.substr(0,12)){var o=t.key,i=o.substr(12),r=void 0,s=n.settings_info[i];if(!s){for(i in n.settings_info)if(n.settings_info.hasOwnProperty(i)&&(s=n.settings_info[i],s.storage_key==o))break;if(s.storage_key!=o)return}this.log("Updated Setting: "+i);try{r=JSON.parse(t.newValue)}catch(a){this.log('Error loading new value for "'+i+'": '+a),r=s.value||void 0}if(this.settings[i]=r,s.on_update)try{s.on_update.bind(this)(r,!1)}catch(a){this.log('Error running updater for setting "'+i+'": '+a)}}},n.prototype._setting_get=function(e){return this.settings[e]},n.prototype._setting_set=function(e,t){var o=n.settings_info[e],i=o.storage_key||make_ls(e),r=JSON.stringify(t);if(this.settings[e]=t,localStorage.setItem(i,r),this.log('Changed Setting "'+e+'" to: '+r),o.on_update)try{o.on_update.bind(this)(t,!0)}catch(s){this.log('Error running updater for setting "'+e+'": '+s)}},n.prototype._setting_del=function(e){var t=n.settings_info[e],o=t.storage_key||make_ls(e),i=void 0;if(localStorage.hasOwnProperty(o)&&localStorage.removeItem(o),delete this.settings[e],t&&(i=this.settings[e]=t.hasOwnProperty("value")?t.value:void 0),t.on_update)try{t.on_update.bind(this)(i,!0)}catch(r){this.log('Error running updater for setting "'+e+'": '+r)}}},{"./constants":3}],16:[function(){Array.prototype.equals=function(e){if(!e)return!1;if(this.length!=e.length)return!1;for(var t=0,n=this.length;n>t;t++)if(this[t]instanceof Array&&e[t]instanceof Array){if(!this[t].equals(e[t]))return!1}else if(this[t]!=e[t])return!1;return!0}},{}],17:[function(){var t=e.FrankerFaceZ;t.prototype._ws_open=!1,t.prototype._ws_delay=0,t.ws_commands={},t.ws_on_close=[],t.prototype.ws_create=function(){var e,n=this;this._ws_last_req=0,this._ws_callbacks={},this._ws_pending=this._ws_pending||[];try{e=this._ws_sock=new WebSocket("ws://ffz.stendec.me/")}catch(o){return this._ws_exists=!1,this.log("Error Creating WebSocket: "+o)}this._ws_exists=!0,e.onopen=function(){n._ws_open=!0,n._ws_delay=0,n.log("Socket connected.");var e=n.get_user();e&&n.ws_send("setuser",e.login);for(var t in n.rooms)n.rooms.hasOwnProperty(t)&&n.ws_send("sub",t);var o=n._ws_pending;n._ws_pending=[];for(var i=0;i0){i=!0;break}}var l=document.createElement("div"),c="";c+="

FrankerFaceZ

",c+='
new ways to woof
',l.className="chat-menu-content center",l.innerHTML=c,t.appendChild(l);var u=document.createElement("div"),d=document.createElement("a"),h="To use custom emoticons in "+(i?"this channel":"tons of channels")+", get FrankerFaceZ from http://www.frankerfacez.com";d.className="button primary",d.innerHTML="Advertise in Chat",d.addEventListener("click",this._add_emote.bind(this,e,h)),u.appendChild(d);var p=document.createElement("a");p.className="button ffz-donate",p.href="http://www.frankerfacez.com/donate.html",p.target="_new",p.innerHTML="Donate",u.appendChild(p),u.className="chat-menu-content center",t.appendChild(u);var m=document.createElement("div");c='',c+='',c+='',c+='',c+='',m.className="chat-menu-content center",m.innerHTML=c;var _=!1;m.querySelector("#ffz-debug-logs").addEventListener("click",function(){_||(_=!0,r._pastebin(r._log_data.join("\n"),function(e){_=!1,e?prompt("Your FrankerFaceZ logs have been uploaded to the URL:",e):alert("There was an error uploading the FrankerFaceZ logs.")}))}),t.appendChild(m)}}},{"../constants":3}],19:[function(t){var n=e.FrankerFaceZ,o=t("../constants");n.settings_info.twitch_chat_dark={type:"boolean",value:!1,visible:!1},n.settings_info.dark_twitch={type:"boolean",value:!1,visible:function(){return!this.has_bttv},name:"Dark Twitch Beta",help:"Apply a dark background to channels and other related pages for easier viewing.",on_update:function(e){if(!this.has_bttv){document.body.classList.toggle("ffz-dark",e);var t=App.__container__.lookup("controller:settings").get("model");e?(this._load_dark_css(),this.settings.set("twitch_chat_dark",t.get("darkMode")),t.set("darkMode",!0)):t.set("darkMode",this.settings.twitch_chat_dark)}}},n.prototype.setup_dark=function(){this.has_bttv||(document.body.classList.toggle("ffz-dark",this.settings.dark_twitch),this.settings.dark_twitch&&App.__container__.lookup("controller:settings").set("model.darkMode",!0),this.settings.dark_twitch&&this._load_dark_css())},n.prototype._load_dark_css=function(){if(!this._dark_style){this.log("Injecting FrankerFaceZ Dark Twitch CSS.");var e=this._dark_style=document.createElement("link");e.id="ffz-dark-css",e.setAttribute("rel","stylesheet"),e.setAttribute("href",o.SERVER+"script/dark.css"),document.head.appendChild(e)}}},{"../constants":3}],20:[function(t){var n=e.FrankerFaceZ,o=t("../constants");n.prototype.setup_menu=function(){this.log("Installing mouse-up event to auto-close menus.");var e=this;jQuery(document).mouseup(function(t){var n,o=e._popup;o&&(o=jQuery(o),n=o.parent(),n.is(t.target)||0!==n.has(t.target).length||(o.remove(),delete e._popup,e._popup_kill&&e._popup_kill(),delete e._popup_kill))})},n.menu_pages={},n.prototype.build_ui_popup=function(e){var t=this._popup;if(t)return t.parentElement.removeChild(t),delete this._popup,this._popup_kill&&this._popup_kill(),void delete this._popup_kill;var i=document.createElement("div"),r=document.createElement("div"),s=document.createElement("ul"),a=this.has_bttv?BetterTTV.settings.get("darkenedMode"):!1;i.className="emoticon-selector chat-menu ffz-ui-popup",r.className="emoticon-selector-box dropmenu",i.appendChild(r),i.classList.toggle("dark",a);var l=document.createElement("div");l.className="ffz-ui-menu-page",r.appendChild(l),s.className="menu clearfix",r.appendChild(s);var c=document.createElement("li");c.className="title",c.innerHTML=""+(o.DEBUG?"[DEV] ":"")+"FrankerFaceZ",s.appendChild(c);var u=[];for(var d in n.menu_pages)if(n.menu_pages.hasOwnProperty(d)){var h=n.menu_pages[d];h&&(!h.hasOwnProperty("visible")||h.visible&&("function"!=typeof h.visible||h.visible.bind(this)()))&&u.push([h.sort_order||0,d,h])}u.sort(function(e,t){if(e[0]t[0])return-1;var n=e[1].toLowerCase(),o=t[1].toLowerCase();return o>n?1:n>o?-1:0});for(var p=0;p0){i=!0;break}}e.classList.toggle("no-emotes",!i),e.classList.toggle("live",a),e.classList.toggle("dark",r),e.classList.toggle("blue",s)}}},{"../constants":3}],22:[function(t){var n=e.FrankerFaceZ,o=t("../constants"),i="http://static-cdn.jtvnw.net/emoticons/v1/",r={"00000turbo":!0},s=function(e){var t=App.__container__.lookup("controller:chat"),n=t.get("currentRoom.id"),o=e.rooms[n],i=o?o.room.tmiSession:null,r=i&&i._emotesParser&&i._emotesParser.emoticonSetIds||"0",s=e.get_user(),a=s&&e.users[s.login]&&e.users[s.login].sets||[];return r=r.split(",").removeObject("0"),[r,a]};n.prototype.setup_my_emotes=function(){if(this._twitch_emote_sets={},this._twitch_set_to_channel={},localStorage.ffzTwitchSets)try{this._twitch_set_to_channel=JSON.parse(localStorage.ffzTwitchSets)}catch(e){}},n.menu_pages.my_emotes={name:"My Emoticons",icon:o.EMOTE,visible:function(){var e=s(this);return e[0].length>0||e[1].length>0},render:function(e,t){var o=s(this),a=this;new RSVP.Promise(function(e){for(var t=[],i=0;i0?(a.ws_send("twitch_sets",t,function(e,n){if(t=[],e){for(var o in n)n.hasOwnProperty(o)&&(a._twitch_set_to_channel[o]=n[o],s(o,n[o]));localStorage.ffzTwitchSets=JSON.stringify(a._twitch_set_to_channel)}l()}),setTimeout(function(){t.length&&l()},5e3)):l()})]).then(function(){for(var t={},n=0;nt[0])return 1;var n=e[1].toLowerCase(),o=t[1].toLowerCase();return"twitch turbo"===n&&(n="zzz"+n),"twitch turbo"===o&&(o="zzz"+o),o>n?-1:n>o?1:0});for(var c=0;c'+l.source+""+n.get_capitalization(l.channel),l.badge&&(u.style.backgroundImage='url("'+l.badge+'")'),d.className="emoticon-grid",d.appendChild(u);for(var h=0;hSpeedRunsLive races under channels.',on_update:function(){this.rebuild_race_ui()}},n.ws_on_close.push(function(){var e=App.__container__.lookup("controller:channel"),t=e.get("id"),n=!1;for(var o in this.srl_races)delete this.srl_races[o],o==t&&(n=!0);n&&this.rebuild_race_ui()}),n.ws_commands.srl_race=function(e){for(var t=App.__container__.lookup("controller:channel"),n=t.get("id"),o=!1,i=0;i=300?"right":"left")+" share dropmenu",this._popup_kill=this._race_kill.bind(this),this._popup=e;var l="http://kadgar.net/live",c=!1;for(var u in s.entrants){var d=s.entrants[u].state;s.entrants.hasOwnProperty(u)&&s.entrants[u].channel&&("racing"==d||"entered"==d)&&(l+="/"+s.entrants[u].channel,c=!0)}var h=document.querySelector(".app-main.theatre")?document.body.clientHeight-300:t.parentElement.offsetTop-175,p=App.__container__.lookup("controller:channel"),m=p?p.get("display_name"):n.get_capitalization(r),_=encodeURIComponent("I'm watching "+m+" race "+s.goal+" in "+s.game+" on SpeedRunsLive!");a='
',a+='
Developers
Dan Salvato  
Stendec  
Version '+n.version_info+'Logs
',a+="
#Entrant Time
",a+='
',a+='',a+='

SRL',c&&(a+='   Multitwitch'),a+="

",e.innerHTML=a,t.appendChild(e),this._update_race(!0)}}},n.prototype._update_race=function(e){this._race_timer&&e&&(clearTimeout(this._race_timer),delete this._race_timer);var t=document.querySelector("#ffz-ui-race");if(t){var n=t.getAttribute("data-channel"),i=this.srl_races[n];if(!i)return t.parentElement.removeChild(t),this._popup_kill&&this._popup_kill(),void(this._popup&&(delete this._popup,delete this._popup_kill));var r=i.twitch_entrants[n],s=i.entrants[r],a=t.querySelector("#ffz-race-popup"),l=Date.now()/1e3,c=Math.floor(l-i.time);if(t.querySelector(".logo").innerHTML=o.placement(s),a){var u=a.querySelector("tbody"),d=a.querySelector(".heading span"),h=a.querySelector(".heading div");u.innerHTML="";var p=[],m=!0;for(var _ in i.entrants)i.entrants.hasOwnProperty(_)&&("racing"==i.entrants[_].state&&(m=!1),p.push(i.entrants[_]));p.sort(function(e,t){var n=e.place||9999,o=t.place||9999,i=e.time||c,r=t.time||c;return("forfeit"==e.state||"dq"==e.state)&&(n=1e4),("forfeit"==t.state||"dq"==t.state)&&(o=1e4),o>n?-1:n>o?1:e.namet.name?1:r>i?-1:i>r?1:void 0});for(var f=0;f'+_.display_name+"",v=_.channel?'':"",b=_.hitbox?'':"",y=c?o.time_to_string(_.time||c):"",w=o.place_string(_.place),k=_.comment?o.sanitize(_.comment):"";u.innerHTML+="'+w+""+g+""+v+b+''+("forfeit"==_.state?"Forfeit":y)+""}if(this._race_game!=i.game||this._race_goal!=i.goal){this._race_game=i.game,this._race_goal=i.goal;var F=o.sanitize(i.game),E=o.sanitize(i.goal);h.innerHTML='

'+F+"

Goal: "+E}c?m?d.innerHTML="Done":(d.innerHTML=o.time_to_string(c),this._race_timer=setTimeout(this._update_race.bind(this),1e3)):d.innerHTML="Entry Open"}}}},{"../utils":27}],25:[function(t){var n=e.FrankerFaceZ,o=t("../constants");n.prototype.setup_css=function(){this.log("Injecting main FrankerFaceZ CSS.");var e=this._main_style=document.createElement("link");e.id="ffz-ui-css",e.setAttribute("rel","stylesheet"),e.setAttribute("href",o.SERVER+"script/style.css?_="+Date.now()),document.head.appendChild(e),jQuery.noty.themes.ffzTheme={name:"ffzTheme",style:function(){this.$bar.removeClass().addClass("noty_bar").addClass("ffz-noty").addClass(this.options.type)},callback:{onShow:function(){},onClose:function(){}}}}},{"../constants":3}],26:[function(t){var n=e.FrankerFaceZ,o=t("../constants"),i=t("../utils");n.ws_commands.viewers=function(e){var t=e[0],n=e[1],r=App.__container__.lookup("controller:channel"),s=r&&r.get&&r.get("id");if(s===t){var a=document.querySelector(".channel-stats .ffz.stat"),l=o.ZREKNARF+" "+i.number_commas(n);if(a)a.innerHTML=l;else{var c=document.querySelector(".channel-stats");if(!c)return;a=document.createElement("span"),a.className="ffz stat",a.title="Viewers with FrankerFaceZ",a.innerHTML=l,c.appendChild(a),jQuery(a).tipsy()}}}},{"../constants":3,"../utils":27}],27:[function(t,n){var o=(e.FrankerFaceZ,t("./constants"),{}),i=document.createElement("span"),r=function(e){return 1==e?"1st":2==e?"2nd":3==e?"3rd":null==e?"---":e+"th"},s=function(e,t){t=0===t?0:t||1,t=Math.round(255*-(t/100));var n=Math.max(0,Math.min(255,e[0]-t)),o=Math.max(0,Math.min(255,e[1]-t)),i=Math.max(0,Math.min(255,e[2]-t));return[n,o,i]},a=function(e){return"rgb("+e[0]+", "+e[1]+", "+e[2]+")"},l=function(e,t){return t=0===t?0:t||1,s(e,-t)},c=function(e){e=[e[0]/255,e[1]/255,e[2]/255];for(var t=0;ts;(l||n)&&(l&&(o=o.substr(0,s)+o.substr(a+r.length)),n&&(o+=i+n+r),e.innerHTML=o)},get_luminance:c,brighten:s,darken:l,rgb_to_css:a,number_commas:function(e){var t=e.toString().split(".");return t[0]=t[0].replace(/\B(?=(\d{3})+(?!\d))/g,","),t.join(".")},place_string:r,placement:function(e){return"forfeit"==e.state?"Forfeit":"dq"==e.state?"DQed":e.place?r(e.place):""},sanitize:function(e){var t=o[e];return t||(i.textContent=e,t=o[e]=i.innerHTML,i.innerHTML=""),t},time_to_string:function(e){var t=e%60,n=Math.floor(e/60),o=Math.floor(n/60);return n%=60,(10>o?"0":"")+o+":"+(10>n?"0":"")+n+":"+(10>t?"0":"")+t}}},{"./constants":3}]},{},[13]),e.ffz=new FrankerFaceZ}(window); \ No newline at end of file +!function(e){!function t(e,n,o){function i(r,a){if(!n[r]){if(!e[r]){var l="function"==typeof require&&require;if(!a&&l)return l(r,!0);if(s)return s(r,!0);throw new Error("Cannot find module '"+r+"'")}var c=n[r]={exports:{}};e[r][0].call(c.exports,function(t){var n=e[r][1][t];return i(n?n:t)},c,c.exports,t,e,n,o)}return n[r].exports}for(var s="function"==typeof require&&require,r=0;re?this._legacy_add_donors(e):void 0):void 0})},n.prototype._legacy_parse_donors=function(e){var t=0;if(null!=e)for(var n=e.trim().split(/\W+/),o=0;o50)return"Each user you unmod counts as a single message. To avoid being globally banned, please limit yourself to 50 at a time and wait between uses.";for(var o=t.length;t.length;){var i=t.shift();e.room.tmiRoom.sendMessage("/unmod "+i)}return"Sent unmod command for "+o+" users."},t.ffz_commands.massunmod.help="Usage: /ffz massunmod \nBroadcaster only. Unmod all the users in the provided list.",t.ffz_commands.massmod=function(e,t){if(t=t.join(" ").trim(),!t.length)return"You must provide a list of users to mod.";t=t.split(/\W*,\W*/);var n=this.get_user();if(!n||!n.login==e.id)return"You must be the broadcaster to use massmod.";if(t.length>50)return"Each user you mod counts as a single message. To avoid being globally banned, please limit yourself to 50 at a time and wait between uses.";for(var o=t.length;t.length;){var i=t.shift();e.room.tmiRoom.sendMessage("/mod "+i)}return"Sent mod command for "+o+" users."},t.ffz_commands.massmod.help="Usage: /ffz massmod \nBroadcaster only. Mod all the users in the provided list."},{}],3:[function(e,t){var n='',o="true"==localStorage.ffzDebugMode&&document.body.classList.contains("ffz-dev");t.exports={DEBUG:o,SERVER:o?"//localhost:8000/":"//cdn.frankerfacez.com/",SVGPATH:n,ZREKNARF:''+n+"",CHAT_BUTTON:''+n+"",GEAR:'',HEART:'',EMOTE:''}},{}],4:[function(){var t=e.FrankerFaceZ;t.settings_info.developer_mode={type:"boolean",value:!1,storage_key:"ffzDebugMode",visible:function(){return this.settings.developer_mode||Date.now()-parseInt(localStorage.ffzLastDevMode||"0")<6048e5},category:"Debugging",name:"Developer Mode",help:"Load FrankerFaceZ from the local development server instead of the CDN. Please refresh after changing this setting.",on_update:function(){localStorage.ffzLastDevMode=Date.now()}},t.ffz_commands.developer_mode=function(e,t){var n,t=t&&t.length?t[0].toLowerCase():null;return"y"==t||"yes"==t||"true"==t||"on"==t?n=!0:("n"==t||"no"==t||"false"==t||"off"==t)&&(n=!1),void 0===n?"Developer Mode is currently "+(this.settings.developer_mode?"enabled.":"disabled."):(this.settings.set("developer_mode",n),"Developer Mode is now "+(n?"enabled":"disabled")+". Please refresh your browser.")},t.ffz_commands.developer_mode.help="Usage: /ffz developer_mode \nEnable or disable Developer Mode. When Developer Mode is enabled, the script will be reloaded from //localhost:8000/script.js instead of from the CDN."},{}],5:[function(){var t=e.FrankerFaceZ;t.prototype.setup_chatview=function(){this.log("Hooking the Ember Chat view.");var e=App.__container__.resolve("view:chat");this._modify_cview(e);try{e.create().destroy()}catch(t){}for(var n in Ember.View.views)if(Ember.View.views.hasOwnProperty(n)){var o=Ember.View.views[n];if(o instanceof e){this.log("Adding UI link manually to Chat view.",o);try{o.$(".textarea-contain").append(this.build_ui_link(o))}catch(t){this.error("setup: build_ui_link: "+t)}}}},t.prototype._modify_cview=function(e){var t=this;e.reopen({didInsertElement:function(){this._super();try{this.$()&&this.$(".textarea-contain").append(t.build_ui_link(this))}catch(e){t.error("didInsertElement: build_ui_link: "+e)}},willClearRender:function(){this._super();try{this.$(".ffz-ui-toggle").remove()}catch(e){t.error("willClearRender: remove ui link: "+e)}},ffzUpdateLink:Ember.observer("controller.currentRoom",function(){try{t.update_ui_link()}catch(e){t.error("ffzUpdateLink: update_ui_link: "+e)}})})}},{}],6:[function(t){var n=e.FrankerFaceZ,o=t("../utils"),i=function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},s="[\\s`~<>!-#%-\\x2A,-/:;\\x3F@\\x5B-\\x5D_\\x7B}\\u00A1\\u00A7\\u00AB\\u00B6\\u00B7\\u00BB\\u00BF\\u037E\\u0387\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061E\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u0AF0\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166D\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u2329\\u232A\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E3B\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uAAF0\\uAAF1\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65]",r=new RegExp(s+"*,"+s+"*"),a=function(e){return(e+"").replace(/&/g,"&").replace(/'/g,"'").replace(/"/g,""").replace(//g,">")},l="http://static-cdn.jtvnw.net/emoticons/v1/",c=function(e){return l+e+"/1.0 1x, "+l+e+"/2.0 2x, "+l+e+"/3.0 4x"},u=function(e){var t=e.set,n=e.set_type;return void 0===n&&(n="Channel"),t?(("00000turbo"==t||"turbo"==t)&&(t="Twitch Turbo",n=null),"Emoticon: "+e.code+"\n"+(n?n+": ":"")+t):e.code},d=function(e){{var t=this._twitch_emotes[e];t?t.set:null}return t?"string"==typeof t?t:t.tooltip?t.tooltip:t.tooltip=u(t):"???"},h=function(e,t,n,o){if(n){t&&(o.code=t),this._twitch_emotes[e]=o;for(var i=d.bind(this)(e),s=document.querySelectorAll('img[emote-id="'+e+'"]'),r=0;r5&&i.log("Tokenizing Message Took Too Long - "+(o-t)+"ms - "+JSON.stringify(e))}catch(s){try{i.error("LineController tokenizedMessage: "+s)}catch(s){}}return e}.property("model.message","isModeratorOrHigher")}),this.log("Hooking the Ember Line view.");var o=App.__container__.resolve("view:line");o.reopen({didInsertElement:function(){this._super();try{var t=performance.now(),o=this.get("element"),s=this.get("context"),r=s.get("model.from"),a=s.get("parentController.content.id"),l=s.get("model.color"),d=s.get("model.ffz_alternate");l&&i._handle_color(l),void 0===d&&(d=i._last_row[a]=i._last_row.hasOwnProperty(a)?!i._last_row[a]:!1,this.set("context.model.ffz_alternate",d)),o.classList.toggle("ffz-alternate",d),o.setAttribute("data-room",a),o.setAttribute("data-sender",r),i.render_badge(this),i.settings.capitalize&&i.capitalize(this,r);var m=o.querySelector("span.mentioned");if(m&&(o.classList.add("ffz-mentioned"),i.settings.highlight_notifications&&!document.hasFocus()&&!this.get("context.model.ffz_notified"))){var _=n.get_capitalization(a),p=n.get_capitalization(r),f=_,g=this.get("context.model.message");this.get("context.parentController.content.isGroupRoom")&&(f=this.get("context.parentController.content.tmiRoom.displayName")),g="action"==this.get("context.model.style")?"* "+p+" "+g:p+": "+g,i.show_notification(g,"Twitch Chat Mention in "+f,_,6e4,e.focus.bind(e))}this.set("context.model.ffz_notified",!0);for(var v=o.querySelectorAll("a.deleted-link"),b=0;b-1&&(-1===t.indexOf("/")||t.indexOf("@")5&&i.log("Line Took Too Long - "+M+"ms - "+o.innerHTML)}catch(D){try{i.error("LineView didInsertElement: "+D)}catch(D){}}}});var s=this.get_user();s&&s.name&&(n.capitalization[s.login]=[s.name,Date.now()])},n.prototype._handle_color=function(e){if(e&&!this._colors[e]){this._colors[e]=!0;var t=parseInt(e.substr(1),16),n=[t>>16,t>>8&255,255&t],i=o.get_luminance(n),s="",r='span[style="color:'+e+'"]',a=!1;if(i>.3){a=!0;for(var l=127,c=n;l--&&(c=o.darken(c),!(o.get_luminance(c)<=.3)););s+=".ffz-chat-colors .ember-chat-container:not(.dark) .chat-line "+r+", .ffz-chat-colors .chat-container:not(.dark) .chat-line "+r+" { color: "+o.rgb_to_css(c)+" !important; }\n"}else s+=".ffz-chat-colors .ember-chat-container:not(.dark) .chat-line "+r+", .ffz-chat-colors .chat-container:not(.dark) .chat-line "+r+" { color: "+e+" !important; }\n";if(.15>i){a=!0;for(var l=127,c=n;l--&&(c=o.brighten(c),!(o.get_luminance(c)>=.15)););s+=".ffz-chat-colors .theatre .chat-container .chat-line "+r+", .ffz-chat-colors .chat-container.dark .chat-line "+r+", .ffz-chat-colors .ember-chat-container.dark .chat-line "+r+" { color: "+o.rgb_to_css(c)+" !important; }\n"}else s+=".ffz-chat-colors .theatre .chat-container .chat-line "+r+", .ffz-chat-colors .chat-container.dark .chat-line "+r+", .ffz-chat-colors .ember-chat-container.dark .chat-line "+r+" { color: "+e+" !important; }\n";a&&(this._fix_color_style.innerHTML+=s)}},n.capitalization={},n._cap_fetching=0,n.get_capitalization=function(t,o){if(e.BetterTTV&&BetterTTV.chat&&BetterTTV.chat.helpers.lookupDisplayName)return BetterTTV.chat.helpers.lookupDisplayName(t);if(!t)return t;if(t=t.toLowerCase(),"jtv"==t||"twitchnotify"==t)return t;var i=n.capitalization[t];return i&&Date.now()-i[1]<36e5?i[0]:(n._cap_fetching<25&&(n._cap_fetching++,n.get().ws_send("get_display_name",t,function(e,i){var s=e?i:t;n.capitalization[t]=[s,Date.now()],n._cap_fetching--,"function"==typeof o&&o(s)})),i?i[0]:t)},n.prototype.capitalize=function(e,t){var o=n.get_capitalization(t,this.capitalize.bind(this,e));if(o&&e){var i=e.$(".from");i&&i.text(o)}},n._regex_cache={},n._get_regex=function(e){return n._regex_cache[e]=n._regex_cache[e]||RegExp("\\b"+i(e)+"\\b","ig")},n._words_to_regex=function(e){var t=n._regex_cache[e];if(!t){for(var o="",r=0;r<banned link>',own:!0}:r)}return i},n.prototype._emoticonize=function(e,t){var n=e.get("parentController.model.id"),o=e.get("model.from"),i=this,s=this.getEmotes(o,n),r=[];return _.each(s,function(e){var n=i.emote_sets[e];n&&_.each(n.emotes,function(e){_.any(t,function(t){return _.isString(t)&&t.match(e.regex)})&&r.push(e)})}),r.length?("string"==typeof t&&(t=[t]),_.each(r,function(e){var n={isEmoticon:!0,cls:e.klass,emoticonSrc:e.url+'" data-ffz-emote="'+encodeURIComponent(JSON.stringify([e.id,e.set_id])),altText:e.hidden?"???":e.name};t=_.compact(_.flatten(_.map(t,function(t){if(_.isObject(t))return t;var o=t.split(e.regex),i=[];return o.forEach(function(e,t){i.push(e),t!==o.length-1&&i.push(n)}),i})))}),t):t}},{"../utils":27}],7:[function(t){var n=e.FrankerFaceZ,o=t("../utils"),i={ESC:27,P:80,B:66,T:84},s=[["5m",300],["10m",600],["1hr",3600],["12hr",43200],["24hr",86400]],r='',a='';n.settings_info.enhanced_moderation={type:"boolean",value:!1,visible:function(){return!this.has_bttv},category:"Chat",name:"Enhanced Moderation",help:"Use /p, /t, /u and /b in chat to moderate chat, or use hotkeys with moderation cards."},n.prototype.setup_mod_card=function(){this.log("Hooking the Ember Moderation Card view.");var e=App.__container__.resolve("view:moderation-card"),t=this;e.reopen({didInsertElement:function(){this._super();try{if(t.has_bttv||!t.settings.enhanced_moderation)return;var e=this.get("element"),n=this.get("context");if(e.classList.add("ffz-moderation-card"),n.get("parentController.model.isModeratorOrHigher")){e.classList.add("ffz-is-mod"),e.setAttribute("tabindex",1),e.addEventListener("keyup",function(e){var t=e.keyCode||e.which,o=n.get("model.user.id"),s=n.get("parentController.model");if(t==i.P)s.send("/timeout "+o+" 1");else if(t==i.B)s.send("/ban "+o);else if(t==i.T)s.send("/timeout "+o+" 600");else if(t!=i.ESC)return;n.send("hideModOverlay")});var l=document.createElement("div");l.className="interface clearfix";var c=function(e){var t=n.get("model.user.id"),o=n.get("parentController.model");o.send(-1===e?"/unban "+t:"/timeout "+t+" "+e)},u=function(e,t){var n=document.createElement("button");return n.className="button",n.innerHTML=e,n.title="Timeout User for "+o.number_commas(t)+" Second"+(1!=t?"s":""),600===t?n.title="(T)"+n.title.substr(1):1===t&&(n.title="(P)urge - "+n.title),jQuery(n).tipsy(),n.addEventListener("click",c.bind(this,t)),n};l.appendChild(u("Purge",1));var d=document.createElement("span");d.className="right",l.appendChild(d);for(var h=0;h button");v&&"button"==v.className&&(v.innerHTML=r,v.classList.add("glyph-only"),v.classList.add("message"),v.title="Message User",jQuery(v).tipsy()),this.$().draggable({start:function(){e.focus()}}),e.focus()}catch(b){try{t.error("ModerationCardView didInsertElement: "+b)}catch(b){}}}})},n.chat_commands.purge=n.chat_commands.p=function(e,t){if(!t||!t.length)return"Purge Usage: /p username [more usernames separated by spaces]";if(t.length>10)return"Please only purge up to 10 users at once.";for(var n=0;n10)return"Please only ban up to 10 users at once.";for(var n=0;n10)return"Please only unban up to 10 users at once.";for(var n=0;nn?this._legacy_add_room(e,t,n):void 0)})},n.prototype._legacy_load_room_css=function(e,t,n){var r=e,a=r.match(s);a&&a[1]&&(r=a[1]);var l={id:e,menu_sets:[r],sets:[r],moderator_badge:null,css:null};return n&&(n=n.replace(o,"").trim()),n&&(n=n.replace(i,function(e,t){return l.moderator_badge||"modicon.png"!==t.substr(-11)?e:(l.moderator_badge=t,"")})),l.css=n||null,this._load_room_json(e,t,l)}},{"../constants":3,"../utils":27}],9:[function(){var t=e.FrankerFaceZ;t.prototype.setup_viewers=function(){this.log("Hooking the Ember Viewers controller.");var e=App.__container__.resolve("controller:viewers");this._modify_viewers(e)},t.prototype._modify_viewers=function(e){var n=this;e.reopen({lines:function(){var e=this._super();try{var o=[],i={},s=null,r=App.__container__.lookup("controller:channel"),a=this.get("parentController.model.id"),l=r&&r.get("id");if(l){var c=r.get("display_name");c&&(t.capitalization[l]=[c,Date.now()])}a!=l&&(l=null);for(var u=0;un?this._legacy_load_set(e,t,n):"function"==typeof t&&t(!1))})},n.prototype._legacy_load_css=function(e,t,n){var s={},r={id:e,emotes:s,extra_css:null},a=this;n=n.replace(o,function(t,n,o,i,r,c,u,d){r=parseInt(r),c=parseInt(c),u=l(u,r);var h="."===i.substr(i.lastIndexOf("/")+1,1),m=++a._last_emote_id,_={id:m,set_id:e,hidden:h,name:o,height:r,width:c,url:i,margins:u,extra_css:d};return s[m]=_,""}).trim(),n&&n.replace(i,function(e,t){r.icon||"modicon.png"!==t.substr(-11)||(r.icon=t)}),this._load_set_json(e,t,r)}},{"./constants":3,"./utils":27}],11:[function(){var t=e.FrankerFaceZ,n=/(\sdata-sender="[^"]*"(?=>))/;t.prototype.find_bttv=function(t,n){return this.has_bttv=!1,e.BTTVLOADED?this.setup_bttv(n||0):void(n>=6e4?this.log("BetterTTV was not detected after 60 seconds."):setTimeout(this.find_bttv.bind(this,t,(n||0)+t),t))},t.prototype.setup_bttv=function(e){this.log("BetterTTV was detected after "+e+"ms. Hooking."),this.has_bttv=!0,document.body.classList.remove("ffz-dark"),this._dark_style&&(this._dark_style.parentElement.removeChild(this._dark_style),delete this._dark_style),document.body.classList.remove("ffz-chat-colors"),document.body.classList.remove("ffz-chat-background");var t=BetterTTV.chat.helpers.sendMessage,o=this;BetterTTV.chat.helpers.sendMessage=function(e){var n=e.split(" ",1)[0].toLowerCase();return"/ffz"!==n?t(e):void o.run_ffz_command(e.substr(5),BetterTTV.chat.store.currentRoom)};var i,s=BetterTTV.chat.handlers.privmsg;BetterTTV.chat.handlers.privmsg=function(e,t){i=e;var n=s(e,t);return i=null,n};var r=BetterTTV.chat.templates.privmsg;BetterTTV.chat.templates.privmsg=function(e,t,s,a,l){o.bttv_badges(l);var c=r(e,t,s,a,l);return c.replace(n,'$1 data-room="'+i+'"')};var a,l=BetterTTV.chat.templates.message;BetterTTV.chat.templates.message=function(e,t,n,o){a=e;var i=l(e,t,n,o);return a=null,i};var c=BetterTTV.chat.templates.emoticonize;BetterTTV.chat.templates.emoticonize=function(e,t){var n=c(e,t),s=o.getEmotes(a,i),t=[];return _.each(s,function(e){var i=o.emote_sets[e];i&&_.each(i.emotes,function(e){_.any(n,function(t){return _.isString(t)&&t.match(e.regex)})&&t.push(e)})}),t.length?(_.each(t,function(e){var t=[''+e.name+''],o=n;if(n=[],!o||!o.length)return n;for(var i=0;i=6e4?this.log("Emote Menu for Twitch was not detected after 60 seconds."):setTimeout(this.find_emote_menu.bind(this,t,(n||0)+t),t))},t.prototype.setup_emote_menu=function(e){this.log("Emote Menu for Twitch was detected after "+e+"ms. Registering emote enumerator."),emoteMenu.registerEmoteGetter("FrankerFaceZ",this._emote_menu_enumerator.bind(this))},t.prototype._emote_menu_enumerator=function(){for(var e=this.get_user(),n=e?e.login:null,o=App.__container__.lookup("controller:chat"),i=o?o.get("currentRoom.id"):null,s=this.getEmotes(n,i),r=[],a=0;a=6e4?this.log('Twitch application not detected in "'+location.toString()+'". Aborting.'):setTimeout(this.initialize.bind(this,t,(n||0)+t),t)))},n.prototype.setup_ember=function(t){var o=e.performance&&performance.now?performance.now():Date.now();this.log("Found Twitch application after "+(t||0)+' ms in "'+location+'". Initializing FrankerFaceZ version '+n.version_info),this.users={},this.load_settings(),this.setup_dark(),this.ws_create(),this.setup_emoticons(),this.setup_badges(),this.setup_room(),this.setup_line(),this.setup_chatview(),this.setup_viewers(),this.setup_mod_card(),this.setup_notifications(),this.setup_css(),this.setup_menu(),this.setup_my_emotes(),this.setup_races(),this.find_bttv(10),this.find_emote_menu(10),this.check_ff();var i=e.performance&&performance.now?performance.now():Date.now(),s=i-o;this.log("Initialization complete in "+s+"ms")}},{"./badges":1,"./commands":2,"./debug":4,"./ember/chatview":5,"./ember/line":6,"./ember/moderation-card":7,"./ember/room":8,"./ember/viewers":9,"./emoticons":10,"./ext/betterttv":11,"./ext/emote_menu":12,"./featurefriday":14,"./settings":15,"./shims":16,"./socket":17,"./ui/about_page":18,"./ui/dark":19,"./ui/menu":20,"./ui/menu_button":21,"./ui/my_emotes":22,"./ui/notifications":23,"./ui/races":24,"./ui/styles":25,"./ui/viewer_count":26}],14:[function(t){var n=e.FrankerFaceZ,o=t("./constants");n.prototype.feature_friday=null,n.prototype.check_ff=function(e){e||this.log("Checking for Feature Friday data..."),jQuery.ajax(o.SERVER+"script/event.json",{cache:!1,dataType:"json",context:this}).done(function(e){return this._load_ff(e)}).fail(function(t){return 404==t.status?this._load_ff(null):(e=e||0,e++,10>e?setTimeout(this.check_ff.bind(this,e),250):this._load_ff(null))})},n.ws_commands.reload_ff=function(){this.check_ff()},n.prototype._feature_friday_ui=function(e,t,n){if(this.feature_friday&&this.feature_friday.channel!=e){this._emotes_for_sets(t,n,[this.feature_friday.set],"Feature Friday");var o=App.__container__.lookup("controller:channel");if(!o||o.get("id")!=this.feature_friday.channel){var i=this.feature_friday,s=document.createElement("div"),r=document.createElement("a");s.className="chat-menu-content",s.style.textAlign="center";var a=i.display_name+(i.live?" is live now!":"");r.className="button primary",r.classList.toggle("live",i.live),r.classList.toggle("blue",this.has_bttv&&BetterTTV.settings.get("showBlueButtons")),r.href="http://www.twitch.tv/"+i.channel,r.title=a,r.target="_new",r.innerHTML=""+a+"",s.appendChild(r),t.appendChild(s)}}},n.prototype._load_ff=function(e){if(this.feature_friday){this.global_sets.removeObject(this.feature_friday.set);var t=this.emote_sets[this.feature_friday.set];t&&(t.global=!1),this.feature_friday=null,this.update_ui_link()}e&&e.set&&e.channel&&(this.feature_friday={set:e.set,channel:e.channel,live:!1,display_name:n.get_capitalization(e.channel,this._update_ff_name.bind(this))},this.global_sets.push(e.set),this.load_set(e.set,this._update_ff_set.bind(this)),this._update_ff_live())},n.prototype._update_ff_live=function(){if(this.feature_friday){var e=this;Twitch.api.get("streams/"+this.feature_friday.channel).done(function(t){e.feature_friday.live=null!=t.stream,e.update_ui_link()}).always(function(){e.feature_friday.timer=setTimeout(e._update_ff_live.bind(e),12e4)})}},n.prototype._update_ff_set=function(e,t){t&&(t.global=!0)},n.prototype._update_ff_name=function(e){this.feature_friday&&(this.feature_friday.display_name=e)}},{"./constants":3}],15:[function(t){var n=e.FrankerFaceZ,o=t("./constants");make_ls=function(e){return"ffz_setting_"+e},toggle_setting=function(e,t){var n=!this.settings.get(t);this.settings.set(t,n),e.classList.toggle("active",n)},n.settings_info={},n.prototype.load_settings=function(){this.log("Loading settings."),this.settings={};for(var t in n.settings_info)if(n.settings_info.hasOwnProperty(t)){var o=n.settings_info[t],i=o.storage_key||make_ls(t),s=o.hasOwnProperty("value")?o.value:void 0;if(localStorage.hasOwnProperty(i))try{s=JSON.parse(localStorage.getItem(i))}catch(r){this.log('Error loading value for "'+t+'": '+r)}this.settings[t]=s}this.settings.get=this._setting_get.bind(this),this.settings.set=this._setting_set.bind(this),this.settings.del=this._setting_del.bind(this),e.addEventListener("storage",this._setting_update.bind(this),!1)},n.menu_pages.settings={render:function(e,t){var o={},i=[];for(var s in n.settings_info)if(n.settings_info.hasOwnProperty(s)){var r=n.settings_info[s],a=r.category||"Miscellaneous",l=o[a];if(void 0!==r.visible&&null!==r.visible){var c=r.visible;if("function"==typeof r.visible&&(c=r.visible.bind(this)()),!c)continue}l||(i.push(a),l=o[a]=[]),l.push([s,r])}i.sort(function(e,t){var e=e.toLowerCase(),t=t.toLowerCase();return"debugging"===e&&(e="zzz"+e),"debugging"===t&&(t="zzz"+t),t>e?-1:e>t?1:0});for(var u=0;un?-1:n>o?1:s>i?-1:i>s?1:0});for(var p=0;p",b.className="switch-label",b.innerHTML=r.name,f.appendChild(v),f.appendChild(b),v.addEventListener("click",toggle_setting.bind(this,v,s))}else{f.classList.add("option");var y=document.createElement("a");y.innerHTML=r.name,y.href="#",f.appendChild(y),y.addEventListener("click",r.method.bind(this))}if(r.help){var w=document.createElement("span");w.className="help",w.innerHTML=r.help,f.appendChild(w)}m.appendChild(f)}t.appendChild(m)}},name:"Settings",icon:o.GEAR,sort_order:99999},n.prototype._setting_update=function(t){if(t||(t=e.event),this.log("Storage Event",t),t.key&&"ffz_setting_"===t.key.substr(0,12)){var o=t.key,i=o.substr(12),s=void 0,r=n.settings_info[i];if(!r){for(i in n.settings_info)if(n.settings_info.hasOwnProperty(i)&&(r=n.settings_info[i],r.storage_key==o))break;if(r.storage_key!=o)return}this.log("Updated Setting: "+i);try{s=JSON.parse(t.newValue)}catch(a){this.log('Error loading new value for "'+i+'": '+a),s=r.value||void 0}if(this.settings[i]=s,r.on_update)try{r.on_update.bind(this)(s,!1)}catch(a){this.log('Error running updater for setting "'+i+'": '+a)}}},n.prototype._setting_get=function(e){return this.settings[e]},n.prototype._setting_set=function(e,t){var o=n.settings_info[e],i=o.storage_key||make_ls(e),s=JSON.stringify(t);if(this.settings[e]=t,localStorage.setItem(i,s),this.log('Changed Setting "'+e+'" to: '+s),o.on_update)try{o.on_update.bind(this)(t,!0)}catch(r){this.log('Error running updater for setting "'+e+'": '+r)}},n.prototype._setting_del=function(e){var t=n.settings_info[e],o=t.storage_key||make_ls(e),i=void 0;if(localStorage.hasOwnProperty(o)&&localStorage.removeItem(o),delete this.settings[e],t&&(i=this.settings[e]=t.hasOwnProperty("value")?t.value:void 0),t.on_update)try{t.on_update.bind(this)(i,!0)}catch(s){this.log('Error running updater for setting "'+e+'": '+s)}}},{"./constants":3}],16:[function(){Array.prototype.equals=function(e){if(!e)return!1;if(this.length!=e.length)return!1;for(var t=0,n=this.length;n>t;t++)if(this[t]instanceof Array&&e[t]instanceof Array){if(!this[t].equals(e[t]))return!1}else if(this[t]!=e[t])return!1;return!0}},{}],17:[function(){var t=e.FrankerFaceZ;t.prototype._ws_open=!1,t.prototype._ws_delay=0,t.ws_commands={},t.ws_on_close=[],t.prototype.ws_create=function(){var e,n=this;this._ws_last_req=0,this._ws_callbacks={},this._ws_pending=this._ws_pending||[];try{e=this._ws_sock=new WebSocket("ws://ffz.stendec.me/")}catch(o){return this._ws_exists=!1,this.log("Error Creating WebSocket: "+o)}this._ws_exists=!0,e.onopen=function(){n._ws_open=!0,n._ws_delay=0,n.log("Socket connected.");var e=n.get_user();e&&n.ws_send("setuser",e.login);for(var t in n.rooms)n.rooms.hasOwnProperty(t)&&n.ws_send("sub",t);var o=n._ws_pending;n._ws_pending=[];for(var i=0;i0){i=!0;break}}var l=document.createElement("div"),c="";c+="

FrankerFaceZ

",c+='
new ways to woof
',l.className="chat-menu-content center",l.innerHTML=c,t.appendChild(l);var u=document.createElement("div"),d=document.createElement("a"),h="To use custom emoticons in "+(i?"this channel":"tons of channels")+", get FrankerFaceZ from http://www.frankerfacez.com";d.className="button primary",d.innerHTML="Advertise in Chat",d.addEventListener("click",this._add_emote.bind(this,e,h)),u.appendChild(d);var m=document.createElement("a");m.className="button ffz-donate",m.href="http://www.frankerfacez.com/donate.html",m.target="_new",m.innerHTML="Donate",u.appendChild(m),u.className="chat-menu-content center",t.appendChild(u);var _=document.createElement("div");c='',c+='',c+='',c+='',c+='',_.className="chat-menu-content center",_.innerHTML=c;var p=!1;_.querySelector("#ffz-debug-logs").addEventListener("click",function(){p||(p=!0,s._pastebin(s._log_data.join("\n"),function(e){p=!1,e?prompt("Your FrankerFaceZ logs have been uploaded to the URL:",e):alert("There was an error uploading the FrankerFaceZ logs.")}))}),t.appendChild(_)}}},{"../constants":3}],19:[function(t){var n=e.FrankerFaceZ,o=t("../constants");n.settings_info.twitch_chat_dark={type:"boolean",value:!1,visible:!1},n.settings_info.dark_twitch={type:"boolean",value:!1,visible:function(){return!this.has_bttv},name:"Dark Twitch Beta",help:"Apply a dark background to channels and other related pages for easier viewing.",on_update:function(e){if(!this.has_bttv){document.body.classList.toggle("ffz-dark",e);var t=App.__container__.lookup("controller:settings").get("model");e?(this._load_dark_css(),this.settings.set("twitch_chat_dark",t.get("darkMode")),t.set("darkMode",!0)):t.set("darkMode",this.settings.twitch_chat_dark)}}},n.prototype.setup_dark=function(){this.has_bttv||(document.body.classList.toggle("ffz-dark",this.settings.dark_twitch),this.settings.dark_twitch&&App.__container__.lookup("controller:settings").set("model.darkMode",!0),this.settings.dark_twitch&&this._load_dark_css())},n.prototype._load_dark_css=function(){if(!this._dark_style){this.log("Injecting FrankerFaceZ Dark Twitch CSS.");var e=this._dark_style=document.createElement("link");e.id="ffz-dark-css",e.setAttribute("rel","stylesheet"),e.setAttribute("href",o.SERVER+"script/dark.css"),document.head.appendChild(e)}}},{"../constants":3}],20:[function(t){var n=e.FrankerFaceZ,o=t("../constants");n.prototype.setup_menu=function(){this.log("Installing mouse-up event to auto-close menus.");var e=this;jQuery(document).mouseup(function(t){var n,o=e._popup;o&&(o=jQuery(o),n=o.parent(),n.is(t.target)||0!==n.has(t.target).length||(o.remove(),delete e._popup,e._popup_kill&&e._popup_kill(),delete e._popup_kill))})},n.menu_pages={},n.prototype.build_ui_popup=function(e){var t=this._popup;if(t)return t.parentElement.removeChild(t),delete this._popup,this._popup_kill&&this._popup_kill(),void delete this._popup_kill;var i=document.createElement("div"),s=document.createElement("div"),r=document.createElement("ul"),a=this.has_bttv?BetterTTV.settings.get("darkenedMode"):!1;i.className="emoticon-selector chat-menu ffz-ui-popup",s.className="emoticon-selector-box dropmenu",i.appendChild(s),i.classList.toggle("dark",a);var l=document.createElement("div");l.className="ffz-ui-menu-page",s.appendChild(l),r.className="menu clearfix",s.appendChild(r);var c=document.createElement("li");c.className="title",c.innerHTML=""+(o.DEBUG?"[DEV] ":"")+"FrankerFaceZ",r.appendChild(c);var u=[];for(var d in n.menu_pages)if(n.menu_pages.hasOwnProperty(d)){var h=n.menu_pages[d];h&&(!h.hasOwnProperty("visible")||h.visible&&("function"!=typeof h.visible||h.visible.bind(this)()))&&u.push([h.sort_order||0,d,h])}u.sort(function(e,t){if(e[0]t[0])return-1;var n=e[1].toLowerCase(),o=t[1].toLowerCase();return o>n?1:n>o?-1:0});for(var m=0;m0){i=!0;break}}e.classList.toggle("no-emotes",!i),e.classList.toggle("live",a),e.classList.toggle("dark",s),e.classList.toggle("blue",r)}}},{"../constants":3}],22:[function(t){var n=e.FrankerFaceZ,o=t("../constants"),i="http://static-cdn.jtvnw.net/emoticons/v1/",s={"00000turbo":!0},r={"B-?\\)":"B-)","\\:-?[z|Z|\\|]":":-Z","\\:-?\\)":":-)","\\:-?\\(":":-(","\\:-?(p|P)":":-P","\\;-?(p|P)":";-P","\\<\\;3":"<3","\\:-?(?:\\/|\\\\)(?!\\/)":":-/","\\;-?\\)":";-)","R-?\\)":"R-)","[o|O](_|\\.)[o|O]":"O.o","\\:-?D":":-D","\\:-?(o|O)":":-O","\\>\\;\\(":">("},a=function(e){var t=App.__container__.lookup("controller:chat"),n=t.get("currentRoom.id"),o=e.rooms[n],i=o?o.room.tmiSession:null,s=i&&i._emotesParser&&i._emotesParser.emoticonSetIds||"0",r=e.get_user(),a=r&&e.users[r.login]&&e.users[r.login].sets||[];return s=s.split(",").removeObject("0"),e.settings.global_emotes_in_menu&&s.push("0"),[s,a]};n.settings_info.global_emotes_in_menu={type:"boolean",value:!1,name:"Display Global Emotes in My Emotes",help:"Display the global Twitch emotes in the My Emoticons menu."},n.prototype.setup_my_emotes=function(){if(this._twitch_emote_sets={},this._twitch_set_to_channel={},localStorage.ffzTwitchSets)try{this._twitch_set_to_channel=JSON.parse(localStorage.ffzTwitchSets)}catch(e){}this._twitch_set_to_channel[0]="twitch_global"},n.menu_pages.my_emotes={name:"My Emoticons",icon:o.EMOTE,visible:function(){var e=a(this);return e[0].length>0||e[1].length>0},render:function(e,t){var o=a(this),l=this;new RSVP.Promise(function(e){for(var t=[],i=0;i0?(l.ws_send("twitch_sets",t,function(e,n){if(t=[],e){for(var o in n)n.hasOwnProperty(o)&&(l._twitch_set_to_channel[o]=n[o],r(o,n[o]));localStorage.ffzTwitchSets=JSON.stringify(l._twitch_set_to_channel)}a()}),setTimeout(function(){t.length&&a()},5e3)):a()})]).then(function(){for(var t={},n=0;nt[0])return 1;var n=e[1].toLowerCase(),o=t[1].toLowerCase();return("twitch turbo"===n||"global emoticons"===n)&&(n="zzz"+n),("twitch turbo"===o||"global emoticons"===o)&&(o="zzz"+o),o>n?-1:n>o?1:0});for(var u=0;u'+c.source+""+n.get_capitalization(c.channel),c.badge&&(d.style.backgroundImage='url("'+c.badge+'")'),h.className="emoticon-grid",h.appendChild(d);for(var m=0;mSpeedRunsLive races under channels.',on_update:function(){this.rebuild_race_ui()}},n.ws_on_close.push(function(){var e=App.__container__.lookup("controller:channel"),t=e.get("id"),n=!1;for(var o in this.srl_races)delete this.srl_races[o],o==t&&(n=!0);n&&this.rebuild_race_ui()}),n.ws_commands.srl_race=function(e){for(var t=App.__container__.lookup("controller:channel"),n=t.get("id"),o=!1,i=0;i=300?"right":"left")+" share dropmenu",this._popup_kill=this._race_kill.bind(this),this._popup=e;var l="http://kadgar.net/live",c=!1;for(var u in r.entrants){var d=r.entrants[u].state;r.entrants.hasOwnProperty(u)&&r.entrants[u].channel&&("racing"==d||"entered"==d)&&(l+="/"+r.entrants[u].channel,c=!0)}var h=document.querySelector(".app-main.theatre")?document.body.clientHeight-300:t.parentElement.offsetTop-175,m=App.__container__.lookup("controller:channel"),_=m?m.get("display_name"):n.get_capitalization(s),p=encodeURIComponent("I'm watching "+_+" race "+r.goal+" in "+r.game+" on SpeedRunsLive!");a='
',a+='
Developers
Dan Salvato  
Stendec  
Version '+n.version_info+'Logs
',a+="
#Entrant Time
",a+='
',a+='',a+='

SRL',c&&(a+='   Multitwitch'),a+="

",e.innerHTML=a,t.appendChild(e),this._update_race(!0)}}},n.prototype._update_race=function(e){this._race_timer&&e&&(clearTimeout(this._race_timer),delete this._race_timer);var t=document.querySelector("#ffz-ui-race");if(t){var n=t.getAttribute("data-channel"),i=this.srl_races[n];if(!i)return t.parentElement.removeChild(t),this._popup_kill&&this._popup_kill(),void(this._popup&&(delete this._popup,delete this._popup_kill));var s=i.twitch_entrants[n],r=i.entrants[s],a=t.querySelector("#ffz-race-popup"),l=Date.now()/1e3,c=Math.floor(l-i.time);if(t.querySelector(".logo").innerHTML=o.placement(r),a){var u=a.querySelector("tbody"),d=a.querySelector(".heading span"),h=a.querySelector(".heading div");u.innerHTML="";var m=[],_=!0;for(var p in i.entrants)i.entrants.hasOwnProperty(p)&&("racing"==i.entrants[p].state&&(_=!1),m.push(i.entrants[p]));m.sort(function(e,t){var n=e.place||9999,o=t.place||9999,i=e.time||c,s=t.time||c;return("forfeit"==e.state||"dq"==e.state)&&(n=1e4),("forfeit"==t.state||"dq"==t.state)&&(o=1e4),o>n?-1:n>o?1:e.namet.name?1:s>i?-1:i>s?1:void 0});for(var f=0;f'+p.display_name+"",v=p.channel?'':"",b=p.hitbox?'':"",y=c?o.time_to_string(p.time||c):"",w=o.place_string(p.place),k=p.comment?o.sanitize(p.comment):"";u.innerHTML+="'+w+""+g+""+v+b+''+("forfeit"==p.state?"Forfeit":y)+""}if(this._race_game!=i.game||this._race_goal!=i.goal){this._race_game=i.game,this._race_goal=i.goal;var F=o.sanitize(i.game),E=o.sanitize(i.goal);h.innerHTML='

'+F+"

Goal: "+E}c?_?d.innerHTML="Done":(d.innerHTML=o.time_to_string(c),this._race_timer=setTimeout(this._update_race.bind(this),1e3)):d.innerHTML="Entry Open"}}}},{"../utils":27}],25:[function(t){var n=e.FrankerFaceZ,o=t("../constants");n.prototype.setup_css=function(){this.log("Injecting main FrankerFaceZ CSS.");var e=this._main_style=document.createElement("link");e.id="ffz-ui-css",e.setAttribute("rel","stylesheet"),e.setAttribute("href",o.SERVER+"script/style.css?_="+Date.now()),document.head.appendChild(e),jQuery.noty.themes.ffzTheme={name:"ffzTheme",style:function(){this.$bar.removeClass().addClass("noty_bar").addClass("ffz-noty").addClass(this.options.type)},callback:{onShow:function(){},onClose:function(){}}}}},{"../constants":3}],26:[function(t){var n=e.FrankerFaceZ,o=t("../constants"),i=t("../utils");n.ws_commands.viewers=function(e){var t=e[0],n=e[1],s=App.__container__.lookup("controller:channel"),r=s&&s.get&&s.get("id");if(r===t){var a=document.querySelector(".channel-stats .ffz.stat"),l=o.ZREKNARF+" "+i.number_commas(n);if(a)a.innerHTML=l;else{var c=document.querySelector(".channel-stats");if(!c)return;a=document.createElement("span"),a.className="ffz stat",a.title="Viewers with FrankerFaceZ",a.innerHTML=l,c.appendChild(a),jQuery(a).tipsy()}}}},{"../constants":3,"../utils":27}],27:[function(t,n){var o=(e.FrankerFaceZ,t("./constants"),{}),i=document.createElement("span"),s=function(e){return 1==e?"1st":2==e?"2nd":3==e?"3rd":null==e?"---":e+"th"},r=function(e,t){t=0===t?0:t||1,t=Math.round(255*-(t/100));var n=Math.max(0,Math.min(255,e[0]-t)),o=Math.max(0,Math.min(255,e[1]-t)),i=Math.max(0,Math.min(255,e[2]-t));return[n,o,i]},a=function(e){return"rgb("+e[0]+", "+e[1]+", "+e[2]+")"},l=function(e,t){return t=0===t?0:t||1,r(e,-t)},c=function(e){e=[e[0]/255,e[1]/255,e[2]/255];for(var t=0;tr;(l||n)&&(l&&(o=o.substr(0,r)+o.substr(a+s.length)),n&&(o+=i+n+s),e.innerHTML=o)},get_luminance:c,brighten:r,darken:l,rgb_to_css:a,number_commas:function(e){var t=e.toString().split(".");return t[0]=t[0].replace(/\B(?=(\d{3})+(?!\d))/g,","),t.join(".")},place_string:s,placement:function(e){return"forfeit"==e.state?"Forfeit":"dq"==e.state?"DQed":e.place?s(e.place):""},sanitize:function(e){var t=o[e];return t||(i.textContent=e,t=o[e]=i.innerHTML,i.innerHTML=""),t},time_to_string:function(e){var t=e%60,n=Math.floor(e/60),o=Math.floor(n/60);return n%=60,(10>o?"0":"")+o+":"+(10>n?"0":"")+n+":"+(10>t?"0":"")+t}}},{"./constants":3}]},{},[13]),e.ffz=new FrankerFaceZ}(window); \ No newline at end of file diff --git a/src/badges.js b/src/badges.js index 50b4e7e3..f921fa2f 100644 --- a/src/badges.js +++ b/src/badges.js @@ -3,6 +3,20 @@ var FFZ = window.FrankerFaceZ, utils = require('./utils'); +// -------------------- +// Settings +// -------------------- + +FFZ.settings_info.bot_badges = { + type: "boolean", + value: true, + + category: "Chat", + name: "Bot Badges", + help: "Give special badges to known bots." + }; + + // -------------------- // Initialization // -------------------- @@ -38,7 +52,8 @@ FFZ.prototype.bttv_badges = function(data) { var user_id = data.sender, user = this.users[user_id], badges_out = [], - insert_at = -1; + insert_at = -1, + alpha = BetterTTV.settings.get('alphaTags'); if ( ! user || ! user.badges ) return; @@ -52,7 +67,6 @@ FFZ.prototype.bttv_badges = function(data) { } } - for (var slot in user.badges) { if ( ! user.badges.hasOwnProperty(slot) ) continue; @@ -60,8 +74,16 @@ FFZ.prototype.bttv_badges = function(data) { var badge = user.badges[slot], full_badge = this.badges[badge.id] || {}, desc = badge.title || full_badge.title, - style = "", - alpha = BetterTTV.settings.get('alphaTags'); + style = ""; + + if ( full_badge.visible !== undefined ) { + var visible = full_badge.visible; + if ( typeof visible == "function" ) + visible = visible.bind(this)(null, user_id); + + if ( ! visible ) + continue; + } if ( badge.image ) style += 'background-image: url(\\"' + badge.image + '\\"); '; @@ -116,12 +138,21 @@ FFZ.prototype.render_badge = function(view) { if ( full_badge.visible !== undefined ) { var visible = full_badge.visible; if ( typeof visible == "function" ) - try { visible = visible.bind(this)(room_id, user); } catch(err) { } + visible = visible.bind(this)(room_id, user); if ( ! visible ) continue; } + if ( full_badge.replaces ) { + var el = badges[0].querySelector('.badge.' + full_badge.replaces); + if ( el ) { + el.style.backgroundImage = 'url("' + (badge.image || full_badge.image) + '")'; + el.title += ", " + (badge.title || full_badge.title); + return; + } + } + var el = document.createElement('div'); el.className = 'badge float-left tooltip ffz-badge-' + badge.id; el.setAttribute('title', badge.title || full_badge.title); @@ -154,24 +185,33 @@ FFZ.prototype.render_badge = function(view) { // Legacy Support // -------------------- -FFZ.known_bots = ["quoteconut", "quoconut", "zenwan", "nightbot", "moobot", "xanbot"]; +FFZ.bttv_known_bots = ["nightbot","moobot","sourbot","xanbot","manabot","mtgbot","ackbot","baconrobot","tardisbot","deejbot","valuebot","stahpbot"]; +FFZ.known_bots = ["quoteconut", "quoconut", "zenwan", "triiharder", "wobblerbot", "theroflbotr", "acebot"]; + FFZ.prototype._legacy_add_donors = function(tries) { this.badges[1] = {id: 1, title: "FFZ Donor", color: "#755000", image: "//cdn.frankerfacez.com/channel/global/donoricon.png"}; utils.update_css(this._badge_style, 1, badge_css(this.badges[1])); - // Developer Badges + // Developer Badge this.badges[0] = {id: 0, title: "FFZ Developer", color: "#FAAF19", image: "//cdn.frankerfacez.com/channel/global/devicon.png"}; utils.update_css(this._badge_style, 0, badge_css(this.badges[0])); - this.users.sirstendec = {badges: {0: {id:0}}}; - // Bot Badges - /*this.badges[2] = {id: 2, title: "Bot", color: "#595959", image: "//cdn.frankerfacez.com/channel/global/boticon.png", - visible: function(r,user) { return !(this.has_bttv && FFZ.bttv_known_bots[user]); }}; + // Bot Badge + this.badges[2] = {id: 2, title: "Bot", color: "#595959", image: "//cdn.frankerfacez.com/channel/global/boticon.png", + replaces: 'moderator', + visible: function(r,user) { return this.settings.bot_badges && !(this.has_bttv && FFZ.bttv_known_bots.indexOf(user)!==-1); }}; utils.update_css(this._badge_style, 2, badge_css(this.badges[2])); + for(var i=0;i", - set = data.set, + var set = data.set, set_type = data.set_type; if ( set_type === undefined ) @@ -40,12 +39,7 @@ var FFZ = window.FrankerFaceZ, set_type = null; } - if ( ! set_type ) - output += '' + set + ''; - else - output += "" + set_type + "" + set + ""; - - return '' + output + '
'; + return "Emoticon: " + data.code + "\n" + (set_type ? set_type + ": " : "") + set; }, build_tooltip = function(id) { @@ -161,7 +155,7 @@ FFZ.settings_info.keywords = { FFZ.settings_info.fix_color = { type: "boolean", - value: false, + value: true, category: "Chat", visible: function() { return ! this.has_bttv }, @@ -230,6 +224,7 @@ FFZ.prototype.setup_line = function() { var tokens = this._super(); try { + var start = performance.now(); tokens = f._remove_banned(tokens); tokens = f._emoticonize(this, tokens); var user = f.get_user(); @@ -237,6 +232,10 @@ FFZ.prototype.setup_line = function() { if ( ! user || this.get("model.from") != user.login ) tokens = f._mentionize(this, tokens); + var end = performance.now(); + if ( end - start > 5 ) + f.log("Tokenizing Message Took Too Long - " + (end-start) + "ms - " + JSON.stringify(tokens)); + } catch(err) { try { f.error("LineController tokenizedMessage: " + err); @@ -256,6 +255,8 @@ FFZ.prototype.setup_line = function() { didInsertElement: function() { this._super(); try { + var start = performance.now(); + var el = this.get('element'), controller = this.get('context'), user = controller.get('model.from'), @@ -298,7 +299,7 @@ FFZ.prototype.setup_line = function() { if ( mentioned ) { el.classList.add("ffz-mentioned"); - if ( ! document.hasFocus() && ! this.get('context.model.ffz_notified') && f.settings.highlight_notifications ) { + if ( f.settings.highlight_notifications && !document.hasFocus() && !this.get('context.model.ffz_notified') ) { var cap_room = FFZ.get_capitalization(room), cap_user = FFZ.get_capitalization(user), room_name = cap_room, @@ -329,7 +330,7 @@ FFZ.prototype.setup_line = function() { // Banned Links var bad_links = el.querySelectorAll('a.deleted-link'); for(var i=0; i < bad_links.length; i++) { - var link = bad_links[i]; + var link = bad_links[i]; link.addEventListener("click", function(e) { if ( ! this.classList.contains("deleted-link") ) @@ -366,7 +367,7 @@ FFZ.prototype.setup_line = function() { // Enhanced Emotes - var images = el.querySelectorAll('img'); + var images = el.querySelectorAll('img.emoticon'); for(var i=0; i < images.length; i++) { var img = images[i], name = img.alt, @@ -389,8 +390,6 @@ FFZ.prototype.setup_line = function() { f.ws_send("twitch_emote", id, load_emote_data.bind(f, id, img.alt)); } - jQuery(img).tipsy({html:true}); - } else if ( img.getAttribute('data-ffz-emote') ) { var data = JSON.parse(decodeURIComponent(img.getAttribute('data-ffz-emote'))), id = data && data[0] || null, @@ -418,13 +417,15 @@ FFZ.prototype.setup_line = function() { set: set_name, set_type: set_type }); - - jQuery(img).tipsy({html:true}); - - } else - jQuery(img).tipsy(); + } } + jQuery(images).tipsy(); + + + var duration = performance.now() - start; + if ( duration > 5 ) + f.log("Line Took Too Long - " + duration + "ms - " + el.innerHTML); } catch(err) { try { @@ -470,7 +471,7 @@ FFZ.prototype._handle_color = function(color) { // Color Too Bright. We need a lum of 0.3 or less. matched = true; - var s = 255, + var s = 127, nc = rgb; while(s--) { nc = utils.darken(nc); @@ -482,15 +483,15 @@ FFZ.prototype._handle_color = function(color) { } else output += '.ffz-chat-colors .ember-chat-container:not(.dark) .chat-line ' + rule + ', .ffz-chat-colors .chat-container:not(.dark) .chat-line ' + rule + ' { color: ' + color + ' !important; }\n'; - if ( lum < 0.1 ) { + if ( lum < 0.15 ) { // Color Too Dark. We need a lum of 0.1 or more. matched = true; - var s = 255, + var s = 127, nc = rgb; while(s--) { nc = utils.brighten(nc); - if ( utils.get_luminance(nc) >= 0.1 ) + if ( utils.get_luminance(nc) >= 0.15 ) break; } @@ -545,8 +546,11 @@ FFZ.get_capitalization = function(name, callback) { FFZ.prototype.capitalize = function(view, user) { var name = FFZ.get_capitalization(user, this.capitalize.bind(this, view)); - if ( name && view ) - view.$('.from').text(name); + if ( !name || !view ) + return; + + var from = view.$('.from'); + from && from.text(name); } diff --git a/src/ember/room.js b/src/ember/room.js index d4732367..db6c6d83 100644 --- a/src/ember/room.js +++ b/src/ember/room.js @@ -10,7 +10,7 @@ var FFZ = window.FrankerFaceZ, if ( ! room.moderator_badge ) return ""; - return '.chat-line[data-room="' + room.id + '"] .badges .moderator { background-image:url("' + room.moderator_badge + '") !important; }'; + return '.chat-line[data-room="' + room.id + '"] .badges .moderator { background-image:url("' + room.moderator_badge + '"); }'; } diff --git a/src/ext/betterttv.js b/src/ext/betterttv.js index c3388624..2369f6f0 100644 --- a/src/ext/betterttv.js +++ b/src/ext/betterttv.js @@ -2,8 +2,6 @@ var FFZ = window.FrankerFaceZ, SENDER_REGEX = /(\sdata-sender="[^"]*"(?=>))/; -FFZ.bttv_known_bots = ["nightbot","moobot","sourbot","xanbot","manabot","mtgbot","ackbot","baconrobot","tardisbot","deejbot","valuebot","stahpbot"]; - // -------------------- // Initialization // -------------------- diff --git a/src/main.js b/src/main.js index 28863a7b..1520a67b 100644 --- a/src/main.js +++ b/src/main.js @@ -22,7 +22,7 @@ FFZ.get = function() { return FFZ.instance; } // Version var VER = FFZ.version_info = { - major: 3, minor: 2, revision: 1, + major: 3, minor: 2, revision: 2, toString: function() { return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); } diff --git a/src/socket.js b/src/socket.js index ab9c9f9d..8e1d10f3 100644 --- a/src/socket.js +++ b/src/socket.js @@ -99,7 +99,10 @@ FFZ.prototype.ws_create = function() { } else { var success = cmd === 'True', callback = f._ws_callbacks[request]; - f.log("Socket Reply to " + request + " - " + (success ? "SUCCESS" : "FAIL"), data); + + if ( ! success || ! callback ) + f.log("Socket Reply to " + request + " - " + (success ? "SUCCESS" : "FAIL"), data); + if ( callback ) { delete f._ws_callbacks[request]; callback(success, data); diff --git a/src/ui/my_emotes.js b/src/ui/my_emotes.js index 1f4bb7dd..d53f2d64 100644 --- a/src/ui/my_emotes.js +++ b/src/ui/my_emotes.js @@ -4,6 +4,22 @@ var FFZ = window.FrankerFaceZ, TWITCH_BASE = "http://static-cdn.jtvnw.net/emoticons/v1/", BANNED_SETS = {"00000turbo":true}, + KNOWN_CODES = { + "B-?\\)": "B-)", + "\\:-?[z|Z|\\|]": ":-Z", + "\\:-?\\)": ":-)", + "\\:-?\\(": ":-(", + "\\:-?(p|P)": ":-P", + "\\;-?(p|P)": ";-P", + "\\<\\;3": "<3", + "\\:-?(?:\\/|\\\\)(?!\\/)": ":-/", + "\\;-?\\)": ";-)", + "R-?\\)": "R-)", + "[o|O](_|\\.)[o|O]": "O.o", + "\\:-?D": ":-D", + "\\:-?(o|O)": ":-O", + "\\>\\;\\(": ">(", + }, get_emotes = function(ffz) { var Chat = App.__container__.lookup('controller:chat'), @@ -18,6 +34,9 @@ var FFZ = window.FrankerFaceZ, // Remove the 'default' set. set_ids = set_ids.split(",").removeObject("0") + if ( ffz.settings.global_emotes_in_menu ) + set_ids.push("0"); + return [set_ids, user_sets]; }; @@ -26,6 +45,15 @@ var FFZ = window.FrankerFaceZ, // Initialization // ------------------- +FFZ.settings_info.global_emotes_in_menu = { + type: "boolean", + value: false, + + name: "Display Global Emotes in My Emotes", + help: "Display the global Twitch emotes in the My Emoticons menu." + }; + + FFZ.prototype.setup_my_emotes = function() { this._twitch_emote_sets = {}; this._twitch_set_to_channel = {}; @@ -35,6 +63,8 @@ FFZ.prototype.setup_my_emotes = function() { this._twitch_set_to_channel = JSON.parse(localStorage.ffzTwitchSets); } catch(err) { } } + + this._twitch_set_to_channel[0] = "twitch_global"; } @@ -96,6 +126,13 @@ FFZ.menu_pages.my_emotes = { if ( !name || BANNED_SETS[name] ) return; + if ( name == "twitch_global" ) { + FFZ.capitalization["global emoticons"] = ["Global Emoticons", Date.now()]; + set.channel = "Global Emoticons"; + set.badge = "//cdn.frankerfacez.com/channel/global/twitch_logo.png"; + return; + } + if ( name == "turbo" ) { set.channel = "Twitch Turbo"; set.badge = "//cdn.frankerfacez.com/script/turbo_badge.png"; @@ -220,10 +257,10 @@ FFZ.menu_pages.my_emotes = { var an = a[1].toLowerCase(), bn = b[1].toLowerCase(); - if ( an === "twitch turbo" ) + if ( an === "twitch turbo" || an === "global emoticons" ) an = "zzz" + an; - if ( bn === "twitch turbo" ) + if ( bn === "twitch turbo" || bn === "global emoticons" ) bn = "zzz" + bn; if ( an < bn ) return -1; @@ -245,7 +282,8 @@ FFZ.menu_pages.my_emotes = { menu.appendChild(heading); for(var x=0; x < set.emotes.length; x++) { - var emote = set.emotes[x]; + var emote = set.emotes[x], + code = KNOWN_CODES[emote.code] || emote.code; var s = document.createElement('span'); s.className = 'emoticon tooltip'; @@ -257,8 +295,8 @@ FFZ.menu_pages.my_emotes = { s.style.backgroundImage = '-ms-' + img_set; s.style.backgroundImage = img_set; - s.title = emote.code; - s.addEventListener('click', f._add_emote.bind(f, view, emote.code)); + s.title = code; + s.addEventListener('click', f._add_emote.bind(f, view, code)); menu.appendChild(s); } diff --git a/style.css b/style.css index 22b39ce6..14b166ab 100644 --- a/style.css +++ b/style.css @@ -352,7 +352,7 @@ .chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading, .chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid .heading { margin-bottom: 5px; - border-bottom: 1px solid rgba(0,0,0, 0.2); + border-bottom: 1px solid rgba(0,0,0,0.2); text-align: left; } @@ -433,7 +433,9 @@ .ffz-ui-popup.dark .ffz-ui-menu-page a { color: #fff; } +.ffz-dark .ffz-ui-popup ul.menu svg path, .ffz-ui-popup.dark ul.menu svg path { fill: #d3d3d3; } + .ffz-ui-popup ul.menu svg path { fill: #333; } @@ -588,22 +590,10 @@ /* Emoticon Tooltips */ -.tipsy table.emote-data td { padding: 0 2px; } - -.tipsy table.emote-data td:first-of-type { - text-align: right; - font-weight: bold; - padding-left: 0; +.tipsy .tipsy-inner { + white-space: pre-wrap; } -.tipsy table.emote-data td:last-of-type { - text-align: left; - padding-right: 0; - white-space: nowrap; -} - -.tipsy table.emote-data td.center { text-align: center; } - /* Menu Page Loader */ .ffz-ui-menu-page:empty {