From c40b3ba337c477f62b713913637e62694bdf8e38 Mon Sep 17 00:00:00 2001 From: SirStendec Date: Sat, 7 Nov 2015 22:56:15 -0500 Subject: [PATCH 1/5] 3.5.51 to 3.5.57. Changes to how chat history is implemented. Made the Actions and Metadata overlay for theater mode optional. Added support for the new Conversation UI. Increased socket server rollout. Mod cards update history in real time. Fixed global moderator badges. Refactored emote clicking code. Moved CSS to external again. --- dark.css | 111 ++ src/badges.js | 2 +- src/colors.js | 12 + src/constants.js | 3 + src/ember/channel.js | 15 + src/ember/chatview.js | 15 + src/ember/directory.js | 43 +- src/ember/layout.js | 33 +- src/ember/line.js | 153 +-- src/ember/moderation-card.js | 26 +- src/ember/room.js | 67 +- src/emoticons.js | 35 + src/main.js | 2 +- src/socket.js | 2 +- src/styles/style.css | 2146 ---------------------------------- src/tokenize.js | 56 +- src/ui/dark.js | 7 +- src/ui/notifications.js | 5 + src/ui/styles.js | 14 +- src/utils.js | 3 + 20 files changed, 459 insertions(+), 2291 deletions(-) delete mode 100644 src/styles/style.css diff --git a/dark.css b/dark.css index de420715..0c24fcf9 100644 --- a/dark.css +++ b/dark.css @@ -164,6 +164,7 @@ /* Popups */ +.ffz-dark .conversation-settings-menu, .ffz-dark .ember-chat .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box, .ffz-dark .card, .ffz-dark #flyout .content, @@ -925,4 +926,114 @@ .ffz-dark .playlist-container:not(.playlist-enabled) .playlist-item:hover, .ffz-dark .playlist-container:not(.playlist-enabled) .ui-sortable-helper { background-color: rgba(255,255,255,0.2); +} + + +/* Conversations */ + +.ffz-dark .conversation-settings-menu .options-divider { + border-bottom-color: rgba(255,255,255,0.2); +} + +.ffz-dark .conversation-settings-menu:before { + border-color: transparent; + border-bottom-color: #32323e; +} + +.ffz-dark .conversation-settings-menu:after { + border-color: transparent; + border-bottom-color: rgb(16,16,16); +} + +.ffz-dark .conversations-list-icon { + background: #19191f; + color: #8c8c9c; + border-color: #19191f +} + +.ffz-dark .conversations-list-icon:hover { + color: #fff +} + +.ffz-dark .conversations-list { + background: #19191f; + border: 1px solid #32323e; + color: #fff +} + +.ffz-dark .conversations-list:after { + border-color: rgba(25,25,31,0); + border-top-color: #19191f; + border-width: 10px; + margin-left: -10px +} + +.ffz-dark .conversations-list:before { + right: 9px; + border-color: rgba(50,50,62,0); + border-top-color: #32323e +} + +.ffz-dark .conversations-list .conversations-list-header { + background: #19191f; + border-bottom: 1px solid #32323e; + color: #fff +} + +.ffz-dark .conversations-list .conversation-preview-line { + color: #8c8c9c +} + +.ffz-dark .conversations-list .conversations-list-item { + border-bottom: 1px solid #32323e +} + +.ffz-dark .conversations-list .conversations-list-item:hover { + background-color: #121217 +} + +.ffz-dark .conversation-window { + background: #19191f; + box-shadow: none; + color: #8c8c9c; +} + +.ffz-dark .conversations-list-icon, +.ffz-dark .conversation-window { + border: 1px solid rgba(255,255,255,0.2); + border-bottom: none; +} + +.ffz-dark .conversation-header { + background: #121217; + box-shadow: none; + border-bottom: 1px solid rgba(255,255,255,0.2); +} + +.ffz-dark .conversation-input-bar textarea { + border-color: rgba(255,255,255,0.1); + background-color: rgba(255,255,255,0.05); + color: #b6b6b6 +} + +.ffz-dark .conversation-input-actions .button, +.ffz-dark .conversation-input-actions .follow-button:not(.ember-follow) .follow { + background-color: #444 +} + +.ffz-dark .conversation-window.has-focus .conversation-header { + background-color: #121217 +} + +.ffz-dark .conversation-window.has-focus .conversation-header-name { + color: #fff +} + +.ffz-dark .conversation-window.has-focus .conversation-input-bar textarea:focus { + border-color: rgba(255,255,255,0.2) +} + +.ffz-dark .conversation-window.has-focus .conversation-input-actions .button, +.ffz-dark .conversation-window.has-focus .conversation-input-actions .follow-button:not(.ember-follow) .follow { + background-color: #6441a5 } \ No newline at end of file diff --git a/src/badges.js b/src/badges.js index 09375e8d..c4ce8098 100644 --- a/src/badges.js +++ b/src/badges.js @@ -254,7 +254,7 @@ FFZ.prototype.render_badges = function(component, badges) { if ( ! this.settings.show_badges ) return badges; - var user = component.get('msgObject.from'), + var user = component.get('msgObject.from') || component.get('message.from.username'), room_id = component.get('msgObject.room') || App.__container__.lookup('controller:chat').get('currentRoom.id'); var data = this.users[user]; diff --git a/src/colors.js b/src/colors.js index 6591ca95..604959d6 100644 --- a/src/colors.js +++ b/src/colors.js @@ -581,6 +581,18 @@ FFZ.prototype._update_colors = function(darkness_only) { bit.style.color = is_dark ? colors[1] : colors[0]; } + + colored_bits = document.querySelectorAll('.conversation-chat-line .has-color'); + for(var i=0, l=colored_bits.length; i < l; i++) { + var bit = colored_bits[i], + color = bit.getAttribute('data-color'), + colors = color && this._handle_color(color); + + if ( ! colors ) + continue; + + bit.style.color = is_dark ? colors[1] : colors[0]; + } } diff --git a/src/constants.js b/src/constants.js index 32d35656..45d456c5 100644 --- a/src/constants.js +++ b/src/constants.js @@ -2,10 +2,13 @@ var SVGPATH = '.dynamic-player, .dynamic-player object, .dynamic-player video{width:" + width + "px !important;height:" + height + "px !important} .dynamic-target-player,.dynamic-target-player object, .dynamic-target-player video{width:" + width + "px !important;height:" + host_height + "px !important}"; }.property("playerSize"), - /*ffzUpdateWidth: _.throttle(function() { - var rc = document.querySelector('#right_close'); - if ( ! rc ) + ffzPortraitWarning: function() { + if ( ! f.settings.portrait_mode || f._portrait_warning || f.settings.portrait_warning || ! this.get('isTooSmallForRightColumn') ) return; - var left_width = this.get("isLeftColumnClosed") ? 50 : 240, - right_width; + f._portrait_warning = true; + f.show_message('Twitch\'s Chat Sidebar has been hidden as a result of FrankerFaceZ\'s Portrait Mode because the window is too wide.

Please disable Portrait Mode or make your window narrower.

Do not show this message again'); - if ( f.settings.swap_sidebars ) - right_width = rc.offsetLeft; // + this.get('rightColumnWidth') - 5; - else - right_width = document.body.offsetWidth - rc.offsetLeft - left_width - 25; - - if ( right_width < 250 ) { - // Close it! - - } - - this.set('rightColumnWidth', right_width); - Ember.propertyDidChange(Layout, 'contentWidth'); - }, 200),*/ + }.observes("isTooSmallForRightColumn"), ffzUpdateCss: function() { // TODO: Fix this mess of duplicate code. @@ -332,6 +325,6 @@ FFZ.prototype.setup_layout = function() { Layout.set('rawPortraitMode', this.settings.portrait_mode); // Force re-calculation of everything. - Ember.propertyDidChange(Layout, 'contentWidth'); + Ember.propertyDidChange(Layout, 'windowWidth'); Ember.propertyDidChange(Layout, 'windowHeight'); } \ No newline at end of file diff --git a/src/ember/line.js b/src/ember/line.js index 40827a89..6a08aaae 100644 --- a/src/ember/line.js +++ b/src/ember/line.js @@ -555,6 +555,13 @@ FFZ.prototype.setup_line = function() { if ( Line ) this._modify_line(Line); + this.log("Hooking the Ember Conversation Line component."); + var Conversation = App.__container__.resolve('component:conversation-line'); + + if ( Conversation ) + this._modify_conversation_line(Conversation); + + // Store the capitalization of our own name. var user = this.get_user(); if ( user && user.name ) @@ -568,6 +575,67 @@ FFZ.prototype.save_aliases = function() { } +FFZ.prototype._modify_conversation_line = function(component) { + var f = this, + + Layout = App.__container__.lookup('controller:layout'), + Settings = App.__container__.lookup('controller:settings'); + + component.reopen({ + tokenizedMessage: function() { + try { + return f.tokenize_conversation_line(this.get('message')); + } catch(err) { + f.error("convo-line tokenizedMessage: " + err); + return this._super(); + } + + }.property("message", "currentUsername"), + + click: function(e) { + if ( e.target && e.target.classList.contains('deleted-link') ) + return f._deleted_link_click.bind(e.target)(e); + + if ( f._click_emote(e.target, e) ) + return; + + return this._super(e); + }, + + render: function(e) { + var user = this.get('message.from.username'), + raw_color = this.get('message.from.color'), + colors = raw_color && f._handle_color(raw_color), + + is_dark = (Layout && Layout.get('isTheatreMode')) || f.settings.dark_twitch; + + e.push('
'); + + var alias = f.aliases[user], + name = this.get('message.from.displayName') || (user && user.capitalize()) || "unknown user", + style = colors && 'color:' + (is_dark ? colors[1] : colors[0]), + colored = style ? ' has-color' : ''; + + if ( alias ) + e.push('' + utils.sanitize(alias) + ''); + else + e.push('' + utils.sanitize(name) + ''); + + e.push(': '); + + if ( ! this.get('isActionMessage') ) { + style = ''; + colored = ''; + } + + e.push(''); + e.push(f.render_tokens(this.get('tokenizedMessage'), true)); + e.push(''); + } + }); +} + + FFZ.prototype._modify_line = function(component) { var f = this, @@ -577,46 +645,13 @@ FFZ.prototype._modify_line = function(component) { component.reopen({ tokenizedMessage: function() { - // Add our own step to the tokenization procedure. - var tokens = this.get("msgObject.cachedTokens"); - if ( tokens ) - return tokens; - - tokens = this._super(); - - var start = performance.now(), - user = f.get_user(), - from_me = user && this.get("msgObject.from") === user.login; - - tokens = f._remove_banned(tokens); - tokens = f._emoticonize(this, tokens); - - if ( f.settings.parse_emoji ) - tokens = f.tokenize_emoji(tokens); - - // Store the capitalization. - var display = this.get("msgObject.tags.display-name"); - if ( display && display.length ) - FFZ.capitalization[this.get("msgObject.from")] = [display.trim(), Date.now()]; - - if ( ! from_me ) - tokens = f.tokenize_mentions(tokens); - - for(var i = 0; i < tokens.length; i++) { - var token = tokens[i]; - if ( ! _.isString(token) && token.mentionedUser && ! token.own ) { - this.set('msgObject.ffz_has_mention', true); - break; - } + try { + return f.tokenize_chat_line(this.get('msgObject')); + } catch(err) { + f.error("chat-line tokenizedMessage: " + err); + return this._super(); } - var end = performance.now(); - if ( end - start > 5 ) - f.log("Tokenizing Message Took Too Long - " + (end-start) + "ms", tokens, false, true); - - this.set("msgObject.cachedTokens", tokens); - return tokens; - }.property("msgObject.message", "isChannelLinksDisabled", "currentUserNick", "msgObject.from", "msgObject.tags.emotes"), ffzUpdated: Ember.observer("msgObject.ffz_deleted", "msgObject.ffz_old_messages", function() { @@ -633,18 +668,6 @@ FFZ.prototype._modify_line = function(component) { if ( e.target && e.target.classList.contains('mod-icon') ) { jQuery(e.target).trigger('mouseout'); - /*if ( e.target.classList.contains('purge') ) { - var i = this.get('msgObject.from'), - room_id = this.get('msgObject.room'), - room = room_id && f.rooms[room_id] && f.rooms[room_id].room; - - if ( room ) { - room.send("/timeout " + i + " 1", true); - room.clearMessages(i); - } - return; - }*/ - if ( e.target.classList.contains('custom') ) { var room_id = this.get('msgObject.room'), room = room_id && f.rooms[room_id] && f.rooms[room_id].room, @@ -660,30 +683,8 @@ FFZ.prototype._modify_line = function(component) { } } - if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons && e.target && e.target.classList.contains('emoticon') ) { - var eid = e.target.getAttribute('data-emote'); - if ( eid ) - window.open("https://twitchemotes.com/emote/" + eid); - else { - eid = e.target.getAttribute("data-ffz-emote"); - var es = e.target.getAttribute("data-ffz-set"), - set = es && f.emote_sets[es], - url; - - if ( ! set ) - return; - - if ( set.hasOwnProperty('source_ext') ) { - var api = f._apis[set.source_ext]; - if ( api && api.emote_url_generator ) - url = api.emote_url_generator(set.source_id, eid); - } else - url = "https://www.frankerfacez.com/emoticons/" + eid; - - if ( url ) - window.open(url); - } - } + if ( f._click_emote(e.target, e) ) + return; return this._super(e); }, @@ -768,7 +769,7 @@ FFZ.prototype._modify_line = function(component) { else if ( this.get('isAdmin') ) badges[0] = {klass: 'admin', title: 'Admin'}; else if ( this.get('isGlobalMod') ) - badges[0] = {klass: 'global-mod', title: 'Global Moderator'}; + badges[0] = {klass: 'global-moderator', title: 'Global Moderator'}; else if ( ! is_whisper && this.get('isModerator') ) badges[0] = {klass: 'moderator', title: 'Moderator'}; @@ -835,7 +836,7 @@ FFZ.prototype._modify_line = function(component) { if ( deleted ) e.push('<message deleted>'); else { - e.push(''); + e.push(''); e.push(f.render_tokens(this.get('tokenizedMessage'), true)); var old_messages = this.get('msgObject.ffz_old_messages'); diff --git a/src/ember/moderation-card.js b/src/ember/moderation-card.js index 4100d297..d8dc6cd4 100644 --- a/src/ember/moderation-card.js +++ b/src/ember/moderation-card.js @@ -435,13 +435,20 @@ FFZ.prototype.setup_mod_card = function() { return alias || this.get("cardInfo.user.display_name") || user_id.capitalize(); }), + willDestroy: function() { + if ( f._mod_card === this ) + f._mod_card = undefined; + this._super(); + }, + didInsertElement: function() { this._super(); - window._card = this; try { if ( f.has_bttv ) return; + f._mod_card = this; + var el = this.get('element'), controller = this.get('controller'), line, @@ -450,11 +457,14 @@ FFZ.prototype.setup_mod_card = function() { chat = window.App && App.__container__.lookup('controller:chat'), user = f.get_user(), - is_broadcaster = user && chat && chat.get('currentRoom.id') === user.login, + room_id = chat && chat.get('currentRoom.id'), + is_broadcaster = user && room_id === user.login, user_id = controller.get('cardInfo.user.id'), alias = f.aliases[user_id]; + this.ffz_room_id = room_id; + // Alias Display if ( alias ) { var name = el.querySelector('h3.name'), @@ -735,17 +745,19 @@ FFZ.prototype.setup_mod_card = function() { l_el.innerHTML = (helpers ? '' + helpers.getTime(line.date) + ' ' : '') + '' + (line.style === 'action' ? '*' + line.from + ' ' : '') + f.render_tokens(line.cachedTokens) + ''; - // Banned Links - var bad_links = l_el.querySelectorAll('a.deleted-link'); - for(var x=0; x < bad_links.length; x++) - bad_links[x].addEventListener("click", f._deleted_link_click); - + // Interactivity + jQuery('a.deleted-link', l_el).click(f._deleted_link_click); + jQuery('img.emoticon', l_el).click(function(e) { f._click_emote(this, e) }); jQuery('.html-tooltip', l_el).tipsy({html:true}); + + // Append history.appendChild(l_el); } el.appendChild(history); + this.ffz_alternate = alternate; + // Lazy scroll-to-bottom history.scrollTop = history.scrollHeight; } diff --git a/src/ember/room.js b/src/ember/room.js index a6f9cbbe..9e257543 100644 --- a/src/ember/room.js +++ b/src/ember/room.js @@ -5,6 +5,7 @@ var FFZ = window.FrankerFaceZ, HOSTED_SUB = / subscribed to /, constants = require('../constants'), utils = require('../utils'), + helpers, // StrimBagZ Support is_android = navigator.userAgent.indexOf('Android') !== -1, @@ -14,7 +15,12 @@ var FFZ = window.FrankerFaceZ, return ""; return '.chat-line[data-room="' + room.id + '"] .badges .moderator:not(.ffz-badge-replacement) { background-image:url("' + room.moderator_badge + '") !important; }'; - } + }; + + +try { + helpers = window.require && window.require("ember-twitch-chat/helpers/chat-line-helpers"); +} catch(err) { } // -------------------- @@ -723,10 +729,11 @@ FFZ.prototype._insert_history = function(room_id, data) { tmiRoom = r.tmiRoom, inserted = 0, + purged = {}, last_msg = data[data.length - 1], now = new Date(), - last_date = typeof last_msg.date === "string" ? utils.parse_date(last_msg.date) : last_msg.date, + last_date = (typeof last_msg.date === "string" || typeof last_msg.date === "number") ? (last_msg.date = utils.parse_date(last_msg.date)) : last_msg.date, age = (now - last_date) / 1000, is_old = age > 300, @@ -738,9 +745,13 @@ FFZ.prototype._insert_history = function(room_id, data) { var i = data.length; while(i--) { - var msg = data[i]; + var msg = data[i], + is_deleted = msg.ffz_deleted = purged[msg.from] || false; - if ( typeof msg.date === "string" ) + if ( is_deleted && ! this.settings.prevent_clear ) + msg.deleted = true; + + if ( typeof msg.date === "string" || typeof msg.date === "number" ) msg.date = utils.parse_date(msg.date); msg.ffz_alternate = alternation = ! alternation; @@ -774,6 +785,14 @@ FFZ.prototype._insert_history = function(room_id, data) { msg.style = "notification"; } + if ( msg.tags && typeof msg.tags.emotes === "string" ) + try { + msg.tags.emotes = JSON.parse(msg.tags.emotes); + } catch(err) { + f.log("Error Parsing JSON Emotes: " + err); + msg.tags.emotes = {}; + } + if ( ! msg.cachedTokens || ! msg.cachedTokens.length ) this.tokenize_chat_line(msg, true, r.get('roomProperties.hide_chat_links')); @@ -791,6 +810,14 @@ FFZ.prototype._insert_history = function(room_id, data) { } else break; } + + // If there was a CLEARCHAT, stop processing. + if ( msg.tags && msg.tags.target === '@@' ) + break; + + // If there was a purge, just track the name. + else if ( msg.tags && msg.tags.target ) + purged[msg.tags.target] = true; } if ( is_old ) { @@ -1190,6 +1217,38 @@ FFZ.prototype._modify_room = function(room) { if ( user_history.length > 20 ) user_history.shift(); + + if ( f._mod_card && f._mod_card.ffz_room_id === msg.room && f._mod_card.get('cardInfo.user.id') === msg.from ) { + var el = f._mod_card.get('element'), + history = el && el.querySelector('.chat-history'), + was_at_top = history && history.scrollTop >= (history.scrollHeight - history.clientHeight); + + if ( history ) { + var l_el = document.createElement('li'); + l_el.className = 'message-line chat-line clearfix'; + + l_el.classList.toggle('ffz-alternate', f._mod_card.ffz_alternate); + f._mod_card.ffz_alternate = !f._mod_card.ffz_alternate; + + if ( msg.style ) + l_el.classList.add(msg.style); + + l_el.innerHTML = (helpers ? '' + helpers.getTime(msg.date) + ' ' : '') + '' + (msg.style === 'action' ? '*' + msg.from + ' ' : '') + f.render_tokens(msg.cachedTokens) + ''; + + // Interactivity + jQuery('a.deleted-link', l_el).click(f._deleted_link_click); + jQuery('img.emoticon', l_el).click(function(e) { f._click_emote(this, e) }); + jQuery('.html-tooltip', l_el).tipsy({html:true}); + + history.appendChild(l_el); + if ( was_at_top ) + setTimeout(function() { history.scrollTop = history.scrollHeight; }) + + // Don't do infinite scrollback. + if ( history.childElementCount > 50 ) + history.removeChild(history.firstElementChild); + } + } } } diff --git a/src/emoticons.js b/src/emoticons.js index 1e59d883..45da1fe3 100644 --- a/src/emoticons.js +++ b/src/emoticons.js @@ -141,6 +141,41 @@ FFZ.prototype._report_emotes = function() { } +// ------------------------ +// Emote Click Handler +// ------------------------ + +FFZ.prototype._click_emote = function(target, event) { + if ( ! this.settings.clickable_emoticons || (event && !((event.shiftKey || event.shiftLeft) && target && target.classList.contains('emoticon'))) ) + return; + + var eid = target.getAttribute('data-emote'); + if ( eid ) + window.open("https://twitchemotes.com/emote/" + eid); + else { + eid = target.getAttribute("data-ffz-emote"); + var es = target.getAttribute("data-ffz-set"), + emote_set = es && this.emote_sets[es], + url; + + if ( ! emote_set ) + return; + + if ( emote_set.hasOwnProperty('source_ext') ) { + var api = this._apis[emote_set.source_ext]; + if ( api && api.emote_url_generator ) + url = api.emote_url_generator(emote_set.source_id, eid); + } else + url = "https://www.frankerfacez.com/emoticons/" + eid; + + if ( url ) { + window.open(url); + return true; + } + } +} + + // ------------------------ // Twitch Emoticon Checker // ------------------------ diff --git a/src/main.js b/src/main.js index 3eb6c92c..598ebf78 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: 5, revision: 50, + major: 3, minor: 5, revision: 57, toString: function() { return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); } diff --git a/src/socket.js b/src/socket.js index 0ebceab2..ecb30044 100644 --- a/src/socket.js +++ b/src/socket.js @@ -35,7 +35,7 @@ FFZ.settings_info.socket_server_pool = { 2: "Development" }, - value: ffz_socket_seed > 0.65 ? 1 : 0, + value: ffz_socket_seed > 0.4 ? 1 : 0, process_value: function(val) { if ( typeof val === "string" ) diff --git a/src/styles/style.css b/src/styles/style.css deleted file mode 100644 index 766e3640..00000000 --- a/src/styles/style.css +++ /dev/null @@ -1,2146 +0,0 @@ -/* Fix Tooltip Opacity */ - -body > div.tipsy { opacity: 1 !important; } -body > div.tipsy .tipsy-inner { background-color: rgba(0,0,0,0.8); } -body > div.tipsy .tipsy-arrow { opacity: 0.8; } - - -.ffz-flip { - -ms-transform: rotate(180deg); - -webkit-transform: rotate(180deg); - transform: rotate(180deg); -} - -.ffz-ui-toggle { - display: block; - position: absolute; - top: 5px; right: 5px; - height: 18px; width: 24px; - cursor: pointer; -} - -.ffz-hide-recent-past-broadcast .recent-past-broadcast, -.ffz-hide-view-count .stat.twitch-channel-views, -.ffz-minimal-chat-input .emoticon-selector-toggle, -.ffz-menu-replace .emoticon-selector-toggle { - display: none !important; -} - -body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + .ffz-ui-toggle svg, -body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + script + .ffz-ui-toggle svg -{ - height: 14px; - width: 18px; -} - -body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + .ffz-ui-toggle, -body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + script + .ffz-ui-toggle { - height: 14px; - width: 18px; - top: 28px; -} - -.ffz-ui-toggle svg.svg-emoticons path { fill: rgba(0,0,0,0.2); } -.ffz-ui-toggle:hover svg.svg-emoticons path { fill: rgba(0,0,0,0.5); } - -.streams .stream .content .overlay_info.live svg path, -.videos .video .content .overlay_info.live svg path { fill: #ff2020; } - -.ember-chat-container.dark .ffz-ui-toggle svg.svg-emoticons path, -.chat-container.dark .ffz-ui-toggle svg.svg-emoticons path, -.app-main.theatre .ffz-ui-toggle svg.svg-emoticons path, -.ffz-ui-toggle.dark svg.svg-emoticons path { fill: #888; } - -.ember-chat-container.dark .ffz-ui-toggle:hover svg.svg-emoticons path, -.chat-container.dark .ffz-ui-toggle:hover svg.svg-emoticons path, -.app-main.theatre .ffz-ui-toggle:hover svg.svg-emoticons path, -.ffz-ui-toggle.dark:hover svg.svg-emoticons path { fill: #777; } - - -.ffz-ui-toggle.no-emotes svg.svg-emoticons path { fill: rgba(80,0,0,0.2); } -.ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path { fill: rgba(80,0,0,0.5); } - -.ffz-ui-toggle.live svg.svg-emoticons path { fill: rgba(100,65,165,0.5); } -.ffz-ui-toggle.live:hover svg.svg-emoticons path { fill: rgba(100,65,165,1); } - -.ffz-ui-toggle.blue.live svg.svg-emoticons path { fill: rgba(47,88,185,0.5); } -.ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill: rgba(47,88,185,1); } - -.ember-chat-container.dark .ffz-ui-toggle.news svg.svg-emoticons path, -.app-main.theatre .ffz-ui-toggle.news svg.svg-emoticons path, -.chat-container.dark .ffz-ui-toggle.news svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.news svg.svg-emoticons path, -.ffz-ui-toggle.news svg.svg-emoticons path { fill: rgba(117, 80, 0, 0.5); } - -.ember-chat-container.dark .ffz-ui-toggle.news:hover svg.svg-emoticons path, -.app-main.theatre .ffz-ui-toggle.news:hover svg.svg-emoticons path, -.chat-container.dark .ffz-ui-toggle.news:hover svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.news:hover svg.svg-emoticons path, -.ffz-ui-toggle.news:hover svg.svg-emoticons path { fill: rgba(117, 80, 0, 0.8); } - -.ember-chat-container.dark .ffz-ui-toggle.no-emotes svg.svg-emoticons path, -.app-main.theatre .ffz-ui-toggle.no-emotes svg.svg-emoticons path, -.chat-container.dark .ffz-ui-toggle.no-emotes svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.no-emotes svg.svg-emoticons path { fill: #453434; } - -.ember-chat-container.dark .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path, -.app-main.theatre .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path, -.chat-container.dark .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.no-emotes:hover svg.svg-emoticons path { fill: #543f3f; } - -.ember-chat-container.dark .ffz-ui-toggle.live svg.svg-emoticons path, -.app-main.theatre .ffz-ui-toggle.live svg.svg-emoticons path, -.chat-container.dark .ffz-ui-toggle.live svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.live svg.svg-emoticons path { fill: #513c78; } - -.ember-chat-container.dark .ffz-ui-toggle.live:hover svg.svg-emoticons path, -.app-main.theatre .ffz-ui-toggle.live:hover svg.svg-emoticons path, -.chat-container.dark .ffz-ui-toggle.live:hover svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.live:hover svg.svg-emoticons path { fill: #5b4487; } - -.ember-chat-container.dark .ffz-ui-toggle.blue.live svg.svg-emoticons path, -.app-main.theatre .ffz-ui-toggle.blue.live svg.svg-emoticons path, -.chat-container.dark .ffz-ui-toggle.blue.live svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.blue.live svg.svg-emoticons path { fill: #3c4e78; } - -.ember-chat-container.dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path, -.app-main.theatre .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path, -.chat-container.dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path, -.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.blue.live:hover svg.svg-emoticons path { fill: #445887; } - - -.ffz-ui-toggle.live { - animation: ffzfade 8s linear infinite; - -webkit-animation: ffzfade 8s linear infinite; -} - -@-webkit-keyframes ffzfade { - from, to { opacity: 1; } - 50% { opacity: 0.75; } -} - -@keyframes ffzfade { - from, to { opacity: 1; } - 50% { opacity: 0.75; } -} - - -.ember-chat .chat-menu.ffz-ui-popup { padding: 0; } - -.ffz-button { - float: right; - margin-top: -6px; - text-transform: none; -} - -.ffz-noty .noty_message { - background-image: url("//cdn.frankerfacez.com/icon32.png") !important; - background-repeat: no-repeat !important; - background-position: 5px 10px !important; - padding-left: 42px !important; - text-align: left; -} - -.ffz-ui-popup .button.live { overflow: hidden; background: #6441A5; color: #fff; } -.ffz-ui-popup .button.live span { z-index: 2; position: relative; } - -.ffz-ui-popup .button.live:before, .ffz-ui-popup .button.live:after { - content: ""; - display: block; - position: absolute; - width: 0px; - height: 0px; - border-radius: 999px; - -moz-border-radius: 999px; - -webkit-border-radius: 999px; - top: 50%; - left: 50%; - z-index: 1 -} - -.ffz-ui-popup .button.live.purple:before, .ffz-ui-popup .button.live.purple:after { - box-shadow: 0 0 3px 1px #a68ed2,inset 0 0 3px 1px #a68ed2; - -moz-box-shadow: 0 0 3px 1px #a68ed2,inset 0 0 3px 1px #a68ed2; - -webkit-box-shadow: 0 0 3px 1px #a68ed2,inset 0 0 3px 1px #a68ed2; -} - -.ffz-ui-popup .button.live.blue:before, .ffz-ui-popup .button.live.blue:after { - box-shadow: 0 0 3px 1px #8ea2d1,inset 0 0 3px 1px #8ea2d1; - -moz-box-shadow: 0 0 3px 1px #8ea2d1,inset 0 0 3px 1px #8ea2d1; - -webkit-box-shadow: 0 0 3px 1px #8ea2d1,inset 0 0 3px 1px #8ea2d1; -} - -.ffz-ui-popup .button.live:before { - animation: expand 1500ms infinite ease-in; - -moz-animation: expand 1500ms infinite ease-in; - -webkit-animation: expand 1500ms infinite ease-in; - -o-animation: expand 1500ms infinite ease-in -} - -.ffz-ui-popup .button.live:after { - animation: expand 1500ms infinite 750ms ease-in; - -moz-animation: expand 1500ms infinite 750ms ease-in; - -webkit-animation: expand 1500ms infinite 750ms ease-in; - -o-animation: expand 1500ms infinite 750ms ease-in -} - -#dash_main #stats .stat.dark#ffz_count svg path { fill: #cacaca; } - -#ffz-ui-following .follow-button a { - padding: 0 10px; - color: #fff; -} - -#ffz-following-popup { - background-image: url('//cdn.frankerfacez.com/script/zreknarf-bg.png'); - background-repeat: no-repeat; - background-position: 115% -75%; - background-size: 50%; -} - -.ffz-live-team-channel .ffz-game { - display: inline-block; - max-width: 150px; - text-overflow: ellipsis; - overflow: hidden; - margin-bottom: -5px; -} - -/* Theater Mode hover bar */ - -.app-main.theatre .player-column:focus #hostmode > div.target-meta, -.app-main.theatre .player-column:hover #hostmode > div.target-meta, -.app-main.theatre #channel .player-column:focus #broadcast-meta, -.app-main.theatre #channel .player-column:hover #broadcast-meta { - background-color: #19191f; - color: #aaa; - - position: absolute; - top: -25px; - left: 120px; - right: 10px; - z-index: 7; - opacity: 0.95; - height: 20px; -} - -.ffz-sidebar-swap .app-main.theatre .player-column:focus #hostmode > div.target-meta, -.ffz-sidebar-swap .app-main.theatre .player-column:hover #hostmode > div.target-meta, -.ffz-sidebar-swap .app-main.theatre #channel .player-column:focus #broadcast-meta, -.ffz-sidebar-swap .app-main.theatre #channel .player-column:hover #broadcast-meta { - left: 145px; -} - -.app-main.theatre #hostmode > div.target-meta div.target-title { - padding: 5px 0 2px 5px; -} - -.app-main.theatre #hostmode > div.target-meta div.target-title, -.app-main.theatre #channel .player-column #broadcast-meta .info { padding-left: 5px; } - -.app-main.theatre #hostmode > div.target-meta div.target-title, -.app-main.theatre #channel .player-column #broadcast-meta .info .title { - font-size: 12px; - line-height: 20px; - color: #dedede; -} - -.app-main.theatre #hostmode > div.target-meta div.target-title, -.app-main.theatre #channel .player-column #broadcast-meta .info .title, -.app-main.theatre #channel .player-column #broadcast-meta .info .title .over { - background-color: rgba(16,16,16,0.3); -} - -.app-main.theatre #hostmode > div.target-meta .target-user-and-game, -.app-main.theatre #channel .player-column #broadcast-meta .info .channel, -.app-main.theatre #channel .player-column #broadcast-meta .info .edit-link, -.app-main.theatre #broadcast-meta .profile-link { - display: none; -} - -.app-main.theatre .player-column:focus #hostmode > div.clearfix, .app-main.theatre .player-column:hover #hostmode > div.clearfix { - margin-bottom: 30px; -} - -.app-main.theatre .player-column:focus #hostmode > div.clearfix, .app-main.theatre .player-column:hover #hostmode > div.clearfix, -.app-main.theatre .player-column:focus .stats-and-actions, .app-main.theatre .player-column:hover .stats-and-actions { - background-color: #19191f; - - color: #aaa; - - position: absolute; - bottom: 10px; - margin-right: 150px; - left: 10px; - z-index: 7; - padding: 10px; - opacity: 0.95; -} - -.app-main.theatre .channel-stats .stat { color: #aaa; } - -.app-main.theatre .channel-stats span:not(.live-count) svg path { - fill: rgba(255,255,255,0.35) !important; -} - -.app-main.theatre .follow-button .notify:before, -.app-main.theatre .button.drop:after, -.app-main.theatre .follow-button .drop.follow:after { - border: 5px solid rgba(255,255,255,0.35); - border-left-color: transparent; - border-right-color: transparent; - border-bottom-color: transparent; -} - -.app-main.theatre .follow-button .notify { - background-color: #25252a; -} - -.app-main.theatre .button { - color: #a68ed2; -} - -.app-main.theatre .button.glyph-only svg path { - fill: #a68ed2; -} - -.app-main.theatre .button.primary.subscribe-button { - color: #fff; -} - - -/* SRL Race Support */ - -#ffz-following-popup.right { - right: 0; - left: auto; -} - -#ffz-ui-following .notification-controls, -#ffz-ui-race { - position: relative; -} - -#ffz-ui-race .button span { - display: inline-block; - height: 30px; - background: no-repeat 0 50%; -} - -#ffz-ui-race .button span.logo { - padding-left: 44px; - background-image: url("//cdn.frankerfacez.com/script/srl_button.png"); -} - - -#ffz-race-popup { - position: absolute; - bottom: 0; - background-image: url("//cdn.frankerfacez.com/script/zreknarf-bg.png"); - background-repeat: no-repeat; - background-position: 115% 110%; -} - -#ffz-race-popup.right { right: 10px; } - -#ffz-race-popup .heading { - margin: -20px -20px 20px; - width: 340px; height: 65px; - position: relative; -} - -#ffz-race-popup .heading div { - padding: 10px 0 0 20px; - max-width: 240px; -} - -#ffz-race-popup .heading h2 { - font-size: 1.5em; - padding-bottom: 5px; - display: block; - width: 240px; - max-height: 45px; - overflow: hidden; - text-overflow: ellipsis; -} - -#ffz-race-popup .heading span { - line-height: 30px; - position: absolute; - top: 17.5px; - right: 20px; - padding: 0 5px; - background: rgba(0,0,0,0.5); - color: #fff; - border-radius: 5px; -} - -#ffz-race-popup .right { text-align: right; } - -#ffz-race-popup .table { - overflow-y: auto; -} - -#ffz-race-popup table { - width: 100%; - text-align: center; - border-spacing: 0; -} - -#ffz-race-popup table a { - color: inherit; -} - -.ffz-about-table a.twitch, -.ffz-about-table a.youtube, -.ffz-about-table a.twitter, -#ffz-race-popup a.twitch, -#ffz-race-popup a.hitbox { - display: inline-block; - height: 16px; - margin-left: 5px; - background-repeat: no-repeat; -} - -.ffz-about-table a.youtube { - width: 23px; - background-image: url("//cdn.frankerfacez.com/script/youtube_logo.png"); -} - -.ffz-about-table a.twitter { - width: 20px; - background-image: url("//cdn.frankerfacez.com/script/twitter_logo.png"); -} - -#ffz-race-popup a.twitch, -.ffz-about-table a.twitch { - width: 15px; - background-image: url("//cdn.frankerfacez.com/script/twitch_logo.png"); -} - -#ffz-race-popup a.hitbox { - width: 12px; - background-image: url("//cdn.frankerfacez.com/script/hitbox_logo.png"); -} - -#ffz-race-popup table tbody tr.done:nth-child(0n+1) td { background-color: rgba(255,255,0,.2); } -#ffz-race-popup table tbody tr.done:nth-child(0n+2) td { background-color: rgba(128,128,128,.2); } -#ffz-race-popup table tbody tr.done:nth-child(0n+3) td { background-color: rgba(210,100,0,.2); } -#ffz-race-popup table tbody tr.forfeit td { opacity: 0.5; background-color: rgba(210,100,100,.2); } -#ffz-race-popup table tbody tr.racing td.time { opacity: 0.5; } - -#ffz-race-popup table th, #ffz-race-popup td { padding: 1px; } -#ffz-race-popup table th { border-bottom: 1px solid; } - - -/* Menu Options */ - -.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content.menu-side-padding { padding-left: 20px; padding-right: 20px; } - -.emoticon-grid.collapsed span, -.chat-menu-content.collapsed p { display: none; } - -.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content.collapsed .heading, -.chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid.collapsed .heading { - padding-bottom: 0; -} - -.emoticon-grid.collapsable .heading, -.emoticon-grid.collapsed, -.chat-menu-content.collapsed { - cursor: pointer; -} - -.emoticon-grid.collapsable .heading, -.chat-menu-content.collapsable .heading { - position: relative; -} - -.list-header span.right { float: right; } - -.chat-menu-content.collapsable .heading span.right { - padding-right: 15px; -} - -.emoticon-grid.collapsable .heading:before, -.chat-menu-content.collapsable .heading:before { - content: ""; - border: 5px solid #666; - border-left-color: transparent; - border-right-color: transparent; - - position: absolute; - margin-top: 6px; - right: 20px; -} - -.emoticon-grid.collapsable.collapsed .heading:before, -.chat-menu-content.collapsable.collapsed .heading:before { border-bottom-color: transparent; } - -.emoticon-grid.collapsable:not(.collapsed) .heading:before { - display: none; -} - -.chat-menu-content.collapsable:not(.collapsed) .heading:before { - border-top-color: transparent; - margin-top: 1px; -} - - -#small_nav .content ul li#ffz_small_menu .filter_icon svg { - margin: 11px 13px; -} - -.ffz-ui-sub-menu-page, -.ffz-ui-menu-page { overflow-y: auto; } - -.ffz-ui-menu-page[data-page="about"], -.ffz-ui-menu-page .chat-menu-content p { padding: 0 20px; } - - -.chat-container.dark .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box, -.app-main.theatre .chat-container .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box, -.chat-container.force-dark .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box, -.ember-chat-container.dark .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box, -.ember-chat-container.force-dark .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box { - background-color: rgb(16,16,16); - color: rgb(195,195,195); - border-color: #32323e; -} - - -.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 { - padding: 10px 20px; - border-top: 1px solid rgba(0,0,0,0.2); - text-align: left; -} - -.chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid .heading { - padding-left: 43px; - background-repeat: no-repeat; - background-position: 20px 10px; -} - -.chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid + .emoticon-grid { padding-top: 0; } - -.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content:first-of-type .heading, -.chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid:first-of-type .heading { - border-top: none; - padding-top: 0; - background-position-y: 0; -} - -.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content { - padding: 10px 0; - background-color: transparent; -} - -.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content + .chat-menu-content { - padding-top: 0; -} - -.ffz-ui-menu-page span.help { - display: block; - opacity: 0.75; -} - -.ffz-ui-menu-page p.disabled span.switch-label, -.ffz-ui-menu-page span.help, -.ffz-ui-menu-page span.option-label, -.ffz-ui-menu-page p.option a { - margin-left: 50px; -} - -.ffz-ui-menu-page span.option-label { - line-height: 25px; -} - -.ffz-ui-menu-page input, -.ffz-ui-menu-page select { - margin: 0 10px 5px; -} - -.ffz-ui-menu-page input[type="file"] { - width: auto; -} - -#ffz-chat-menu { pointer-events: none; } - -.ffz-ui-popup ul.menu { - list-style-type: none; - border-top: 1px solid rgba(0,0,0,0.2); - background-color: #eee; -} - -.ffz-ui-popup ul.menu:not(.sub-menu) { - cursor: ew-resize; -} - -.ffz-ui-popup .emoticon-selector-box { - width: 10000px !important; /* Max-width has our back */ - max-width: 300px; - pointer-events: auto; -} - -.ember-chat .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box .emoticon-grid { background-color: transparent; } - -.app-main.theatre .ffz-ui-popup ul.menu, -.chat-container.dark .ffz-ui-popup ul.menu, -.chat-container.force-dark .ffz-ui-popup ul.menu, -.ember-chat-container.dark .ffz-ui-popup ul.menu, -.ember-chat-container.force-dark .ffz-ui-popup ul.menu, -.ffz-ui-popup.dark ul.menu { - background-color: #282828; -} - -.ffz-ui-popup ul.sub-menu li.title, -.ffz-ui-menu-page .heading .right, -.ffz-ui-popup ul.menu li.item { - float: right; -} - -.ffz-ui-popup ul.sub-menu li.item, -.ffz-ui-popup ul.menu li.title { - float: left; -} - -.ffz-ui-popup ul.sub-menu { background-color: #dfdfdf; } - -.app-main.theatre .ffz-ui-popup ul.sub-menu, -.chat-container.dark .ffz-ui-popup ul.sub-menu, -.chat-container.force-dark .ffz-ui-popup ul.sub-menu, -.ember-chat-container.dark .ffz-ui-popup ul.sub-menu, -.ember-chat-container.force-dark .ffz-ui-popup ul.sub-menu, -.ffz-ui-popup.dark ul.sub-menu { - background-color: #181818; -} - -.ffz-ui-popup ul.sub-menu a { - text-decoration: none; - color: #333; -} - -.app-main.theatre .ffz-ui-popup ul.sub-menu a, -.chat-container.dark .ffz-ui-popup ul.sub-menu a, -.chat-container.force-dark .ffz-ui-popup ul.sub-menu a, -.ember-chat-container.dark .ffz-ui-popup ul.sub-menu a, -.ember-chat-container.force-dark .ffz-ui-popup ul.sub-menu a, -.ffz-ui-popup.dark ul.sub-menu a { - color: #d3d3d3 !important; -} - -span.ffz-handle { - display: inline-block; - position: relative; - height: 26px; - width: 14px; - transition: width 500ms; -} - -span.ffz-handle:before, -span.ffz-handle:after { - position: absolute; - left: 4px; - top: 5px; - content: ""; - height: 14px; - border: 1px solid #bbb; - border-radius: 4px; - transition: transform 500ms, left 500ms, border-color 500ms, border-width 500ms, height 500ms; -} - -span.ffz-handle:after { left: 8px } - -.ffz-ui-popup.ui-moved span.ffz-handle { width: 24px; cursor: pointer; } - -.ffz-ui-popup.ui-moved span.ffz-handle:before, -.ffz-ui-popup.ui-moved span.ffz-handle:after { - left: 11px; - border-color: #333; -} - -.ffz-ui-popup.ui-moved span.ffz-handle:before { transform: rotate(45deg); } -.ffz-ui-popup.ui-moved span.ffz-handle:after { transform: rotate(-45deg); } - -.app-main.theatre span.ffz-handle:before, -.chat-container.dark span.ffz-handle:before, -.chat-container.force-dark span.ffz-handle:before, -.ember-chat-container.dark span.ffz-handle:before, -.ember-chat-container.force-dark span.ffz-handle:before, -.ffz-ui-popup.dark span.ffz-handle:before, -.app-main.theatre span.ffz-handle:after, -.chat-container.dark span.ffz-handle:after, -.chat-container.force-dark span.ffz-handle:after, -.ember-chat-container.dark span.ffz-handle:after, -.ember-chat-container.force-dark span.ffz-handle:after, -.ffz-ui-popup.dark span.ffz-handle:after { - border-color: #666; -} - -.app-main.theatre .ffz-ui-popup.ui-moved span.ffz-handle:before, -.chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:before, -.chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:before, -.ember-chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:before, -.ember-chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:before, -.ffz-ui-popup.ui-moved.dark span.ffz-handle:before, -.app-main.theatre .ffz-ui-popup.ui-moved span.ffz-handle:after, -.chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:after, -.chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:after, -.ember-chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:after, -.ember-chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:after, -.ffz-ui-popup.ui-moved.dark span.ffz-handle:after { - border-color: #d3d3d3; -} - - -.ffz-ui-popup ul.menu li.title > span.ffz-handle { - float: left; - margin: 5px; -} - -.ffz-ui-popup ul.menu li.title > span.title { - display: block; - margin-left: 24px; - padding: 10px 20px 10px 0; - line-height: 16px; - transition: margin-left 500ms; -} - -.ffz-ui-popup.ui-moved ul.menu li.title > span.title { margin-left: 34px; } - -.ffz-ui-popup ul.menu a { - display: block; - padding: 10px; - height: 16px; - margin-top: -1px; - cursor: pointer; - border-left: 1px solid rgba(0,0,0,0.2); - border-top: 1px solid transparent; -} - -.ffz-ui-popup ul.sub-menu a { - border-left: none; - border-right: 1px solid rgba(0,0,0,0.2); -} - -.ffz-ui-popup ul.menu li.active { - background-color: #fff; -} - -.ffz-ui-popup ul.menu li.active a { - border-top-color: #fff; -} - -.ffz-ui-popup ul.menu li.active.has-sub-menu { - background-color: #dfdfdf; -} - -.ffz-ui-popup ul.menu li.active.has-sub-menu a { - border-top-color: #dfdfdf; -} - - -.chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active, -.chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active, -.ember-chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active, -.ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active, -.app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu li.active, -.ffz-ui-popup.dark ul.menu li.active { - background-color: rgb(16,16,16); -} - -.chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active a, -.chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active a, -.ember-chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active a, -.ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active a, -.app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu li.active a, -.ffz-ui-popup.dark ul.menu li.active a { - border-top-color: rgb(16,16,16); -} - -.chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu, -.chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu, -.ember-chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu, -.ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu, -.app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu, -.ffz-ui-popup.dark ul.menu li.active.has-sub-menu { - background-color: #181818; -} - -.chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu a, -.chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu a, -.ember-chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu a, -.ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu a, -.app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu a, -.ffz-ui-popup.dark ul.menu li.active.has-sub-menu a { - border-top-color: #181818; -} - -.chat-container.dark .chat-interface .ffz-ui-popup a, -.chat-container.force-dark .chat-interface .ffz-ui-popup a, -.ember-chat-container.dark .chat-interface .ffz-ui-popup a, -.ember-chat-container.force-dark .chat-interface .ffz-ui-popup a, -.app-main.theatre .chat-container .chat-interface .ffz-ui-popup a, -.ffz-ui-popup.dark .ffz-ui-menu-page a { color: #fff; } - - -.chat-container.dark .chat-interface .ffz-ui-popup ul.menu svg path, -.chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu svg path, -.ember-chat-container.dark .chat-interface .ffz-ui-popup ul.menu svg path, -.ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu svg path, -.app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu svg path, -.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; } - - -.ffz-ui-popup .option-label span, -.ffz-ui-popup .switch-label span { - opacity: 0.8; - font-size: 10px; - line-height: 20px; - padding: 4px; - background: rgba(0,0,0,0.2); - vertical-align: top; -} - -/* BTTV Menu Fixes */ - -.ffz-ui-popup.dark .emoticon-grid .heading, -.ffz-ui-popup.dark li.title { color: #fff; } -.ffz-ui-popup.dark .ffz-ui-menu-page { background-color: #1e1e1e; } - - -/* Menu Scrollbar */ - -.chat-history::-webkit-scrollbar, -#ffz-race-popup .table::-webkit-scrollbar, -.emoticon-selector-box .all-emotes::-webkit-scrollbar, -.ffz-ui-sub-menu-page::-webkit-scrollbar, -.ffz-ui-menu-page::-webkit-scrollbar { - width: 6px; -} - -.chat-history::-webkit-scrollbar-thumb, -#ffz-race-popup .table::-webkit-scrollbar-thumb, -.emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, -.ffz-ui-sub-menu-page::-webkit-scrollbar-thumb, -.ffz-ui-menu-page::-webkit-scrollbar-thumb { - border-radius: 7px; - background: rgba(0,0,0,0.7); - box-shadow: 0 0 1px 1px rgba(255,255,255,0.25); -} - -.ffz-dark .chat-history::-webkit-scrollbar-thumb, -.ffz-dark .table::-webkit-scrollbar-thumb, -.ember-chat-container.dark .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, -.chat-container.dark .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, -.app-main.theatre .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, -.ember-chat-container.dark .ffz-ui-menu-page::-webkit-scrollbar-thumb, -.chat-container.dark .ffz-ui-menu-page::-webkit-scrollbar-thumb, -.app-main.theatre .ffz-ui-menu-page::-webkit-scrollbar-thumb, -.ember-chat-container.dark .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb, -.chat-container.dark .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb, -.app-main.theatre .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb { - background: rgba(255,255,255,0.6); - box-shadow: 0 0 1px 1px rgba(0,0,0,0.25); -} - - -/* Chat Mentions */ - -.ember-chat .mentioned:empty, -.ember-chat .mentioning:empty { - display: none; -} - -.ffz-chat-colors-gray .chat-line:not(.admin):not(.notification) span.from, -.ffz-chat-colors-gray .chat-line:not(.admin):not(.notification) span.message { - color: inherit !important -} - -.ffz-chat-background .ember-chat .mentioning, -.ffz-chat-background .ember-chat .mentioned { - border-radius: 10px; - padding: 3px 7px; - font-weight: bold; - color: #32323e; - background-color: rgba(255,255,255, 0.75); -} - -.ffz-chat-background .app-main.theatre .chat-container .chat-line .mentioned, -.ffz-chat-background .ember-chat-container.dark .chat-line .mentioned, -.ffz-chat-background .chat-container.dark .chat-line .mentioned, -.ffz-chat-background .app-main.theatre .chat-container .chat-line .mentioning, -.ffz-chat-background .ember-chat-container.dark .chat-line .mentioning, -.ffz-chat-background .chat-container.dark .chat-line .mentioning { - color: #8c8c9c; - background-color: rgba(16,16,20, 0.75); -} - - -/* Fix Moderation Cards */ - -img.channel_background[src="null"] { display: none; } - -.ember-chat .ffz-moderation-card { - border: 2px solid #cbcbcb; - max-width: 340px; - /*box-shadow: #808080 0 0 5px;*/ -} - -.ember-chat .ffz-moderation-card .extra-interface { - padding-top: 0; -} - -.ember-chat .ffz-moderation-card .extra-interface + .extra-interface { - margin-top: -10px; -} - -.ember-chat .ffz-moderation-card.ffz-has-info h3.name { - margin-top: 0; -} - -.ember-chat .ffz-moderation-card .info { - float: none; - position: relative; - z-index: 4; - margin-left: 50px; - height: 18px; - line-height: 18px; -} - -.ember-chat .ffz-moderation-card .info.channel-stats .stat { - color: #fff; -} - -.ember-chat .ffz-moderation-card .info.channel-stats .stat svg { - margin: 1px 5px 1px 0; - pointer-events: none; -} - -.ember-chat .ffz-moderation-card .info svg path { fill: #fff; } - -.ember-chat .ffz-moderation-card button { - margin: 0; - padding: 0 5px; -} - -.ember-chat .ffz-moderation-card button:not(.glyph-only):hover, -.ember-chat .ffz-moderation-card button:not(.glyph-only):focus { - color: #fff; - background-color: rgba(117,80,186, 1); -} - -.ember-chat .ffz-moderation-card button.message { - height: 30px; width: 28px; -} - -.ember-chat .ffz-moderation-card.ffz-is-mod .interface .mod-controls:last-of-type, -.ember-chat .ffz-moderation-card .interface span.right { - float: right; -} - -.ember-chat .ffz-moderation-card:focus { - outline: none; - border-color: #444; - /*box-shadow: #000 0 0 5px;*/ -} - -.ember-chat .ffz-moderation-card .interface:not(:last-of-type) { - border-bottom: none; -} - -.ember-chat .ffz-moderation-card .interface { - border-top: none; -} - -.ember-chat .ffz-moderation-card h3.name { display: inline-block; } - -.ember-chat .ffz-moderation-card .info, -.ember-chat .ffz-moderation-card h3.name { - text-shadow: black 0 0 5px; -} - -.ember-chat .ffz-moderation-card .channel_background { - width: 100%; - top: 0; -} - - -body:not(.ffz-chat-purge-icon) .ember-chat .mod-icons .purge { display: none; } - -.ember-chat .mod-icons .purge { - background-image: url('//cdn.frankerfacez.com/script/PurgeButton.svg'); - background-repeat: no-repeat; -} - -.ember-chat .mod-icons .custom { - text-indent: 0; - text-align: center; - text-decoration: none; - font-size: 18px; - font-weight: bold; - color: #888 !important; -} - - -/* Chat Rows */ - -.ffz-alias { font-style: italic; } - -.ember-chat .chat-messages .chat-line.ffz-has-deleted { - line-height: 30px; -} - -.chat-line.ffz-deleted > span { - opacity: 0.5; -} - -.chat-line.ffz-deleted > span.message { - text-decoration: line-through; -} - -.chat-line.ffz-deleted:hover > span { - opacity: 0.9; -} - -.chat-line.ffz-deleted:hover > span.message { - text-decoration: none; -} - -.ffz-chat-background .more-messages-indicator { - /* This looks better when it's full width. */ - margin: 0 -20px; -} - -.ffz-chat-background .chat-line .message { - word-break: break-word; -} - -.ffz-chat-background .ember-chat .chat-messages .tse-scroll-content { - padding: 0; -} - -/* This cuts off emotes. -.ffz-chat-background .ember-chat .chat-messages .chat-line { - padding: 3px 20px; - margin: 0px 0px; -} */ - -.ffz-chat-separator .chat-line, -.ffz-chat-background .chat-line { - position: relative; - z-index: 1; -} - -.ffz-chat-padding .ember-chat .chat-messages .chat-line, -.ffz-chat-padding .ember-chat .chat-messages .chat-line.admin { - padding: 5px; -} - -.ffz-chat-separator .chat-line:before, -.ffz-chat-background .chat-line:before { - content: ""; - position: absolute; - z-index: -1; - left: 0; right: 0; - top: 2px; bottom: 1px; -} - -.ffz-chat-background .chat-history .chat-line:before { - top: 0; bottom: 0; -} - -.ffz-chat-separator .chat-line:before { - border-bottom: 1px solid #aaa; -} - -.ffz-chat-separator-wide .chat-line:before { - border-top: 1px solid #aaa; -} - -.ffz-chat-separator-3d .chat-line:before { - border-top: 1px solid rgba(255,255,255,0.5); -} - -.ffz-chat-separator-3d-inset .chat-line:before { - border-bottom-color: rgba(255,255,255,0.5); - border-top: 1px solid #aaa; -} - -.ffz-chat-separator-3d ul.chat-lines div:first-of-type .chat-line:before { - border-top: none; -} - -.ffz-chat-separator:not(.ffz-chat-background) ul.chat-lines div:last-of-type .chat-line:before, -.ffz-chat-separator ul.chat-lines div:last-of-type .chat-line:not(.ffz-alternate):before { - border-bottom: none; -} - -.ffz-chat-separator .app-main.theatre .chat-line:before, -.ffz-chat-separator .chat-container.dark .chat-line:before, -.ffz-chat-separator .chat-container.force-dark .chat-line:before, -.ffz-chat-separator .ember-chat-container.dark .chat-line:before, -.ffz-chat-separator .ember-chat-container.force-dark .chat-line:before { - border-bottom-color: #000; -} - -.ffz-chat-separator-wide .app-main.theatre .chat-line:before, -.ffz-chat-separator-wide .chat-container.dark .chat-line:before, -.ffz-chat-separator-wide .chat-container.force-dark .chat-line:before, -.ffz-chat-separator-wide .ember-chat-container.dark .chat-line:before, -.ffz-chat-separator-wide .ember-chat-container.force-dark .chat-line:before { - border-top-color: #000; -} - -.ffz-chat-separator-3d .app-main.theatre .chat-line:before, -.ffz-chat-separator-3d .chat-container.dark .chat-line:before, -.ffz-chat-separator-3d .chat-container.force-dark .chat-line:before, -.ffz-chat-separator-3d .ember-chat-container.dark .chat-line:before, -.ffz-chat-separator-3d .ember-chat-container.force-dark .chat-line:before { - border-top-color: rgba(255,255,255,0.1); -} - -.ffz-chat-separator-3d-inset .app-main.theatre .chat-line:before, -.ffz-chat-separator-3d-inset .chat-container.dark .chat-line:before, -.ffz-chat-separator-3d-inset .chat-container.force-dark .chat-line:before, -.ffz-chat-separator-3d-inset .ember-chat-container.dark .chat-line:before, -.ffz-chat-separator-3d-inset .ember-chat-container.force-dark .chat-line:before { - border-bottom-color: rgba(255,255,255,0.1); - border-top-color: #000; -} - -.ffz-chat-background .chat-history .chat-line.ffz-alternate:before, -.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-alternate:before { - background-color: rgba(0,0,0, 0.1); -} - -.ffz-chat-background .chat-history .chat-line.ffz-mentioned:before, -.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-mentioned:before { - background-color: rgba(255,127,127, 0.2); -} - -.ffz-chat-background .chat-history .chat-line.ffz-mentioned-ffz-alternate:before, -.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate:before { - background-color: rgba(255,127,127, 0.4); -} - - -.ffz-chat-background .app-main.theatre .chat-history .chat-line.ffz-alternate:before, -.ffz-chat-background .chat-container.dark .chat-history .chat-line.ffz-alternate:before, -.ffz-chat-background .ember-chat-container.dark .chat-history .chat-line.ffz-alternate:before, -.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .chat-line.ffz-alternate:before, -.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-alternate:before, -.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .chat-line.ffz-alternate:before { - background-color: rgba(255,255,255, 0.05); -} - - -.ffz-chat-background .app-main.theatre .chat-history .chat-line.ffz-mentioned:before, -.ffz-chat-background .chat-container.dark .chat-history .chat-line.ffz-mentioned:before, -.ffz-chat-background .ember-chat-container.dark .chat-history .chat-line.ffz-mentioned:before, -.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .chat-line.ffz-mentioned:before, -.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned:before, -.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned:before { - background-color: rgba(255,0,0, 0.2); -} - -.ffz-chat-background .app-main.theatre .chat-history .chat-line.ffz-mentioned.ffz-alternate:before, -.ffz-chat-background .chat-container.dark .chat-history .chat-line.ffz-mentioned.ffz-alternate:before, -.ffz-chat-background .ember-chat-container.dark .chat-history .chat-line.ffz-mentioned.ffz-alternate:before, -.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate:before, -.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate:before, -.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate:before { - background-color: rgba(255,0,0, 0.3); -} -*/ - -/* The New Whispers */ - -.ffz-chat-background .ember-chat .chat-messages .whisper-line { - padding-left: 16px; - border-left-width: 4px !important; -} - -.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .whisper-line.whisper-incoming:before, -.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming:before, -.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming:before { - /* 675980 */ - background-color: rgba(78,51,128, 0.4); -} - -.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .whisper-line.whisper-incoming.ffz-alternate:before, -.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming.ffz-alternate:before, -.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming.ffz-alternate:before { - /* 675980 */ - background-color: rgba(78,51,128, 0.5); -} - -.ffz-chat-background .ember-chat .chat-messages .whisper-line.whisper-incoming:before { - background-color: rgba(205,178,255, 0.4); -} - -.ffz-chat-background .ember-chat .chat-messages .whisper-line.whisper-incoming.ffz-alternate:before { - background-color: rgba(205,178,255, 0.6); -} - - - -/* Temporary Fix */ - -.chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming, -.app-main.theatre .chat-container .ember-chat .chat-messages .whisper-line.whisper-incoming, -.chat-container.force-dark .ember-chat .chat-messages .whisper-line.whisper-incoming, -.ember-chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming, -.app-main.theatre .ember-chat-container.chat-container .ember-chat .chat-messages .whisper-line.whisper-incoming, -.ember-chat-container.force-dark .ember-chat .chat-messages .whisper-line.whisper-incoming { - background-color: #101014; - border-left: 2px solid #a68ed2 -} - - -/* Emoticon Tooltips */ - -.ffz-wide-tip .tipsy-inner { - min-width: 300px; - max-width: 600px; - text-align: left; - position: relative; -} - -.ffz-wide-tip span.stat { - float: right; - margin-left: 5px; -} - -.ffz-wide-tip b { margin-right: 20px; } - -.ffz-wide-tip span.stat svg { - float: left; - margin: 1px; -} - -.ffz-wide-tip svg path { fill: #fff; } -.ffz-wide-tip span.playing { - opacity: 0.7; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - display: block; - position: relative; - left: 0; - right: 0; -} - -.tipsy .tipsy-inner { - white-space: pre-wrap; -} - -/* Menu Page Loader */ - -.ffz-ui-sub-menu-page:empty, -.ffz-ui-menu-page:empty { - overflow: hidden; -} - -.ffz-ui-sub-menu-page:empty::after, -.ffz-ui-menu-page:empty::after { - content: " "; - display: block; - width: 80px; - height: 63px; - - background-image: url("//cdn.frankerfacez.com/script/spinner-dark.png"); - - margin: 50px auto; - -webkit-animation: ffz-rotateplane 1.2s infinite linear; - animation: ffz-rotateplane 1.2s infinite linear; -} - -@-webkit-keyframes ffz-rotateplane { - 0% { -webkit-transform: perspective(120px) rotateY(90deg) } - 25% { -webkit-transform: perspective(120px) rotateY(180deg) } - 75% { -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg) } - 100% { -webkit-transform: perspective(120px) rotateY(90deg) rotateX(180deg) } -} - -@keyframes ffz-rotateplane { - 0% { transform: perspective(120px) rotateY(90deg) } - 25% { transform: perspective(120px) rotateY(180deg) } - 75% { transform: perspective(120px) rotateY(180deg) rotateX(180deg) } - 100% { transform: perspective(120px) rotateY(90deg) rotateX(180deg) } -} - -/* Menu About Page */ - -.ffz-about-table { - width: 100%; -} - -.ffz-about-table td:first-child { - text-align: left; - width: 100%; -} - -.ffz-about-table .debug td { - padding-top: 10px; - opacity: 0.8; - font-size: 10px; -} - -.ffz-about-subheading { - /*text-transform: uppercase;*/ - letter-spacing: 2px; - margin: -5px 0 5px; -} - -.button.ffz-news, -.button.ffz-donate { - margin-left: 10px; - color: #fff !important; - padding: 0 10px; - font-size: 12px; -} - -.button.ffz-donate { background: #00b132; } -.button.ffz-donate:not(.disabled):hover { background: #08c43d; } - -.button.ffz-news { background: #755000; } -.button.ffz-news:not(.disabled):hover { background: #8a5f03; } - - -/* Dumb Fixes */ - -.ffz-bttv .no-bttv { display: none; } - -.chat-container.dark, .app-main.theatre .chat-container, -.chat-container.force-dark, .ember-chat-container.dark, -.app-main.theatre .ember-chat-container.chat-container, -.ember-chat-container.force-dark { - box-shadow: none; -} - - -/* Unsafe Links */ - -a.unsafe-link { - color: #a64141 !important; -} - -.chat-container.dark .chat-line a.unsafe-link { - color: #d28e8e !important; -} - -/* Chat Menu */ - -.ffz-room-list > div.ffz + ul.room-list { display: block !important; } - -.ffz-room-list > div:not(.ffz), -.ffz-room-list > ul:not(.ffz) { - display: none !important; -} - -.ffz-room-list > table { - padding: 15px 0 0; -} - -.ffz-room-list > table + table { - margin-top: 10px; -} - -.ffz-room-list > table th { - padding: 2px 5px; - color: #8c8c8c; - font-weight: normal; - text-transform: uppercase; -} - -.ffz-room-list > table > tbody tr { - line-height: 26px; -} - -.ffz-room-list > table td { - padding: 2px 0; - text-align: center; -} - -.ffz-room-list > table th:first-child, -.ffz-room-list > table td:nth-child(0n+2) { - width: 100%; - text-align: left; -} - -.ffz-room-row { - cursor: pointer; -} - -.ffz-room-list > table th:first-child, -.ffz-room-list > table td:first-child { - padding-left: 18px; -} - -.ffz-room-list > table th:last-child, -.ffz-room-list > table td:last-child { - padding-right: 18px; -} - -.ffz-room-list td svg { - margin: 5px; - float: left; -} - -.ffz-dark .ffz-room-row { color: #a68ed2; } -.ffz-dark .ffz-room-row svg path { fill: #a68ed2; } - -.ffz-room-row { color: #6441a5; } -.ffz-room-row svg path { fill: #6441a5; } - -.ffz-room-row:hover svg path, -.ffz-room-row:focus svg path, -.ffz-room-row.active svg path { fill: #fff; } - -.ffz-room-row:hover td, -.ffz-room-row:focus td, -.ffz-room-row.active td { - background-color: #6441A5; - color: #fff !important; -} - -th.ffz-row-switch { - min-width: 40px; -} - -.ffz-room-row a.leave-chat { - float: right; - margin-right: 12px; -} - -.ffz-row-switch .switch { - float: none; - margin: 5px 0 -4px; -} - -.ffz-row-switch .switch.active { - background-color: #362359; -} - - -/* Chat Tabs */ - -#ffz-group-tabs { - padding: 10px 10px 6px; - box-shadow: inset 0 -1px 0 0 rgba(0,0,0,0.2); - display: flex; - flex-wrap: wrap; -} - -.ffz-chat-tab { - flex-grow: 1; - position: relative; - - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - min-width: 70px; - - cursor: pointer; - padding: 5px; - margin: 0 4px 4px 0; - - display: inline-block; - - background-color: rgba(127,127,127,0.1); - color: #6441A5; -} - - -.ffz-chat-tab svg path { - fill: #6441A5; -} - -#ffz-group-tabs .button { - height: 18px; - padding-bottom: 10px; - margin-bottom: -10px; - margin-right: 4px; -} - -#ffz-group-tabs .button.glyph-only svg { - margin: 6px 0; -} - -.ffz-chat-tab svg { - width: 18px; - height: 18px; - margin: -5px 5px -5px 0; -} - -.ffz-chat-tab:hover, -.ffz-chat-tab:focus, -.ffz-chat-tab.active { - background-color: #6441A5; - color: #fff !important; -} - -.ffz-chat-tab.tab-mentioned { - background-color: rgba(128,50,50,0.1); - color: red !important; -} - -.ffz-chat-tab.tab-mentioned:not(.active):hover, -.ffz-chat-tab.tab-mentioned:not(.active):focus { - background-color: #a54141; - color: #fff !important; -} - -.ffz-chat-tab:not(.active):hover, -.ffz-chat-tab:not(.active):focus { - background-color: #7550ba; -} - -.ffz-chat-tab:hover svg path, -.ffz-chat-tab:focus svg path, -.ffz-chat-tab.active svg path { - fill: #fff !important; -} - -.ffz-chat-tab.active { - cursor: default; -} - -.ffz-chat-tab span:empty { display: none; } - -.ffz-chat-tab span { - padding: 0 4px; - display: inline-block; - border-radius: 2px; - text-align: center; - background-color: #f2f2f2; - color: #666; - position: absolute; - right: 5px; -} - - -/* Dark Group Tabs */ - -.app-main.theatre #ffz-group-tabs, -.chat-container.dark #ffz-group-tabs, -.ember-chat-container.dark #ffz-group-tabs { - box-shadow: inset 0 -1px 0 0 #32323e; -} - -.app-main.theatre .ffz-chat-tab, -.chat-container.dark .ffz-chat-tab, -.ember-chat-container.dark .ffz-chat-tab { - color: #B9A3E3; -} - -.app-main.theatre .ffz-chat-tab span, -.chat-container.dark .ffz-chat-tab span, -.ember-chat-container.dark .ffz-chat-tab span { - background-color: #19191f; - color: #fff; -} - -.app-main.theatre .ffz-chat-tab svg path, -.chat-container.dark .ffz-chat-tab svg path, -.ember-chat-container.dark .ffz-chat-tab svg path { - fill: #B9A3E3; -} - -/* Minimalistic Chat */ - -body.ffz-minimal-chat-head .ember-chat > .chat-header, -body.ffz-minimal-chat-head .ember-chat #ffz-group-tabs, -body.ffz-minimal-chat-input .ember-chat .chat-buttons-container { - display: none !important; -} - -/*body.ffz-minimal-chat .ember-chat .chat-messages, -body.ffz-minimal-chat .ember-chat .chat-interface .emoticon-selector { - bottom: 33px; -}*/ - -body.ffz-minimal-chat-input .ember-chat .chat-interface .emoticon-selector { - right: 10px; -} - -body.ffz-minimal-chat-input .ember-chat .chat-interface .emoticon-selector .dropmenu { - margin-bottom: 10px; -} - -body.ffz-minimal-chat-head .ember-chat .chat-room { - top: 0 !important; -} - -body.ffz-minimal-chat-input .ember-chat .chat-interface { - /*height: 33px !important;*/ - padding: 0; -} - -body.ffz-minimal-chat-input .ember-chat .chat-interface .textarea-contain { - top: 0 !important; - margin: 0 !important; - height: auto; -} - -body.ffz-minimal-chat-input .ember-chat .chat-interface .textarea-contain textarea { - /*height: 33px !important;*/ - overflow: hidden; - border-bottom: 0 !important; - border-left: 0; - border-right: 0; -} - -/* Chat Pause */ - -.ember-chat .chat-interface .more-messages-indicator.ffz-freeze-indicator { - opacity: 1; - cursor: default; - top: 0; -} - -/* Chat History */ - -.ember-chat .moderation-card .chat-history, -.chat-history { - list-style-type: none; - padding: 0; - max-height: 200px; - overflow-y: scroll; -} - -.chat-history.interface li:first-child { padding-top: 10px; } -.chat-history.interface li:last-child { padding-bottom: 10px; } - -.chat-history .chat-line { - line-height: 20px; - padding: 4px 10px; - word-wrap: break-word; - list-style-position: unset; -} - -.ember-chat .moderation-card .interface.chat-history .chat-line.action { - float: none; - margin-right: 0px; -} - -.chat-history .chat-line.admin .message { color: #666; } - -.chat-history .timestamp { - color: #8c8c8c; - margin-right: 5px; -} - -/* Room State */ - -.ffz.room-state.stat { - line-height: 30px; - margin-left: -10px; - margin-right: 15px; -} - -.ffz.room-state.truncated span { font-size: 8px; } - -.button.primary.ffz-waiting:not(:hover) { - background-color: rgba(0,0,0,0.1); - color: #32323e; -} - -.button.primary.ffz-waiting.ffz-banned:not(:hover) { - background-color: rgba(128,0,0,0.1); - color: #88323e; -} - -.chat-container.dark .button.primary.ffz-waiting:not(:hover), -.app-main.theatre .button-primary.ffz-waiting:not(:hover), -.chat-container.force-dark .button-primary.ffz-waiting:not(:hover), -.ember-chat-container.dark .button-primary.ffz-waiting:not(:hover), -.ember-chat-container.force-dark .button-primary.ffz-waiting:not(:hover) { - background-color: rgba(255,255,255,0.1); - color: #fff; -} - -.chat-container.dark .button.primary.ffz-waiting.ffz-banned:not(:hover), -.app-main.theatre .button-primary.ffz-waiting.ffz-banned:not(:hover), -.chat-container.force-dark .button-primary.ffz-waiting.ffz-banned:not(:hover), -.ember-chat-container.dark .button-primary.ffz-waiting.ffz-banned:not(:hover), -.ember-chat-container.force-dark .button-primary.ffz-waiting.ffz-banned:not(:hover) { - background-color: rgba(255,128,128,0.1); - color: #f66; -} - -/* Swap Sidebars */ - -body[data-current-path^="user."].ffz-portrait #right_close { transform: rotate(90deg); } -body[data-current-path^="user."].ffz-portrait .archives-contain .more-archives { width: 100%; } - -body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-interface .emoticon-selector, -.ffz-sidebar-swap:not(.ffz-portrait) .ember-chat .chat-interface .emoticon-selector { - right: auto; - left: 20px; -} - -.ffz-sidebar-swap #left_col { - left: auto; - right: 0; -} - -.ffz-sidebar-swap #right_col { - right: auto; - left: 0; -} - -.ffz-sidebar-swap:not(.ffz-portrait) #right_close, -.ffz-sidebar-swap #left_close { - transform: scaleX(-1); -} - -.ffz-sidebar-swap #right_close { - right: auto; - left: 5px; -} - -.ffz-sidebar-swap #left_close { - right: auto; - left: -25px; -} - -.ffz-sidebar-swap #main_col { - margin-left: 340px; - margin-right: 240px; -} - -.ffz-sidebar-swap .app-main.theatre #main_col { - margin-left: 340px; - margin-right: 0px; -} - -.ffz-sidebar-swap .app-main.theatre #main_col.expandRight { - margin-left: 0px; -} - - -.ffz-sidebar-swap .exit-theatre { - left: 30px; -} - -.ffz-sidebar-swap #main_col.expandLeft { - margin-right: 50px; -} - -.ffz-sidebar-swap #main_col.expandRight { - margin-left: 0px; -} - -.ffz-sidebar-swap #flyout { - left: auto !important; - right: 50px; -} - -.ffz-sidebar-swap #flyout .content { - right: 10px; -} - -.ffz-sidebar-swap #flyout .point { - left: auto; - right: -1px; -} - -.ffz-sidebar-swap #flyout .point:before { - border-left-color: #fff; - border-right-color: transparent; - right: auto; - left: 0px; -} - -.ffz-sidebar-swap #flyout .point:after { - border-right-color: transparent; - border-left-color: rgba(0,0,0,0.25); - right: auto; - left: 1px; -} - -.ffz-dark.ffz-sidebar-swap #flyout .point:after { - border-left-color: #32323e; - border-right-color: transparent; -} - -.ffz-dark.ffz-sidebar-swap #flyout .point:before { - border-left-color: #101010; - border-right-color: transparent; -} - -/* Badge Styles */ - -.ffz-rounded-badges .ember-chat .badges .badge:not(.subscriber) { border-radius: 2px; } - -.ffz-circular-blank-badges .ember-chat .badges .badge:not(.subscriber), -.ffz-circular-small-badges .ember-chat .badges .badge:not(.subscriber), -.ffz-circular-badges .ember-chat .badges .badge:not(.subscriber) { - border-radius: 9px; - background-size: 16px; - background-repeat: no-repeat; - background-position: center center; -} - -.ffz-circular-small-badges .ember-chat .badges .badge:not(.subscriber), -.ffz-circular-blank-badges .ember-chat .badges .badge:not(.subscriber) { - background-size: 0px; -} - -.ffz-circular-small-badges .ember-chat .badges .badge:not(.subscriber) { - height: 10px; - min-width: 10px; - margin: 5px 3px 5px 0; -} - -.ffz-transparent-badges .ember-chat .badges .badge { - background-color: transparent !important; -} - -.ffz-transparent-badges > .chat-container:not(.dark):not(.force-dark) .ember-chat .badges .badge:not(.ffz-badge-0):not(.subscriber), -.ffz-transparent-badges > .ember-chat-container:not(.dark):not(.force-dark) .ember-chat .badges .badge:not(.ffz-badge-0):not(.subscriber), -.ffz-transparent-badges .app-main:not(.theatre) .chat-container:not(.dark):not(.force-dark) .ember-chat .badges .badge:not(.ffz-badge-0):not(.subscriber), -.ffz-transparent-badges .app-main:not(.theatre) .ember-chat-container:not(.dark):not(.force-dark) .ember-chat .badges .badge:not(.ffz-badge-0):not(.subscriber) { - filter: invert(100%); - -webkit-filter: invert(100%); -} - -/* No Blue */ - -.ffz-no-blue #large_nav .content, -.ffz-no-blue #small_nav .content, -.ffz-no-blue .chat-container.dark, -.ffz-no-blue .app-main.theatre .chat-container, -.ffz-no-blue .chat-container.force-dark, -.ffz-no-blue .ember-chat-container.dark, -.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container, -.ffz-no-blue .ember-chat-container.force-dark, -.ffz-no-blue .chat-container.dark .chat-hidden-overlay, -.ffz-no-blue .app-main.theatre .chat-container .chat-hidden-overlay, -.ffz-no-blue .chat-container.force-dark .chat-hidden-overlay, -.ffz-no-blue .ember-chat-container.dark .chat-hidden-overlay, -.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .chat-hidden-overlay, -.ffz-no-blue .ember-chat-container.force-dark .chat-hidden-overlay, -.ffz-no-blue .chat-container.dark .chatters-view, -.ffz-no-blue .app-main.theatre .chat-container .chatters-view, -.ffz-no-blue .chat-container.force-dark .chatters-view, -.ffz-no-blue .ember-chat-container.dark .chatters-view, -.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .chatters-view, -.ffz-no-blue .ember-chat-container.force-dark .chatters-view, -.ffz-no-blue .chat-container.dark .emoticon-selector .emoticon-selector-box, -.ffz-no-blue .app-main.theatre .chat-container .emoticon-selector .emoticon-selector-box, -.ffz-no-blue .chat-container.force-dark .emoticon-selector .emoticon-selector-box, -.ffz-no-blue .ember-chat-container.dark .emoticon-selector .emoticon-selector-box, -.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .emoticon-selector .emoticon-selector-box, -.ffz-no-blue .ember-chat-container.force-dark .emoticon-selector .emoticon-selector-box, -.ffz-no-blue .chat-container.dark .emoticon-selector .emoticon-grid, -.ffz-no-blue .app-main.theatre .chat-container .emoticon-selector .emoticon-grid, -.ffz-no-blue .chat-container.force-dark .emoticon-selector .emoticon-grid, -.ffz-no-blue .ember-chat-container.dark .emoticon-selector .emoticon-grid, -.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .emoticon-selector .emoticon-grid, -.ffz-no-blue .ember-chat-container.force-dark .emoticon-selector .emoticon-grid, -.ffz-no-blue .chat-container.dark .chat-commands-dropdown, -.ffz-no-blue .app-main.theatre .chat-container .chat-commands-dropdown, -.ffz-no-blue .chat-container.force-dark .chat-commands-dropdown, -.ffz-no-blue .ember-chat-container.dark .chat-commands-dropdown, -.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .chat-commands-dropdown, -.ffz-no-blue .ember-chat-container.force-dark .chat-commands-dropdown, -.ffz-no-blue .chat-container.dark .chat-commands-dropdown li, -.ffz-no-blue .app-main.theatre .chat-container .chat-commands-dropdown li, -.ffz-no-blue .chat-container.force-dark .chat-commands-dropdown li, -.ffz-no-blue .ember-chat-container.dark .chat-commands-dropdown li, -.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .chat-commands-dropdown li, -.ffz-no-blue .ember-chat-container.force-dark .chat-commands-dropdown li, -.ffz-no-blue.error_500, -.ffz-no-blue.error_400, -.ffz-no-blue .takeover #carousel, -.ffz-no-blue #carousel_and_background, -.ffz-no-blue #carousel .items .pic img, -.ffz-no-blue #content .turbo_landing { - background-color: #191919; -} - -.ffz-no-blue .chat-container.dark .chat-interface .emoticon-selector .tabs, -.ffz-no-blue .app-main.theatre .chat-container .chat-interface .emoticon-selector .tabs, -.ffz-no-blue .chat-container.force-dark .chat-interface .emoticon-selector .tabs, -.ffz-no-blue .ember-chat-container.dark .chat-interface .emoticon-selector .tabs, -.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .chat-interface .emoticon-selector .tabs, -.ffz-no-blue .ember-chat-container.force-dark .chat-interface .emoticon-selector .tabs { - background-color: #232323; -} - -/* Following Count */ - -li[data-name="following"] a { - position: relative; -} - -.ffz-follow-count:empty { display: none; } - -.ffz-follow-count { - display: inline-block; - border-radius: 2px; - text-align: center; - color: #fff; -} - -#header_following .ffz-follow-count { - margin: 0 5px; - padding: 0 5px; - line-height: 20px; - background-color: rgba(25,25,25,0.5); -} - -#large_nav .ffz-follow-count, -.ffz-dark #header_following .ffz-follow-count { - background-color: rgba(127,127,127,0.5); -} - -#large_nav .ffz-follow-count { - position: absolute; - right: 10px; - top: 8px; - - line-height: 14px; - padding: 2px 5px; -} - -#large_nav .game_filter.selected .ffz-follow-count { right: 13px; } - -#small_nav .ffz-follow-count { - position: absolute; - bottom: 2px; - right: 2px; - padding: 0 2px; - font-size: 10px; - background-color: #191919; - color: rgba(255,255,255,0.5); -} - -#small_nav .game_filter.selected a .ffz-follow-count, -#small_nav .content ul li a:hover .ffz-follow-count { - background-color: #101014; -} - -#small_nav .game_filter.selected .ffz-follow-count { right: 5px; } - -/* Legacy Badges */ - -.ffz-legacy-mod-badges .ember-chat .badges .moderator, -.ffz-legacy-badges .ember-chat .badges .moderator { - background-color: #068c10; - background-image: url('//cdn.frankerfacez.com/script/legacy-mod.png'); -} - -.ffz-legacy-badges .ember-chat .badges .staff { - background-color: #6441a5; - background-image: url('//cdn.frankerfacez.com/script/legacy-staff.png'); -} - -.ffz-legacy-badges .ember-chat .badges .broadcaster { - background-color: #000; - background-image: url('//cdn.frankerfacez.com/script/legacy-broadcaster.png'); -} - -.ffz-legacy-badges .ember-chat .badges .admin { - background-color: #ff0303; - background-image: url('//cdn.frankerfacez.com/script/legacy-admin.png'); -} - -.ffz-legacy-turbo-badges .ember-chat .badges .turbo, -.ffz-legacy-badges .ember-chat .badges .turbo { - background-color: #6441a3; - background-image: url('//cdn.frankerfacez.com/script/legacy-turbo.png'); -} - -/* High Contrast Chat */ - -.ffz-high-contrast-chat-text .chat-container, -.ffz-high-contrast-chat-text .ember-chat-container { - color: "#000"; -} - -.ffz-high-contrast-chat-bg .chat-container, -.ffz-high-contrast-chat-bg .ember-chat-container { - background-color: #fff; -} - -.ffz-high-contrast-chat-bold .ember-chat .chat-messages .chat-line .from, -.ffz-high-contrast-chat-bold .ember-chat .chat-messages .chat-line .colon, -.ffz-high-contrast-chat-bold .ember-chat .chat-messages .chat-line .message { - font-weight: bold; -} - -/*.ffz-high-contrast-chat .chat-line:before { - background-color: transparent !important; - border: none !important; -}*/ - -.ffz-high-contrast-chat-text .chat-container.dark, -.ffz-high-contrast-chat-text .chat-container.force-dark, -.ffz-high-contrast-chat-text .ember-chat-container.dark, -.ffz-high-contrast-chat-text .ember-chat-container.force-dark, -.ffz-high-contrast-chat-text .app-main.theatre .chat-container, -.ffz-high-contrast-chat-text.ffz-dark .ember-chat-container.dark .chat-line, -.ffz-high-contrast-chat-text.ffz-dark .chat-container.dark .chat-line { - color: #fff; -} - -.ffz-high-contrast-chat-bg .chat-container.dark, -.ffz-high-contrast-chat-bg .chat-container.force-dark, -.ffz-high-contrast-chat-bg .ember-chat-container.dark, -.ffz-high-contrast-chat-bg .ember-chat-container.force-dark, -.ffz-high-contrast-chat-bg .app-main.theatre .chat-container, -.ffz-high-contrast-chat-bg.ffz-dark .ember-chat-container.dark .chat-line, -.ffz-high-contrast-chat-bg.ffz-dark .chat-container.dark .chat-line { - background-color: #000; -} - - -/*.ffz-high-contrast-chat .chat-line .mentioned { - color: #fff !important; - background-color: #000 !important; -} - -.ffz-high-contrast-chat .chat-container.dark .chat-line .mentioned, -.ffz-high-contrast-chat .chat-container.force-dark .chat-line .mentioned, -.ffz-high-contrast-chat .ember-chat-container.dark .chat-line .mentioned, -.ffz-high-contrast-chat .ember-chat-container.force-dark .chat-line .mentioned, -.ffz-high-contrast-chat .app-main.theatre .chat-container .chat-line .mentioned, -.ffz-high-contrast-chat.ffz-dark .ember-chat-container.dark .chat-line .chat-line .mentioned, -.ffz-high-contrast-chat.ffz-dark .chat-container.dark .chat-line .chat-line .mentioned { - color: #000 !important; - background-color: #fff !important; -}*/ - -.ffz-image-hover { - border:none; - max-width: 186px; - max-height: 186px; - overflow: hidden; -} - -.ffz-yt-thumb { - max-height: 90px; -} - -/* Classic Player */ - -.ffz-classic-player .player .player-video { - position: absolute; - top: 0; bottom: 32px; - left: 0; right: 0; -} - -.ffz-classic-player .player.player-isvod .player-video { - bottom: 36px; -} - -.ffz-classic-player .player .player-controls-bottom { - opacity: 1; - - padding-top: 0; - border-top: 1px solid #000; - border-bottom: 1px solid #000; - - background: -webkit-linear-gradient(bottom, #252525, #666); - background: linear-gradient(to top, #252525, #666); -} - -.ffz-classic-player .app-main.theatre .player .player-video, -.ffz-classic-player .player[data-fullscreen="true"] .player-video { - bottom: 0; -} - -.ffz-classic-player .app-main.theatre .player .player-controls-bottom, -.ffz-classic-player .player[data-fullscreen="true"] .player-controls-bottom { - margin-bottom: -32px; - -webkit-transition: margin-bottom .2s ease-out; - transition: margin-bottom .2s ease-out; -} - -.ffz-classic-player .app-main.theatre .player.player-isvod .player-controls-bottom, -.ffz-classic-player .player.player-isvod[data-fullscreen="true"] .player-controls-bottom { - margin-bottom: -36px; -} - -.ffz-classic-player .app-main.theatre .player-column:hover .player .player-controls-bottom, -.ffz-classic-player .app-main.theatre .player-column:focus .player .player-controls-bottom, -.ffz-classic-player .player[data-fullscreen="true"][data-controls="true"] .player-controls-bottom { - margin-bottom: 0; -} - -.ffz-classic-player .player .player-button { - padding-bottom: 0; - height: 30px; -} - - -.ffz-classic-player .player .player-slider:before, -.ffz-classic-player .player .player-button, -.ffz-classic-player .player .player-slider .ui-slider-handle, -.ffz-classic-player .player .player-seek .player-seek__time { - -webkit-filter: drop-shadow(0px 0px 1px #000); - filter: drop-shadow(0px 0px 1px #000); -} - - -.ffz-classic-player .player .player-slider .ui-slider-handle { background-color: #aeaeae; } -.ffz-classic-player .player .player-button svg { fill: #aeaeae; } -.ffz-classic-player .player .player-seek .player-seek__time { color: #ddd; } - -.ffz-classic-player .player .player-volume__slider-container { - width: auto; -} - - -.ffz-classic-player .player .player-seek { - padding: 0; -} - -.ffz-classic-player .player .player-seek .player-slider { - margin: -1em 0; -} - -.ffz-classic-player .player .player-seek .player-seek__time-container { - position: absolute; - bottom: -12px; - left: 210px; -} - -.ffz-classic-player .player .player-seek .player-seek__time + .player-seek__time:before { - content: "/"; - padding: 0 5px; - opacity: 0.8; -} - -/* Directory Logos */ - -.ffz-directory-logo .meta p { width: auto; } - -.ffz-directory-logo .profile-photo { - float: left; - height: 46px; - width: 46px; - margin-right: 10px; -} - -/* Flip Dashboard */ - -.ffz-flip-dashboard #dash_main #controls_column { - float: right; - margin-left: 20px; - margin-right: 0; -} - -.ffz-flip-dashboard #dash_main .dash-chat-column { - right: inherit; - left: 0; - margin-right: 20px; -} \ No newline at end of file diff --git a/src/tokenize.js b/src/tokenize.js index ce514300..bd34ed56 100644 --- a/src/tokenize.js +++ b/src/tokenize.js @@ -401,14 +401,58 @@ FFZ.prototype.load_twitch_emote_data = function(tries) { // Tokenization // --------------------- +FFZ.prototype.tokenize_conversation_line = function(message, prevent_notification) { + var msg = message.get('body'), + user = this.get_user(), + from_user = message.get('from.username'), + from_me = user && from_user === user.login, + + emotes = message.get('tags.emotes'), + tokens = [msg]; + + // Standard Tokenization + if ( helpers && helpers.linkifyMessage ) + tokens = helpers.linkifyMessage(tokens); + + if ( user && user.login && helpers && helpers.mentionizeMessage ) + tokens = helpers.mentionizeMessage(tokens, user.login, from_me); + + if ( helpers && helpers.emoticonizeMessage && emotes ) + tokens = helpers.emoticonizeMessage(tokens, emotes); + + if ( this.settings.replace_bad_emotes ) + tokens = this.tokenize_replace_emotes(tokens); + + // FrankerFaceZ Extras + tokens = this._remove_banned(tokens); + tokens = this.tokenize_emotes(from_user, undefined, tokens, from_me); + + if ( this.settings.parse_emoji ) + tokens = this.tokenize_emoji(tokens); + + // Capitalization + var display_name = message.get('from.displayName'); + if ( display_name && display_name.length ) + FFZ.capitalization[from_user] = [display_name.trim(), Date.now()]; + + // Mentions! + if ( ! from_me ) + tokens = this.tokenize_mentions(tokens); + + // TODO: Notifications? + + return tokens; +} + FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, delete_links) { if ( msgObject.cachedTokens ) return msgObject.cachedTokens; - var msg = msgObject.message, + var msg = msgObject.message || msgObject.get('body'), user = this.get_user(), room_id = msgObject.room, - from_me = user && msgObject.from === user.login, + from_user = msgObject.from, + from_me = user && from_user === user.login, emotes = msgObject.tags && msgObject.tags.emotes, tokens = [msg]; @@ -438,7 +482,7 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, del // FrankerFaceZ Extras tokens = this._remove_banned(tokens); - tokens = this.tokenize_emotes(msgObject.from, room_id, tokens, from_me); + tokens = this.tokenize_emotes(from_user, room_id, tokens, from_me); if ( this.settings.parse_emoji ) tokens = this.tokenize_emoji(tokens); @@ -446,7 +490,7 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, del // Capitalization var display = msgObject.tags && msgObject.tags['display-name']; if ( display && display.length ) - FFZ.capitalization[msgObject.from] = [display.trim(), Date.now()]; + FFZ.capitalization[from_user] = [display.trim(), Date.now()]; // Mentions! @@ -482,7 +526,7 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, del else room_name = FFZ.get_capitalization(room_id); - display = display || Twitch.display.capitalize(msgObject.from); + display = display || Twitch.display.capitalize(from_user); if ( msgObject.style === 'action' ) msg = '* ' + display + ' ' + msg; @@ -602,7 +646,7 @@ FFZ.prototype.render_tokens = function(tokens, render_links) { var mirror_url = utils.quote_attr(constants.EMOTE_MIRROR_BASE + id + '.png'); - extra = ' data-emote="' + id + '" onerror="FrankerFaceZ._emote_mirror_swap(this)"'; + extra = ' data-emote="' + id + '"'; // onerror="FrankerFaceZ._emote_mirror_swap(this)"'; // Disable error checking for now. if ( ! constants.EMOTE_REPLACEMENTS[id] ) srcset = build_srcset(id); diff --git a/src/ui/dark.js b/src/ui/dark.js index 65d98a80..3c7f5260 100644 --- a/src/ui/dark.js +++ b/src/ui/dark.js @@ -1,6 +1,6 @@ var FFZ = window.FrankerFaceZ, - constants = require("../constants"), - styles = require("../styles"); + constants = require("../constants"); + //styles = require("../styles"); // --------------------- @@ -211,7 +211,6 @@ FFZ.prototype._load_dark_css = function() { s.id = "ffz-dark-css"; s.setAttribute('rel', 'stylesheet'); - s.setAttribute('href', constants.SERVER + "script/dark.css?_=" + (constants.DEBUG ? Date.now() : FFZ.version_info)); - s.onerror = "this.href = this.href + '_';" + s.setAttribute('href', constants.DIRECT_SERVER + "script/dark.css?_=" + (constants.DEBUG ? Date.now() : FFZ.version_info)); document.head.appendChild(s); } \ No newline at end of file diff --git a/src/ui/notifications.js b/src/ui/notifications.js index 6a2b5b37..e7834523 100644 --- a/src/ui/notifications.js +++ b/src/ui/notifications.js @@ -181,6 +181,11 @@ FFZ.prototype.show_notification = function(message, title, tag, timeout, on_clic // --------------------- FFZ.prototype.show_message = function(message) { + if ( ! window.jQuery || ! window.jQuery.noty || ! jQuery.noty.themes.ffzTheme ) { + setTimeout(this.show_message.bind(this, message), 50); + return; + } + window.noty({ text: message, theme: "ffzTheme", diff --git a/src/ui/styles.js b/src/ui/styles.js index a10b1684..43e6313c 100644 --- a/src/ui/styles.js +++ b/src/ui/styles.js @@ -1,18 +1,24 @@ var FFZ = window.FrankerFaceZ, - constants = require('../constants'), - styles = require('../styles'); + constants = require('../constants'); + //styles = require('../styles'); FFZ.prototype.setup_css = function() { document.body.classList.toggle('ffz-flip-dashboard', this.settings.flip_dashboard); this.log("Injecting main FrankerFaceZ CSS."); - var s = this._main_style = document.createElement('style'); + var s = this._main_style = document.createElement('link'); + s.id = "ffz-main-css"; + s.setAttribute('rel', 'stylesheet'); + s.setAttribute('href', constants.DIRECT_SERVER + "script/style.css?_=" + (constants.DEBUG ? Date.now() : FFZ.version_info)); + document.head.appendChild(s); + + /*var s = this._main_style = document.createElement('style'); s.textContent = styles.style; s.id = "ffz-ui-css"; - document.head.appendChild(s); + document.head.appendChild(s);*/ if ( window.jQuery && jQuery.noty ) jQuery.noty.themes.ffzTheme = { diff --git a/src/utils.js b/src/utils.js index f9794ce9..b1cce141 100644 --- a/src/utils.js +++ b/src/utils.js @@ -42,6 +42,9 @@ var sanitize_el = document.createElement('span'), date_regex = /^(\d{4}|\+\d{6})(?:-?(\d{2})(?:-?(\d{2})(?:T(\d{2})(?::?(\d{2})(?::?(\d{2})(?:(?:\.|,)(\d{1,}))?)?)?(Z|([\-+])(\d{2})(?::?(\d{2}))?)?)?)?)?$/, parse_date = function(str) { + if ( typeof str === "number" ) + return new Date(str); + var parts = str.match(date_regex); if ( ! parts ) return null; From 4f6dcc9999031506eea2085d5749ca973071a626 Mon Sep 17 00:00:00 2001 From: SirStendec Date: Tue, 10 Nov 2015 21:37:30 -0500 Subject: [PATCH 2/5] 3.5.58 to 3.5.62. Added enhanced following controls to the profile page. New Conversations options. Tweaked conversation styles. --- dark.css | 5 +- src/colors.js | 14 +- src/constants.js | 1 + src/ember/conversations.js | 252 ++++ src/ember/directory.js | 8 +- src/ember/following.js | 318 +++++ src/ember/line.js | 8 - src/ember/room.js | 14 +- src/emoticons.js | 2 +- src/main.js | 6 +- src/tokenize.js | 6 +- src/ui/menu.js | 5 +- src/ui/my_emotes.js | 6 +- src/ui/styles.js | 2 +- style.css | 2408 ++++++++++++++++++++++++++++++++++++ 15 files changed, 3017 insertions(+), 38 deletions(-) create mode 100644 src/ember/conversations.js create mode 100644 src/ember/following.js create mode 100644 style.css diff --git a/dark.css b/dark.css index 0c24fcf9..0f33d367 100644 --- a/dark.css +++ b/dark.css @@ -1036,4 +1036,7 @@ .ffz-dark .conversation-window.has-focus .conversation-input-actions .button, .ffz-dark .conversation-window.has-focus .conversation-input-actions .follow-button:not(.ember-follow) .follow { background-color: #6441a5 -} \ No newline at end of file +} + +.ffz-dark .conversation-window .new-message-divider span { background: transparent; } +.ffz-dark .conversation-window .new-message-divider:after { display: none; } \ No newline at end of file diff --git a/src/colors.js b/src/colors.js index 604959d6..a0d09ad4 100644 --- a/src/colors.js +++ b/src/colors.js @@ -570,19 +570,7 @@ FFZ.prototype._update_colors = function(darkness_only) { this._color_old_darkness = is_dark; - var colored_bits = document.querySelectorAll('.chat-line .has-color'); - for(var i=0, l=colored_bits.length; i < l; i++) { - var bit = colored_bits[i], - color = bit.getAttribute('data-color'), - colors = color && this._handle_color(color); - - if ( ! colors ) - continue; - - bit.style.color = is_dark ? colors[1] : colors[0]; - } - - colored_bits = document.querySelectorAll('.conversation-chat-line .has-color'); + var colored_bits = document.querySelectorAll('.has-color'); for(var i=0, l=colored_bits.length; i < l; i++) { var bit = colored_bits[i], color = bit.getAttribute('data-color'), diff --git a/src/constants.js b/src/constants.js index 45d456c5..d8422d59 100644 --- a/src/constants.js +++ b/src/constants.js @@ -77,6 +77,7 @@ module.exports = { CLOCK: '', GEAR: '', HEART: '', + UNHEART: '', EMOTE: '', STAR: '', CLOSE: '', diff --git a/src/ember/conversations.js b/src/ember/conversations.js new file mode 100644 index 00000000..f73996b2 --- /dev/null +++ b/src/ember/conversations.js @@ -0,0 +1,252 @@ +var FFZ = window.FrankerFaceZ, + utils = require('../utils'), + constants = require('../constants'); + + +// --------------- +// Settings +// --------------- + +FFZ.settings_info.conv_title_clickable = { + type: "boolean", + value: false, + no_mobile: true, + + category: "Conversations", + name: "Clickable Header Name", + help: "Make the conversation header a link that takes you to that person's page.", + on_update: function(val) { + document.body.classList.toggle('ffz-conv-title-clickable', val); + } + }; + +FFZ.settings_info.conv_focus_on_click = { + type: "boolean", + value: false, + no_mobile: true, + + category: "Conversations", + name: "Focus Input on Click", + help: "Focus on a conversation's input box when you click it." + }; + +FFZ.settings_info.top_conversations = { + type: "boolean", + value: false, + no_mobile: true, + + category: "Conversations", + name: "Position on Top", + help: "Display the new conversation-style whisper UI at the top of the window instead of the bottom.", + on_update: function(val) { + document.body.classList.toggle('ffz-top-conversations', val); + } + }; + +FFZ.settings_info.conv_beta_enable = { + type: "boolean", + value: false, + no_mobile: true, + + category: "Conversations", + name: "Enable Conversations", + help: "Twitch hasn't enabled them yet, but they're in the code for testing. Try them out!", + on_update: function(val) { + App.__container__.lookup('route:application').controller.set('isConversationsEnabled', val); + } + }; + + +// --------------- +// Initialization +// --------------- + +FFZ.prototype.setup_conversations = function() { + document.body.classList.toggle('ffz-top-conversations', this.settings.top_conversations); + document.body.classList.toggle('ffz-conv-title-clickable', this.settings.conv_title_clickable);; + + if ( this.settings.conv_beta_enable ) + App.__container__.lookup('route:application').controller.set('isConversationsEnabled', true); + + this.log("Hooking the Ember Conversation Window component."); + var ConvWindow = App.__container__.resolve('component:conversation-window'); + if ( ConvWindow ) + this._modify_conversation_window(ConvWindow); + + + this.log("Hooking the Ember Conversation Line component."); + var ConvLine = App.__container__.resolve('component:conversation-line'); + if ( ConvLine ) + this._modify_conversation_line(ConvLine); +} + + +FFZ.prototype._modify_conversation_window = function(component) { + var f = this, + + Layout = App.__container__.lookup('controller:layout'), + Settings = App.__container__.lookup('controller:settings'); + + component.reopen({ + onConversationClick: Ember.on('click', function() { + this.markConversationRead(); + if ( f.settings.conv_focus_on_click ) + this.$(".conversation-input-bar textarea").focus(); + }), + + headerBadges: Ember.computed("conversation.participants", "currentUsername", function() { + var e = this.get("conversation.participants").rejectBy("username", this.get("currentUsername")).objectAt(0), + badges = {}, + + ut = e.get("userType"); + + if ( ut === "staff" ) + badges[0] = {classes: 'badge staff', title: 'Staff'}; + else if ( ut === 'admin' ) + badges[0] = {classes: 'badge admin', title: 'Admin'}; + else if ( ut === 'global_mod' ) + badges[0] = {classes: 'badge global-moderator', title: 'Global Moderator'}; + + if ( e.get('hasTurbo') ) + badges[15] = {classes: 'badge turbo', title: 'Turbo'} + + // FFZ Badges + var data = f.users[e.get('username')]; + if ( data && data.badges ) { + for(var slot in data.badges) { + if ( ! data.badges.hasOwnProperty(slot) ) + continue; + + var badge = data.badges[slot], + full_badge = f.badges[badge.id] || {}, + old_badge = badges[slot]; + + if ( full_badge.visible !== undefined ) { + var visible = full_badge.visible; + if ( typeof visible === "function" ) + try { + visible = visible.bind(f)(null, e.get('username'), null, badges); + } catch(err) { + f.error("badge " + badge.id + " visible: " + err); + continue; + } + + if ( ! visible ) + continue; + } + + if ( old_badge ) { + var replaces = badge.hasOwnProperty('replaces') ? badge.replaces : full_badge.replaces; + if ( ! replaces ) + continue; + + old_badge.klass = 'badge ffz-badge-' + badge.id; + old_badge.title += ', ' + (badge.title || full_badge.title); + continue; + } + + badges[slot] = { + classes: 'badge ffz-badge-' + badge.id, + title: badge.title || full_badge.title + } + } + } + + var out = []; + for(var slot in badges) + out.push(badges[slot]); + + return out; + }), + + didInsertElement: function() { + var el = this.get('element'), + header = el && el.querySelector('.conversation-header'), + header_name = header && header.querySelector('.conversation-header-name'), + + new_header_name = document.createElement('span'), + + raw_color = this.get('otherUser.color'), + colors = raw_color && f._handle_color(raw_color), + + is_dark = (Layout && Layout.get('isTheatreMode')) || f.settings.dark_twitch; + + if ( header_name ) { + new_header_name.className = 'conversation-header-name'; + new_header_name.textContent = header_name.textContent; + header.insertBefore(new_header_name, header_name); + + if ( raw_color ) { + header_name.style.color = (is_dark ? colors[1] : colors[0]); + header_name.classList.add('has-color'); + header_name.setAttribute('data-color', raw_color); + + new_header_name.style.color = (is_dark ? colors[1] : colors[0]); + new_header_name.classList.add('has-color'); + new_header_name.setAttribute('data-color', raw_color); + } + } + } + }); +} + + +FFZ.prototype._modify_conversation_line = function(component) { + var f = this, + + Layout = App.__container__.lookup('controller:layout'), + Settings = App.__container__.lookup('controller:settings'); + + component.reopen({ + tokenizedMessage: function() { + try { + return f.tokenize_conversation_line(this.get('message')); + } catch(err) { + f.error("convo-line tokenizedMessage: " + err); + return this._super(); + } + + }.property("message", "currentUsername"), + + click: function(e) { + if ( e.target && e.target.classList.contains('deleted-link') ) + return f._deleted_link_click.bind(e.target)(e); + + if ( f._click_emote(e.target, e) ) + return; + + return this._super(e); + }, + + render: function(e) { + var user = this.get('message.from.username'), + raw_color = this.get('message.from.color'), + colors = raw_color && f._handle_color(raw_color), + + is_dark = (Layout && Layout.get('isTheatreMode')) || f.settings.dark_twitch; + + e.push('
'); + + var alias = f.aliases[user], + name = this.get('message.from.displayName') || (user && user.capitalize()) || "unknown user", + style = colors && 'color:' + (is_dark ? colors[1] : colors[0]), + colored = style ? ' has-color' : ''; + + if ( alias ) + e.push('' + utils.sanitize(alias) + ''); + else + e.push('' + utils.sanitize(name) + ''); + + e.push(': '); + + if ( ! this.get('isActionMessage') ) { + style = ''; + colored = ''; + } + + e.push(''); + e.push(f.render_tokens(this.get('tokenizedMessage'), true)); + e.push(''); + } + }); +} \ No newline at end of file diff --git a/src/ember/directory.js b/src/ember/directory.js index 281fe89b..f3704d36 100644 --- a/src/ember/directory.js +++ b/src/ember/directory.js @@ -45,8 +45,12 @@ FFZ.prototype.setup_directory = function() { // Initialize existing views. for(var key in Ember.View.views) { var view = Ember.View.views[key]; - if ( view instanceof ChannelView || view instanceof CreativeChannel || view instanceof CSGOChannel || view instanceof HostView ) - view.ffzInit(); + try { + if ( (ChannelView && view instanceof ChannelView) || (CreativeChannel && view instanceof CreativeChannel) || (CSGOChannel && view instanceof CSGOChannel) || (HostView && view instanceof HostView) ) + view.ffzInit(); + } catch(err) { + this.error("Directory Setup: " + err); + } } } diff --git a/src/ember/following.js b/src/ember/following.js new file mode 100644 index 00000000..a743749e --- /dev/null +++ b/src/ember/following.js @@ -0,0 +1,318 @@ +var FFZ = window.FrankerFaceZ, + utils = require('../utils'), + constants = require('../constants'); + + +// -------------------- +// Settings +// -------------------- + +FFZ.settings_info.enhance_profile_following = { + type: "boolean", + value: true, + + category: "Appearance", + name: "Enhanced Following Control", + help: "Display additional controls on your own profile's Following tab to make management easier." +} + + +// -------------------- +// Initialization +// -------------------- + +FFZ.prototype.setup_profile_following = function() { + if ( ! window.App ) + return; + + var f = this; + + // Build our is-following cache. + this._following_cache = {}; + + // First, we need to hook the model. This is what we'll use to grab the following notification state, + // rather than making potentially hundreds of API requests. + var Following = App.__container__.resolve('model:kraken-channel-following'); + if ( ! Following ) + return; + + this._hook_following(Following); + + // Also try hooking that other model. + var Notification = App.__container__.resolve('model:notification'); + if ( Notification ) + this._hook_following(Notification, true); + + + // Now, we need to edit the profile Following view itself. + var ProfileView = App.__container__.resolve('view:channel/following'); + if ( ! ProfileView ) + return; + + ProfileView.reopen({ + didInsertElement: function() { + this._super(); + try { + this.ffzInit(); + } catch(err) { + f.error("ProfileView ffzInit: " + err); + } + }, + + willClearRender: function() { + try { + this.ffzTeardown(); + } catch(err) { + f.error("ProvileView ffzTeardown: " + err); + } + this._super(); + }, + + ffzInit: function() { + // Only process our own profile following page. + var user = f.get_user(); + if ( ! f.settings.enhance_profile_following || ! user || ! user.login === this.get('context.id') ) + return; + + var el = this.get('element'), + users = el && el.querySelectorAll('.user.item'); + + el.classList.add('ffz-enhanced-following'); + + var had_data = true; + + if ( users && users.length ) + for(var i=0; i < users.length; i++) + had_data = this.ffzProcessUser(users[i]) && had_data; + else + had_data = false; + + if ( ! had_data ) { + // Force a refresh. + f.log("Forcing a refresh of user following data."); + var following = this.get('context.following'), + refresher = function() { + if ( following.get('isLoading') ) + setTimeout(refresher, 25); + + following.clear(); + following.load(); + } + + // We use this weird function to prevent trying to load twice mucking things up. + setTimeout(refresher); + } + + // Watch for new ones the bad way. + if ( ! this._ffz_observer ) { + var t = this; + var observer = this._ffz_observer = new MutationObserver(function(mutations) { + for(var i=0; i < mutations.length; i++) { + var mutation = mutations[i]; + if ( mutation.type !== "childList" ) + continue; + + for(var x=0; x < mutation.addedNodes.length; x++) { + var added = mutation.addedNodes[x]; + if ( added.nodeType !== added.ELEMENT_NODE || added.tagName !== "DIV" ) + continue; + + // Is it an ember-view? Check its kids. + if ( added.classList.contains('ember-view') ) { + var users = added.querySelectorAll('.user.item'); + if ( users ) + for(var y=0; y < users.length; y++) + t.ffzProcessUser(users[y]); + + } else if ( added.classList.contains('user') ) + t.ffzProcessUser(added); + } + } + }); + + observer.observe(el, { + childList: true, + subtree: true + }); + } + }, + + ffzTeardown: function() { + if ( this._ffz_observer ) { + this._ffz_observer.disconnect(); + this._ffz_observer = null; + } + }, + + ffzProcessUser: function(user) { + if ( user.classList.contains('ffz-processed') ) + return true; + + var link = user.querySelector('a'), + link_parts = link && link.href.split("/"), + user_id = link_parts && link_parts[3], + data = f._following_cache[user_id], + t_el = document.createElement('div'); + + user.classList.add('ffz-processed'); + if ( ! data ) + return false; + + t_el.className = 'overlay_info length'; + jQuery(t_el).tipsy({html: true}); + + var age = data[0] ? Math.floor((Date.now() - data[0].getTime()) / 1000) : 0; + if ( age ) { + t_el.innerHTML = constants.CLOCK + ' ' + utils.human_time(age, 10); + t_el.setAttribute('original-title', 'Following Since: ' + data[0].toLocaleString() + ''); + } else + t_el.style.display = 'none'; + + user.appendChild(t_el); + + var actions = document.createElement('div'), + follow = document.createElement('button'), + notif = document.createElement('button'), + + update_follow = function() { + data = f._following_cache[user_id]; + user.classList.toggle('followed', data); + follow.innerHTML = constants.HEART + constants.UNHEART + ' Follow'; + + if ( t_el ) { + var age = data && data[0] ? Math.floor((Date.now() - data[0].getTime()) / 1000) : undefined; + if ( age !== undefined ) { + t_el.innerHTML = constants.CLOCK + ' ' + (age < 60 ? 'now' : utils.human_time(age, 10)); + t_el.setAttribute('original-title', 'Following Since: ' + data[0].toLocaleString() + ''); + t_el.style.display = ''; + } else { + t_el.style.display = 'none'; + } + } + }, + + update_notif = function() { + data = f._following_cache[user_id]; + notif.classList.toggle('notifications-on', data && data[1]); + notif.textContent = 'Notification ' + (data && data[1] ? 'On' : 'Off'); + }; + + actions.className = 'actions'; + + follow.className = 'button follow'; + notif.className = 'button notifications'; + + update_follow(); + update_notif(); + + follow.addEventListener('click', function() { + var was_following = !!data; + + follow.disabled = true; + notif.disabled = true; + follow.textContent = 'Updating'; + + (was_following ? + Twitch.api.del("users/:login/follows/channels/" + user_id) : + Twitch.api.put("users/:login/follows/channels/" + user_id, {notifications: false})) + .done(function() { + data = f._following_cache[user_id] = was_following ? null : [new Date(), false]; + }) + .always(function() { + update_follow(); + update_notif(); + follow.disabled = false; + notif.disabled = false; + }) + }); + + notif.addEventListener('click', function() { + var was_following = data[1]; + + follow.disabled = true; + notif.disabled = true; + notif.textContent = 'Updating'; + + Twitch.api.put("users/:login/follows/channels/" + user_id, {notifications: !was_following}) + .done(function() { + data[1] = ! was_following; + }) + .always(function() { + update_notif(); + follow.disabled = false; + notif.disabled = false; + }); + }); + + actions.appendChild(follow); + actions.appendChild(notif); + user.appendChild(actions); + + return true; + } + }); + + // Now, rebuild any views. + try { + ProfileView.create().destroy(); + } catch(err) { } + + for(var key in Ember.View.views) { + var view = Ember.View.views[key]; + if ( ! view || !(view instanceof ProfileView) ) + continue; + + this.log("Manually updating existing Following View.", view); + try { + var following = view.get('context.following'); + this._hook_following(following); + } catch(err) { + this.error("setup: view:channel/following: model hook: " + err); + } + + try { + view.ffzInit(); + } catch(err) { + this.error("setup: view:channel/following: " + err); + } + } +} + + +FFZ.prototype._hook_following = function(Following) { + var f = this; + Following.reopen({ + apiLoad: function(e) { + var user = f.get_user(), + channel_id = this.get('id'), + t = this; + + if ( ! user || user.login !== channel_id ) + return this._super(e); + + return new RSVP.Promise(function(success, fail) { + t._super(e).then(function(data) { + if ( data && data.follows ) { + var now = Date.now(); + for(var i=0; i < data.follows.length; i++) { + var follow = data.follows[i]; + if ( ! follow || ! follow.channel || ! follow.channel.name ) { + continue; + } + + if ( follow.channel.display_name ) + FFZ.capitalization[follow.channel.name] = [follow.channel.display_name, now]; + + f._following_cache[follow.channel.name] = [follow.created_at ? utils.parse_date(follow.created_at) : null, follow.notifications || false]; + } + } + + success(data); + + }, function(err) { + fail(err); + }) + }); + } + }); +} \ No newline at end of file diff --git a/src/ember/line.js b/src/ember/line.js index 6a08aaae..699618c9 100644 --- a/src/ember/line.js +++ b/src/ember/line.js @@ -549,19 +549,11 @@ FFZ.prototype.setup_line = function() { this._modify_line(Whisper); this.log("Hooking the Ember Message Line component."); - var Line = App.__container__.resolve('component:message-line'); if ( Line ) this._modify_line(Line); - this.log("Hooking the Ember Conversation Line component."); - var Conversation = App.__container__.resolve('component:conversation-line'); - - if ( Conversation ) - this._modify_conversation_line(Conversation); - - // Store the capitalization of our own name. var user = this.get_user(); if ( user && user.name ) diff --git a/src/ember/room.js b/src/ember/room.js index 9e257543..4c3c30ef 100644 --- a/src/ember/room.js +++ b/src/ember/room.js @@ -115,6 +115,8 @@ FFZ.prototype.setup_room = function() { FFZ.prototype._modify_rview = function(view) { var f = this; view.reopen({ + alternate: false, + didInsertElement: function() { this._super(); @@ -134,6 +136,10 @@ FFZ.prototype._modify_rview = function(view) { this._super(); }, + ffzUpdateAlternate: function() { + this.get('element').classList.toggle('ffz-alternate', this.get('ffzAlternate')); + }.observes("ffzAlternate"), + ffzInit: function() { f._roomv = this; @@ -1182,10 +1188,10 @@ FFZ.prototype._modify_room = function(room) { return; var is_whisper = msg.style === 'whisper'; - if ( f.settings.group_tabs && f.settings.whisper_room ) { - if ( ( is_whisper && ! this.ffz_whisper_room ) || ( ! is_whisper && this.ffz_whisper_room ) ) - return; - } + + // Ignore whispers if conversations are enabled. + if ( is_whisper && App.__container__.lookup('route:application').controller.get('isConversationsEnabled') ) + return; if ( ! is_whisper ) msg.room = this.get('id'); diff --git a/src/emoticons.js b/src/emoticons.js index 45da1fe3..e7b7c9be 100644 --- a/src/emoticons.js +++ b/src/emoticons.js @@ -262,7 +262,7 @@ FFZ.prototype._emote_tooltip = function(emote) { title = set && set.title || "Global", source = set && set.source || "FFZ"; - emote._tooltip = "Emoticon: " + (emote.hidden ? "???" : emote.name) + "\n" + source + " " + title + (owner ? "\nBy: " + owner.display_name : ""); + emote._tooltip = "Emoticon: " + (emote.hidden ? "???" : emote.name) + "
" + source + " " + title + (owner ? "
By: " + owner.display_name : ""); return emote._tooltip; } diff --git a/src/main.js b/src/main.js index 598ebf78..3609f2f6 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: 5, revision: 57, + major: 3, minor: 5, revision: 62, toString: function() { return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); } @@ -123,11 +123,13 @@ require('./ember/room'); require('./ember/layout'); require('./ember/line'); require('./ember/chatview'); +require('./ember/conversations'); require('./ember/viewers'); require('./ember/moderation-card'); require('./ember/chat-input'); //require('./ember/teams'); require('./ember/directory'); +require('./ember/following'); require('./debug'); @@ -335,10 +337,12 @@ FFZ.prototype.init_ember = function(delay) { this.setup_line(); this.setup_layout(); this.setup_chatview(); + this.setup_conversations(); this.setup_viewers(); this.setup_mod_card(); this.setup_chat_input(); this.setup_directory(); + this.setup_profile_following(); //this.setup_teams(); diff --git a/src/tokenize.js b/src/tokenize.js index bd34ed56..1f3d1d51 100644 --- a/src/tokenize.js +++ b/src/tokenize.js @@ -35,7 +35,7 @@ var FFZ = window.FrankerFaceZ, set_type = null; } - return "Emoticon: " + data.code + "\n" + (set_type ? set_type + ": " : "") + set + (owner ? "\nBy: " + owner.display_name : ""); + return "Emoticon: " + data.code + "
" + (set_type ? set_type + ": " : "") + set + (owner ? "
By: " + owner.display_name : ""); }, build_tooltip = function(id) { @@ -603,7 +603,7 @@ FFZ.prototype.render_tokens = function(tokens, render_links) { var emote_set = f.emote_sets && f.emote_sets[token.ffzEmoteSet], emote = emote_set && emote_set.emoticons && emote_set.emoticons[token.ffzEmote]; - tooltip = emote ? utils.sanitize(f._emote_tooltip(emote)) : token.altText; + tooltip = emote ? f._emote_tooltip(emote) : token.altText; srcset = emote ? emote.srcSet : token.srcSet; extra = (emote ? ' data-ffz-emote="' + emote.id + '"' : '') + (emote_set ? ' data-ffz-set="' + emote_set.id + '"' : ''); @@ -652,7 +652,7 @@ FFZ.prototype.render_tokens = function(tokens, render_links) { srcset = build_srcset(id); } - return ''; + return ''; } if ( token.isLink ) { diff --git a/src/ui/menu.js b/src/ui/menu.js index 07093642..ff29cf0d 100644 --- a/src/ui/menu.js +++ b/src/ui/menu.js @@ -224,6 +224,9 @@ FFZ.prototype.build_ui_popup = function(view) { container.classList.toggle('dark', dark); + // Stuff + jQuery(inner).find('.html-tooltip').tipsy({live: true, html: true, gravity: jQuery.fn.tipsy.autoNS}); + // Menu Container var sub_container = document.createElement('div'); @@ -599,7 +602,7 @@ FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, image, sub c++; var s = document.createElement('span'); - s.className = 'emoticon tooltip'; + s.className = 'emoticon html-tooltip'; s.style.backgroundImage = 'url("' + emote.urls[1] + '")'; if ( srcset ) { diff --git a/src/ui/my_emotes.js b/src/ui/my_emotes.js index 06d23479..9d12f761 100644 --- a/src/ui/my_emotes.js +++ b/src/ui/my_emotes.js @@ -166,7 +166,7 @@ FFZ.menu_pages.myemotes = { if ( (settings === 1 && ! emoji.tw) || (settings === 2 && ! emoji.noto) ) continue; - em.className = 'emoticon tooltip'; + em.className = 'emoticon html-tooltip'; em.title = 'Emoji: ' + emoji.raw + '\nName: ' + emoji.name + (emoji.short_name ? '\nShort Name: :' + emoji.short_name + ':' : ''); em.addEventListener('click', this._add_emote.bind(this, view, emoji.raw)); @@ -239,7 +239,7 @@ FFZ.menu_pages.myemotes = { em = document.createElement('span'), img_set = 'image-set(url("' + TWITCH_BASE + emote.id + '/1.0") 1x, url("' + TWITCH_BASE + emote.id + '/2.0") 2x, url("' + TWITCH_BASE + emote.id + '/3.0") 4x)'; - em.className = 'emoticon tooltip'; + em.className = 'emoticon html-tooltip'; if ( this.settings.replace_bad_emotes && constants.EMOTE_REPLACEMENTS[emote.id] ) { em.style.backgroundImage = 'url("' + constants.EMOTE_REPLACEMENT_BASE + constants.EMOTE_REPLACEMENTS[emote.id] + '")'; @@ -316,7 +316,7 @@ FFZ.menu_pages.myemotes = { img_set += ')'; - em.className = 'emoticon tooltip'; + em.className = 'emoticon html-tooltip'; em.style.backgroundImage = 'url("' + emote.urls[1] + '")'; em.style.backgroundImage = '-webkit-' + img_set; em.style.backgroundImage = '-moz-' + img_set; diff --git a/src/ui/styles.js b/src/ui/styles.js index 43e6313c..56a134f9 100644 --- a/src/ui/styles.js +++ b/src/ui/styles.js @@ -16,7 +16,7 @@ FFZ.prototype.setup_css = function() { /*var s = this._main_style = document.createElement('style'); s.textContent = styles.style; - s.id = "ffz-ui-css"; + s.id = "ffz-main-css"; document.head.appendChild(s);*/ diff --git a/style.css b/style.css new file mode 100644 index 00000000..dae3d975 --- /dev/null +++ b/style.css @@ -0,0 +1,2408 @@ +/* Fix Tooltip Opacity */ + +body > div.tipsy { opacity: 1 !important; } +body > div.tipsy .tipsy-inner { background-color: rgba(0,0,0,0.8); } +body > div.tipsy .tipsy-arrow { opacity: 0.8; } + + +.ffz-flip { + -ms-transform: rotate(180deg); + -webkit-transform: rotate(180deg); + transform: rotate(180deg); +} + +.ffz-ui-toggle { + display: block; + position: absolute; + top: 5px; right: 5px; + height: 18px; width: 24px; + cursor: pointer; +} + +.ffz-hide-recent-past-broadcast .recent-past-broadcast, +.ffz-hide-view-count .stat.twitch-channel-views, +.ffz-minimal-chat-input .emoticon-selector-toggle, +.ffz-menu-replace .emoticon-selector-toggle { + display: none !important; +} + +body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + .ffz-ui-toggle svg, +body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + script + .ffz-ui-toggle svg +{ + height: 14px; + width: 18px; +} + +body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + .ffz-ui-toggle, +body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + script + .ffz-ui-toggle { + height: 14px; + width: 18px; + top: 28px; +} + +.ffz-ui-toggle svg.svg-emoticons path { fill: rgba(0,0,0,0.2); } +.ffz-ui-toggle:hover svg.svg-emoticons path { fill: rgba(0,0,0,0.5); } + +.streams .stream .content .overlay_info.live svg path, +.videos .video .content .overlay_info.live svg path { fill: #ff2020; } + +.ember-chat-container.dark .ffz-ui-toggle svg.svg-emoticons path, +.chat-container.dark .ffz-ui-toggle svg.svg-emoticons path, +.app-main.theatre .ffz-ui-toggle svg.svg-emoticons path, +.ffz-ui-toggle.dark svg.svg-emoticons path { fill: #888; } + +.ember-chat-container.dark .ffz-ui-toggle:hover svg.svg-emoticons path, +.chat-container.dark .ffz-ui-toggle:hover svg.svg-emoticons path, +.app-main.theatre .ffz-ui-toggle:hover svg.svg-emoticons path, +.ffz-ui-toggle.dark:hover svg.svg-emoticons path { fill: #777; } + + +.ffz-ui-toggle.no-emotes svg.svg-emoticons path { fill: rgba(80,0,0,0.2); } +.ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path { fill: rgba(80,0,0,0.5); } + +.ffz-ui-toggle.live svg.svg-emoticons path { fill: rgba(100,65,165,0.5); } +.ffz-ui-toggle.live:hover svg.svg-emoticons path { fill: rgba(100,65,165,1); } + +.ffz-ui-toggle.blue.live svg.svg-emoticons path { fill: rgba(47,88,185,0.5); } +.ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill: rgba(47,88,185,1); } + +.ember-chat-container.dark .ffz-ui-toggle.news svg.svg-emoticons path, +.app-main.theatre .ffz-ui-toggle.news svg.svg-emoticons path, +.chat-container.dark .ffz-ui-toggle.news svg.svg-emoticons path, +.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.news svg.svg-emoticons path, +.ffz-ui-toggle.news svg.svg-emoticons path { fill: rgba(117, 80, 0, 0.5); } + +.ember-chat-container.dark .ffz-ui-toggle.news:hover svg.svg-emoticons path, +.app-main.theatre .ffz-ui-toggle.news:hover svg.svg-emoticons path, +.chat-container.dark .ffz-ui-toggle.news:hover svg.svg-emoticons path, +.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.news:hover svg.svg-emoticons path, +.ffz-ui-toggle.news:hover svg.svg-emoticons path { fill: rgba(117, 80, 0, 0.8); } + +.ember-chat-container.dark .ffz-ui-toggle.no-emotes svg.svg-emoticons path, +.app-main.theatre .ffz-ui-toggle.no-emotes svg.svg-emoticons path, +.chat-container.dark .ffz-ui-toggle.no-emotes svg.svg-emoticons path, +.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.no-emotes svg.svg-emoticons path { fill: #453434; } + +.ember-chat-container.dark .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path, +.app-main.theatre .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path, +.chat-container.dark .ffz-ui-toggle.no-emotes:hover svg.svg-emoticons path, +.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.no-emotes:hover svg.svg-emoticons path { fill: #543f3f; } + +.ember-chat-container.dark .ffz-ui-toggle.live svg.svg-emoticons path, +.app-main.theatre .ffz-ui-toggle.live svg.svg-emoticons path, +.chat-container.dark .ffz-ui-toggle.live svg.svg-emoticons path, +.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.live svg.svg-emoticons path { fill: #513c78; } + +.ember-chat-container.dark .ffz-ui-toggle.live:hover svg.svg-emoticons path, +.app-main.theatre .ffz-ui-toggle.live:hover svg.svg-emoticons path, +.chat-container.dark .ffz-ui-toggle.live:hover svg.svg-emoticons path, +.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.live:hover svg.svg-emoticons path { fill: #5b4487; } + +.ember-chat-container.dark .ffz-ui-toggle.blue.live svg.svg-emoticons path, +.app-main.theatre .ffz-ui-toggle.blue.live svg.svg-emoticons path, +.chat-container.dark .ffz-ui-toggle.blue.live svg.svg-emoticons path, +.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.blue.live svg.svg-emoticons path { fill: #3c4e78; } + +.ember-chat-container.dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path, +.app-main.theatre .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path, +.chat-container.dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path, +.ember-chat .chat-interface .textarea-contain .ffz-ui-toggle.dark.blue.live:hover svg.svg-emoticons path { fill: #445887; } + + +.ffz-ui-toggle.live { + animation: ffzfade 8s linear infinite; + -webkit-animation: ffzfade 8s linear infinite; +} + +@-webkit-keyframes ffzfade { + from, to { opacity: 1; } + 50% { opacity: 0.75; } +} + +@keyframes ffzfade { + from, to { opacity: 1; } + 50% { opacity: 0.75; } +} + + +.ember-chat .chat-menu.ffz-ui-popup { padding: 0; } + +.ffz-button { + float: right; + margin-top: -6px; + text-transform: none; +} + +.ffz-noty .noty_message { + background-image: url("//cdn.frankerfacez.com/icon32.png") !important; + background-repeat: no-repeat !important; + background-position: 5px 10px !important; + padding-left: 42px !important; + text-align: left; +} + +.ffz-ui-popup .button.live { overflow: hidden; background: #6441A5; color: #fff; } +.ffz-ui-popup .button.live span { z-index: 2; position: relative; } + +.ffz-ui-popup .button.live:before, .ffz-ui-popup .button.live:after { + content: ""; + display: block; + position: absolute; + width: 0px; + height: 0px; + border-radius: 999px; + -moz-border-radius: 999px; + -webkit-border-radius: 999px; + top: 50%; + left: 50%; + z-index: 1 +} + +.ffz-ui-popup .button.live.purple:before, .ffz-ui-popup .button.live.purple:after { + box-shadow: 0 0 3px 1px #a68ed2,inset 0 0 3px 1px #a68ed2; + -moz-box-shadow: 0 0 3px 1px #a68ed2,inset 0 0 3px 1px #a68ed2; + -webkit-box-shadow: 0 0 3px 1px #a68ed2,inset 0 0 3px 1px #a68ed2; +} + +.ffz-ui-popup .button.live.blue:before, .ffz-ui-popup .button.live.blue:after { + box-shadow: 0 0 3px 1px #8ea2d1,inset 0 0 3px 1px #8ea2d1; + -moz-box-shadow: 0 0 3px 1px #8ea2d1,inset 0 0 3px 1px #8ea2d1; + -webkit-box-shadow: 0 0 3px 1px #8ea2d1,inset 0 0 3px 1px #8ea2d1; +} + +.ffz-ui-popup .button.live:before { + animation: expand 1500ms infinite ease-in; + -moz-animation: expand 1500ms infinite ease-in; + -webkit-animation: expand 1500ms infinite ease-in; + -o-animation: expand 1500ms infinite ease-in +} + +.ffz-ui-popup .button.live:after { + animation: expand 1500ms infinite 750ms ease-in; + -moz-animation: expand 1500ms infinite 750ms ease-in; + -webkit-animation: expand 1500ms infinite 750ms ease-in; + -o-animation: expand 1500ms infinite 750ms ease-in +} + +#dash_main #stats .stat.dark#ffz_count svg path { fill: #cacaca; } + +#ffz-ui-following .follow-button a { + padding: 0 10px; + color: #fff; +} + +#ffz-following-popup { + background-image: url('//cdn.frankerfacez.com/script/zreknarf-bg.png'); + background-repeat: no-repeat; + background-position: 115% -75%; + background-size: 50%; +} + +.ffz-live-team-channel .ffz-game { + display: inline-block; + max-width: 150px; + text-overflow: ellipsis; + overflow: hidden; + margin-bottom: -5px; +} + +/* Theater Mode hover bar */ + +.ffz-theater-stats .app-main.theatre .player-column:focus #hostmode > div.target-meta, +.ffz-theater-stats .app-main.theatre .player-column:hover #hostmode > div.target-meta, +.ffz-theater-stats .app-main.theatre #channel .player-column:focus #broadcast-meta, +.ffz-theater-stats .app-main.theatre #channel .player-column:hover #broadcast-meta { + background-color: #19191f; + color: #aaa; + + position: absolute; + top: -25px; + left: 120px; + right: 10px; + z-index: 7; + opacity: 0.95; + height: 20px; +} + +.ffz-theater-stats.ffz-sidebar-swap .app-main.theatre .player-column:focus #hostmode > div.target-meta, +.ffz-theater-stats.ffz-sidebar-swap .app-main.theatre .player-column:hover #hostmode > div.target-meta, +.ffz-theater-stats.ffz-sidebar-swap .app-main.theatre #channel .player-column:focus #broadcast-meta, +.ffz-theater-stats.ffz-sidebar-swap .app-main.theatre #channel .player-column:hover #broadcast-meta { + left: 145px; +} + +.ffz-theater-stats .app-main.theatre #hostmode > div.target-meta div.target-title { + padding: 5px 0 2px 5px; +} + +.ffz-theater-stats .app-main.theatre #hostmode > div.target-meta div.target-title, +.ffz-theater-stats .app-main.theatre #channel .player-column #broadcast-meta .info { padding-left: 5px; } + +.ffz-theater-stats .app-main.theatre #hostmode > div.target-meta div.target-title, +.ffz-theater-stats .app-main.theatre #channel .player-column #broadcast-meta .info .title { + font-size: 12px; + line-height: 20px; + color: #dedede; +} + +.ffz-theater-stats .app-main.theatre #hostmode > div.target-meta div.target-title, +.ffz-theater-stats .app-main.theatre #channel .player-column #broadcast-meta .info .title, +.ffz-theater-stats .app-main.theatre #channel .player-column #broadcast-meta .info .title .over { + background-color: rgba(16,16,16,0.3); +} + +.ffz-theater-stats .app-main.theatre #hostmode > div.target-meta .target-user-and-game, +.ffz-theater-stats .app-main.theatre #channel .player-column #broadcast-meta .info .channel, +.ffz-theater-stats .app-main.theatre #channel .player-column #broadcast-meta .info .edit-link, +.ffz-theater-stats .app-main.theatre #broadcast-meta .profile-link { + display: none; +} + +.ffz-theater-stats .app-main.theatre .player-column:focus #hostmode > div.clearfix, +.ffz-theater-stats .app-main.theatre .player-column:hover #hostmode > div.clearfix { + margin-bottom: 30px; +} + +.ffz-theater-stats .app-main.theatre .player-column:focus #hostmode > div.clearfix, +.ffz-theater-stats .app-main.theatre .player-column:hover #hostmode > div.clearfix, +.ffz-theater-stats .app-main.theatre .player-column:focus .stats-and-actions, +.ffz-theater-stats .app-main.theatre .player-column:hover .stats-and-actions { + background-color: #19191f; + + color: #aaa; + + position: absolute; + bottom: 55px; + margin-right: 150px; + left: 10px; + z-index: 7; + padding: 10px; + opacity: 0.95; +} + +.ffz-theater-stats.ffz-top-conversations .app-main.theatre .player-column:focus #hostmode > div.clearfix, +.ffz-theater-stats.ffz-top-conversations .app-main.theatre .player-column:hover #hostmode > div.clearfix, +.ffz-theater-stats.ffz-top-conversations .app-main.theatre .player-column:focus .stats-and-actions, +.ffz-theater-stats.ffz-top-conversations .app-main.theatre .player-column:hover .stats-and-actions { + bottom: 15px; +} + +.ffz-theater-stats .app-main.theatre .channel-stats .stat { color: #aaa; } + +.ffz-theater-stats .app-main.theatre .channel-stats span:not(.live-count) svg path { + fill: rgba(255,255,255,0.35) !important; +} + +.ffz-theater-stats .app-main.theatre .follow-button .notify:before, +.ffz-theater-stats .app-main.theatre .button.drop:after, +.ffz-theater-stats .app-main.theatre .follow-button .drop.follow:after { + border: 5px solid rgba(255,255,255,0.35); + border-left-color: transparent; + border-right-color: transparent; + border-bottom-color: transparent; +} + +.ffz-theater-stats .app-main.theatre .follow-button .notify { + background-color: #25252a; +} + +.ffz-theater-stats .app-main.theatre .button:not(.primary) { + color: #a68ed2; +} + +.ffz-theater-stats .app-main.theatre .button.glyph-only svg path { + fill: #a68ed2; +} + +.ffz-theater-stats .app-main.theatre .button.primary.subscribe-button { + color: #fff; +} + + +/* SRL Race Support */ + +#ffz-following-popup.right { + right: 0; + left: auto; +} + +#ffz-ui-following .notification-controls, +#ffz-ui-race { + position: relative; +} + +#ffz-ui-race .button span { + display: inline-block; + height: 30px; + background: no-repeat 0 50%; +} + +#ffz-ui-race .button span.logo { + padding-left: 44px; + background-image: url("//cdn.frankerfacez.com/script/srl_button.png"); +} + + +#ffz-race-popup { + position: absolute; + bottom: 0; + background-image: url("//cdn.frankerfacez.com/script/zreknarf-bg.png"); + background-repeat: no-repeat; + background-position: 115% 110%; +} + +#ffz-race-popup.right { right: 10px; } + +#ffz-race-popup .heading { + margin: -20px -20px 20px; + width: 340px; height: 65px; + position: relative; +} + +#ffz-race-popup .heading div { + padding: 10px 0 0 20px; + max-width: 240px; +} + +#ffz-race-popup .heading h2 { + font-size: 1.5em; + padding-bottom: 5px; + display: block; + width: 240px; + max-height: 45px; + overflow: hidden; + text-overflow: ellipsis; +} + +#ffz-race-popup .heading span { + line-height: 30px; + position: absolute; + top: 17.5px; + right: 20px; + padding: 0 5px; + background: rgba(0,0,0,0.5); + color: #fff; + border-radius: 5px; +} + +#ffz-race-popup .right { text-align: right; } + +#ffz-race-popup .table { + overflow-y: auto; +} + +#ffz-race-popup table { + width: 100%; + text-align: center; + border-spacing: 0; +} + +#ffz-race-popup table a { + color: inherit; +} + +.ffz-about-table a.twitch, +.ffz-about-table a.youtube, +.ffz-about-table a.twitter, +#ffz-race-popup a.twitch, +#ffz-race-popup a.hitbox { + display: inline-block; + height: 16px; + margin-left: 5px; + background-repeat: no-repeat; +} + +.ffz-about-table a.youtube { + width: 23px; + background-image: url("//cdn.frankerfacez.com/script/youtube_logo.png"); +} + +.ffz-about-table a.twitter { + width: 20px; + background-image: url("//cdn.frankerfacez.com/script/twitter_logo.png"); +} + +#ffz-race-popup a.twitch, +.ffz-about-table a.twitch { + width: 15px; + background-image: url("//cdn.frankerfacez.com/script/twitch_logo.png"); +} + +#ffz-race-popup a.hitbox { + width: 12px; + background-image: url("//cdn.frankerfacez.com/script/hitbox_logo.png"); +} + +#ffz-race-popup table tbody tr.done:nth-child(0n+1) td { background-color: rgba(255,255,0,.2); } +#ffz-race-popup table tbody tr.done:nth-child(0n+2) td { background-color: rgba(128,128,128,.2); } +#ffz-race-popup table tbody tr.done:nth-child(0n+3) td { background-color: rgba(210,100,0,.2); } +#ffz-race-popup table tbody tr.forfeit td { opacity: 0.5; background-color: rgba(210,100,100,.2); } +#ffz-race-popup table tbody tr.racing td.time { opacity: 0.5; } + +#ffz-race-popup table th, #ffz-race-popup td { padding: 1px; } +#ffz-race-popup table th { border-bottom: 1px solid; } + + +/* Menu Options */ + +.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content.menu-side-padding { padding-left: 20px; padding-right: 20px; } + +.emoticon-grid.collapsed span, +.chat-menu-content.collapsed p { display: none; } + +.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content.collapsed .heading, +.chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid.collapsed .heading { + padding-bottom: 0; +} + +.emoticon-grid.collapsable .heading, +.emoticon-grid.collapsed, +.chat-menu-content.collapsed { + cursor: pointer; +} + +.emoticon-grid.collapsable .heading, +.chat-menu-content.collapsable .heading { + position: relative; +} + +.list-header span.right { float: right; } + +.chat-menu-content.collapsable .heading span.right { + padding-right: 15px; +} + +.emoticon-grid.collapsable .heading:before, +.chat-menu-content.collapsable .heading:before { + content: ""; + border: 5px solid #666; + border-left-color: transparent; + border-right-color: transparent; + + position: absolute; + margin-top: 6px; + right: 20px; +} + +.emoticon-grid.collapsable.collapsed .heading:before, +.chat-menu-content.collapsable.collapsed .heading:before { border-bottom-color: transparent; } + +.emoticon-grid.collapsable:not(.collapsed) .heading:before { + display: none; +} + +.chat-menu-content.collapsable:not(.collapsed) .heading:before { + border-top-color: transparent; + margin-top: 1px; +} + + +#small_nav .content ul li#ffz_small_menu .filter_icon svg { + margin: 11px 13px; +} + +.ffz-ui-sub-menu-page, +.ffz-ui-menu-page { overflow-y: auto; } + +.ffz-ui-menu-page[data-page="about"], +.ffz-ui-menu-page .chat-menu-content p { padding: 0 20px; } + + +.chat-container.dark .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box, +.app-main.theatre .chat-container .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box, +.chat-container.force-dark .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box, +.ember-chat-container.dark .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box, +.ember-chat-container.force-dark .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box { + background-color: rgb(16,16,16); + color: rgb(195,195,195); + border-color: #32323e; +} + + +.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 { + padding: 10px 20px; + border-top: 1px solid rgba(0,0,0,0.2); + text-align: left; +} + +.chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid .heading { + padding-left: 43px; + background-repeat: no-repeat; + background-position: 20px 10px; +} + +.chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid + .emoticon-grid { padding-top: 0; } + +.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content:first-of-type .heading, +.chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid:first-of-type .heading { + border-top: none; + padding-top: 0; + background-position-y: 0; +} + +.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content { + padding: 10px 0; + background-color: transparent; +} + +.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content + .chat-menu-content { + padding-top: 0; +} + +.ffz-ui-menu-page span.help { + display: block; + opacity: 0.75; +} + +.ffz-ui-menu-page p.disabled span.switch-label, +.ffz-ui-menu-page span.help, +.ffz-ui-menu-page span.option-label, +.ffz-ui-menu-page p.option a { + margin-left: 50px; +} + +.ffz-ui-menu-page span.option-label { + line-height: 25px; +} + +.ffz-ui-menu-page input, +.ffz-ui-menu-page select { + margin: 0 10px 5px; +} + +.ffz-ui-menu-page input[type="file"] { + width: auto; +} + +#ffz-chat-menu { pointer-events: none; } + +.ffz-ui-popup ul.menu { + list-style-type: none; + border-top: 1px solid rgba(0,0,0,0.2); + background-color: #eee; +} + +.ffz-ui-popup ul.menu:not(.sub-menu) { + cursor: ew-resize; +} + +.ffz-ui-popup .emoticon-selector-box { + width: 10000px !important; /* Max-width has our back */ + max-width: 300px; + pointer-events: auto; +} + +.ember-chat .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box .emoticon-grid { background-color: transparent; } + +.app-main.theatre .ffz-ui-popup ul.menu, +.chat-container.dark .ffz-ui-popup ul.menu, +.chat-container.force-dark .ffz-ui-popup ul.menu, +.ember-chat-container.dark .ffz-ui-popup ul.menu, +.ember-chat-container.force-dark .ffz-ui-popup ul.menu, +.ffz-ui-popup.dark ul.menu { + background-color: #282828; +} + +.ffz-ui-popup ul.sub-menu li.title, +.ffz-ui-menu-page .heading .right, +.ffz-ui-popup ul.menu li.item { + float: right; +} + +.ffz-ui-popup ul.sub-menu li.item, +.ffz-ui-popup ul.menu li.title { + float: left; +} + +.ffz-ui-popup ul.sub-menu { background-color: #dfdfdf; } + +.app-main.theatre .ffz-ui-popup ul.sub-menu, +.chat-container.dark .ffz-ui-popup ul.sub-menu, +.chat-container.force-dark .ffz-ui-popup ul.sub-menu, +.ember-chat-container.dark .ffz-ui-popup ul.sub-menu, +.ember-chat-container.force-dark .ffz-ui-popup ul.sub-menu, +.ffz-ui-popup.dark ul.sub-menu { + background-color: #181818; +} + +.ffz-ui-popup ul.sub-menu a { + text-decoration: none; + color: #333; +} + +.app-main.theatre .ffz-ui-popup ul.sub-menu a, +.chat-container.dark .ffz-ui-popup ul.sub-menu a, +.chat-container.force-dark .ffz-ui-popup ul.sub-menu a, +.ember-chat-container.dark .ffz-ui-popup ul.sub-menu a, +.ember-chat-container.force-dark .ffz-ui-popup ul.sub-menu a, +.ffz-ui-popup.dark ul.sub-menu a { + color: #d3d3d3 !important; +} + +span.ffz-handle { + display: inline-block; + position: relative; + height: 26px; + width: 14px; + transition: width 500ms; +} + +span.ffz-handle:before, +span.ffz-handle:after { + position: absolute; + left: 4px; + top: 5px; + content: ""; + height: 14px; + border: 1px solid #bbb; + border-radius: 4px; + transition: transform 500ms, left 500ms, border-color 500ms, border-width 500ms, height 500ms; +} + +span.ffz-handle:after { left: 8px } + +.ffz-ui-popup.ui-moved span.ffz-handle { width: 24px; cursor: pointer; } + +.ffz-ui-popup.ui-moved span.ffz-handle:before, +.ffz-ui-popup.ui-moved span.ffz-handle:after { + left: 11px; + border-color: #333; +} + +.ffz-ui-popup.ui-moved span.ffz-handle:before { transform: rotate(45deg); } +.ffz-ui-popup.ui-moved span.ffz-handle:after { transform: rotate(-45deg); } + +.app-main.theatre span.ffz-handle:before, +.chat-container.dark span.ffz-handle:before, +.chat-container.force-dark span.ffz-handle:before, +.ember-chat-container.dark span.ffz-handle:before, +.ember-chat-container.force-dark span.ffz-handle:before, +.ffz-ui-popup.dark span.ffz-handle:before, +.app-main.theatre span.ffz-handle:after, +.chat-container.dark span.ffz-handle:after, +.chat-container.force-dark span.ffz-handle:after, +.ember-chat-container.dark span.ffz-handle:after, +.ember-chat-container.force-dark span.ffz-handle:after, +.ffz-ui-popup.dark span.ffz-handle:after { + border-color: #666; +} + +.app-main.theatre .ffz-ui-popup.ui-moved span.ffz-handle:before, +.chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:before, +.chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:before, +.ember-chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:before, +.ember-chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:before, +.ffz-ui-popup.ui-moved.dark span.ffz-handle:before, +.app-main.theatre .ffz-ui-popup.ui-moved span.ffz-handle:after, +.chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:after, +.chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:after, +.ember-chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:after, +.ember-chat-container.force-dark .ffz-ui-popup.ui-moved span.ffz-handle:after, +.ffz-ui-popup.ui-moved.dark span.ffz-handle:after { + border-color: #d3d3d3; +} + + +.ffz-ui-popup ul.menu li.title > span.ffz-handle { + float: left; + margin: 5px; +} + +.ffz-ui-popup ul.menu li.title > span.title { + display: block; + margin-left: 24px; + padding: 10px 20px 10px 0; + line-height: 16px; + transition: margin-left 500ms; +} + +.ffz-ui-popup.ui-moved ul.menu li.title > span.title { margin-left: 34px; } + +.ffz-ui-popup ul.menu a { + display: block; + padding: 10px; + height: 16px; + margin-top: -1px; + cursor: pointer; + border-left: 1px solid rgba(0,0,0,0.2); + border-top: 1px solid transparent; +} + +.ffz-ui-popup ul.sub-menu a { + border-left: none; + border-right: 1px solid rgba(0,0,0,0.2); +} + +.ffz-ui-popup ul.menu li.active { + background-color: #fff; +} + +.ffz-ui-popup ul.menu li.active a { + border-top-color: #fff; +} + +.ffz-ui-popup ul.menu li.active.has-sub-menu { + background-color: #dfdfdf; +} + +.ffz-ui-popup ul.menu li.active.has-sub-menu a { + border-top-color: #dfdfdf; +} + + +.chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active, +.chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active, +.ember-chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active, +.ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active, +.app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu li.active, +.ffz-ui-popup.dark ul.menu li.active { + background-color: rgb(16,16,16); +} + +.chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active a, +.chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active a, +.ember-chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active a, +.ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active a, +.app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu li.active a, +.ffz-ui-popup.dark ul.menu li.active a { + border-top-color: rgb(16,16,16); +} + +.chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu, +.chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu, +.ember-chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu, +.ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu, +.app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu, +.ffz-ui-popup.dark ul.menu li.active.has-sub-menu { + background-color: #181818; +} + +.chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu a, +.chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu a, +.ember-chat-container.dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu a, +.ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu a, +.app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu li.active.has-sub-menu a, +.ffz-ui-popup.dark ul.menu li.active.has-sub-menu a { + border-top-color: #181818; +} + +.chat-container.dark .chat-interface .ffz-ui-popup a, +.chat-container.force-dark .chat-interface .ffz-ui-popup a, +.ember-chat-container.dark .chat-interface .ffz-ui-popup a, +.ember-chat-container.force-dark .chat-interface .ffz-ui-popup a, +.app-main.theatre .chat-container .chat-interface .ffz-ui-popup a, +.ffz-ui-popup.dark .ffz-ui-menu-page a { color: #fff; } + + +.chat-container.dark .chat-interface .ffz-ui-popup ul.menu svg path, +.chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu svg path, +.ember-chat-container.dark .chat-interface .ffz-ui-popup ul.menu svg path, +.ember-chat-container.force-dark .chat-interface .ffz-ui-popup ul.menu svg path, +.app-main.theatre .chat-container .chat-interface .ffz-ui-popup ul.menu svg path, +.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; } + + +.ffz-ui-popup .option-label span, +.ffz-ui-popup .switch-label span { + opacity: 0.8; + font-size: 10px; + line-height: 20px; + padding: 4px; + background: rgba(0,0,0,0.2); + vertical-align: top; +} + +/* BTTV Menu Fixes */ + +.ffz-ui-popup.dark .emoticon-grid .heading, +.ffz-ui-popup.dark li.title { color: #fff; } +.ffz-ui-popup.dark .ffz-ui-menu-page { background-color: #1e1e1e; } + + +/* Menu Scrollbar */ + +.conversations-list .conversations-list-inner::-webkit-scrollbar, +.conversation-window .conversation-content::-webkit-scrollbar, +.chat-history::-webkit-scrollbar, +#ffz-race-popup .table::-webkit-scrollbar, +.emoticon-selector-box .all-emotes::-webkit-scrollbar, +.ffz-ui-sub-menu-page::-webkit-scrollbar, +.ffz-ui-menu-page::-webkit-scrollbar { + width: 6px; +} + +.conversations-list .conversations-list-inner::-webkit-scrollbar-thumb, +.conversation-window .conversation-content::-webkit-scrollbar-thumb, +.chat-history::-webkit-scrollbar-thumb, +#ffz-race-popup .table::-webkit-scrollbar-thumb, +.emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, +.ffz-ui-sub-menu-page::-webkit-scrollbar-thumb, +.ffz-ui-menu-page::-webkit-scrollbar-thumb { + border-radius: 7px; + background: rgba(0,0,0,0.7); + box-shadow: 0 0 1px 1px rgba(255,255,255,0.25); +} + +.ffz-dark .chat-history::-webkit-scrollbar-thumb, +.ffz-dark .table::-webkit-scrollbar-thumb, +.ffz-dark .conversation-window .conversation-content::-webkit-scrollbar-thumb, +.ffz-dark .conversations-list .conversations-list-inner::-webkit-scrollbar-thumb, +.app-main.theatre .conversation-window .conversation-content::-webkit-scrollbar-thumb, +.app-main.theatre .conversations-list .conversations-list-inner::-webkit-scrollbar-thumb, +.ember-chat-container.dark .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, +.chat-container.dark .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, +.app-main.theatre .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, +.ember-chat-container.dark .ffz-ui-menu-page::-webkit-scrollbar-thumb, +.chat-container.dark .ffz-ui-menu-page::-webkit-scrollbar-thumb, +.app-main.theatre .ffz-ui-menu-page::-webkit-scrollbar-thumb, +.ember-chat-container.dark .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb, +.chat-container.dark .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb, +.app-main.theatre .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb { + background: rgba(255,255,255,0.6); + box-shadow: 0 0 1px 1px rgba(0,0,0,0.25); +} + + +/* Chat Mentions */ + +.ember-chat .mentioned:empty, +.ember-chat .mentioning:empty { + display: none; +} + +.ffz-chat-colors-gray .chat-line:not(.admin):not(.notification) span.from, +.ffz-chat-colors-gray .chat-line:not(.admin):not(.notification) span.message { + color: inherit !important +} + +.ffz-chat-background .ember-chat .mentioning, +.ffz-chat-background .ember-chat .mentioned { + border-radius: 10px; + padding: 3px 7px; + font-weight: bold; + color: #32323e; + background-color: rgba(255,255,255, 0.75); +} + +.ffz-chat-background .app-main.theatre .chat-container .chat-line .mentioned, +.ffz-chat-background .ember-chat-container.dark .chat-line .mentioned, +.ffz-chat-background .chat-container.dark .chat-line .mentioned, +.ffz-chat-background .app-main.theatre .chat-container .chat-line .mentioning, +.ffz-chat-background .ember-chat-container.dark .chat-line .mentioning, +.ffz-chat-background .chat-container.dark .chat-line .mentioning { + color: #8c8c9c; + background-color: rgba(16,16,20, 0.75); +} + + +/* Fix Moderation Cards */ + +img.channel_background[src="null"] { display: none; } + +.ember-chat .ffz-moderation-card { + border: 2px solid #cbcbcb; + max-width: 340px; + /*box-shadow: #808080 0 0 5px;*/ +} + +.ember-chat .ffz-moderation-card .extra-interface { + padding-top: 0; +} + +.ember-chat .ffz-moderation-card .extra-interface + .extra-interface { + margin-top: -10px; +} + +.ember-chat .ffz-moderation-card.ffz-has-info h3.name { + margin-top: 0; +} + +.ember-chat .ffz-moderation-card .info { + float: none; + position: relative; + z-index: 4; + margin-left: 50px; + height: 18px; + line-height: 18px; +} + +.ember-chat .ffz-moderation-card .info.channel-stats .stat { + color: #fff; +} + +.ember-chat .ffz-moderation-card .info.channel-stats .stat svg { + margin: 1px 5px 1px 0; + pointer-events: none; +} + +.ember-chat .ffz-moderation-card .info svg path { fill: #fff; } + +.ember-chat .ffz-moderation-card button { + margin: 0; + padding: 0 5px; +} + +.ember-chat .ffz-moderation-card button:not(.glyph-only):hover, +.ember-chat .ffz-moderation-card button:not(.glyph-only):focus { + color: #fff; + background-color: rgba(117,80,186, 1); +} + +.ember-chat .ffz-moderation-card button.message { + height: 30px; width: 28px; +} + +.ember-chat .ffz-moderation-card.ffz-is-mod .interface .mod-controls:last-of-type, +.ember-chat .ffz-moderation-card .interface span.right { + float: right; +} + +.ember-chat .ffz-moderation-card:focus { + outline: none; + border-color: #444; + /*box-shadow: #000 0 0 5px;*/ +} + +.ember-chat .ffz-moderation-card .interface:not(:last-of-type) { + border-bottom: none; +} + +.ember-chat .ffz-moderation-card .interface { + border-top: none; +} + +.ember-chat .ffz-moderation-card h3.name { display: inline-block; } + +.ember-chat .ffz-moderation-card .info, +.ember-chat .ffz-moderation-card h3.name { + text-shadow: black 0 0 5px; +} + +.ember-chat .ffz-moderation-card .channel_background { + width: 100%; + top: 0; +} + + +body:not(.ffz-chat-purge-icon) .ember-chat .mod-icons .purge { display: none; } + +.ember-chat .mod-icons .purge { + background-image: url('//cdn.frankerfacez.com/script/PurgeButton.svg'); + background-repeat: no-repeat; +} + +.ember-chat .mod-icons .custom { + text-indent: 0; + text-align: center; + text-decoration: none; + font-size: 18px; + font-weight: bold; + color: #888 !important; +} + + +/* Chat Rows */ + +.ffz-alias { font-style: italic; } + +.ember-chat .chat-messages .chat-line.ffz-has-deleted { + line-height: 30px; +} + +.chat-line.ffz-deleted > span { + opacity: 0.5; +} + +.chat-line.ffz-deleted > span.message { + text-decoration: line-through; +} + +.chat-line.ffz-deleted:hover > span { + opacity: 0.9; +} + +.chat-line.ffz-deleted:hover > span.message { + text-decoration: none; +} + +.ffz-chat-background .more-messages-indicator { + /* This looks better when it's full width. */ + margin: 0 -20px; +} + +.ffz-chat-background .chat-line .message { + word-break: break-word; +} + +.ffz-chat-background .ember-chat .chat-messages .tse-scroll-content { + padding: 0; +} + +/* This cuts off emotes. +.ffz-chat-background .ember-chat .chat-messages .chat-line { + padding: 3px 20px; + margin: 0px 0px; +} */ + +.ffz-chat-separator .conversation-chat-lines > div, +.ffz-chat-background .conversation-chat-lines > div, +.ffz-chat-separator .chat-line, +.ffz-chat-background .chat-line { + position: relative; + z-index: 1; +} + +.ffz-chat-padding .conversation-window .conversation-chat-lines { + padding-top: 0; +} + +.ffz-chat-padding .ember-chat .chat-messages .chat-line, +.ffz-chat-padding .ember-chat .chat-messages .chat-line.admin, +.ffz-chat-padding .conversation-window .conversation-system-messages, +.ffz-chat-padding .conversation-window .conversation-chat-line, +.ffz-chat-padding .conversation-window .timestamp-line { + padding: 5px; +} + +.ffz-chat-separator .conversation-chat-lines > div:before, +.ffz-chat-background .conversation-chat-lines > div:before, +.ffz-chat-separator .chat-line:before, +.ffz-chat-background .chat-line:before { + content: ""; + position: absolute; + z-index: -1; + left: 0; right: 0; + top: 2px; bottom: 1px; +} + +.ffz-chat-background .chat-history .chat-line:before { + top: 0; bottom: 0; +} + + +.ffz-chat-separator .conversation-chat-lines > div:before, +.ffz-chat-separator .chat-line:before { + border-bottom: 1px solid #aaa; +} + +.ffz-chat-separator-wide .conversation-chat-lines > div:before, +.ffz-chat-separator-wide .chat-line:before { + border-top: 1px solid #aaa; +} + +.ffz-chat-separator-3d .conversation-chat-lines > div:before, +.ffz-chat-separator-3d .chat-line:before { + border-top: 1px solid rgba(255,255,255,0.5); +} + +.ffz-chat-separator-3d-inset .conversation-chat-lines > div:before, +.ffz-chat-separator-3d-inset .chat-line:before { + border-bottom-color: rgba(255,255,255,0.5); + border-top: 1px solid #aaa; +} + +.ffz-chat-separator-wide .conversation-chat-lines > div:first-of-type:before, +.ffz-chat-separator-3d .conversation-chat-lines > div:first-of-type:before, +.ffz-chat-separator-wide ul.chat-lines div:first-of-type .chat-line:before, +.ffz-chat-separator-3d ul.chat-lines div:first-of-type .chat-line:before { + border-top: none; +} + +.ffz-chat-separator:not(.ffz-chat-background) .conversation-chat-lines > div:last-of-type:before, +.ffz-chat-separator:not(.ffz-chat-background) ul.chat-lines div:last-of-type .chat-line:before, +.ffz-chat-separator ul.chat-lines div:last-of-type .chat-line:not(.ffz-alternate):before { + border-bottom: none; +} + +.ffz-chat-separator .theatre .conversation-chat-lines > div:before, +.ffz-chat-separator.ffz-dark .conversation-chat-lines > div:before, +.ffz-chat-separator .app-main.theatre .chat-line:before, +.ffz-chat-separator .chat-container.dark .chat-line:before, +.ffz-chat-separator .chat-container.force-dark .chat-line:before, +.ffz-chat-separator .ember-chat-container.dark .chat-line:before, +.ffz-chat-separator .ember-chat-container.force-dark .chat-line:before { + border-bottom-color: #000; +} + +.ffz-chat-separator-wide .theatre .conversation-chat-lines > div:before, +.ffz-chat-separator-wide.ffz-dark .conversation-chat-lines > div:before, +.ffz-chat-separator-wide .app-main.theatre .chat-line:before, +.ffz-chat-separator-wide .chat-container.dark .chat-line:before, +.ffz-chat-separator-wide .chat-container.force-dark .chat-line:before, +.ffz-chat-separator-wide .ember-chat-container.dark .chat-line:before, +.ffz-chat-separator-wide .ember-chat-container.force-dark .chat-line:before { + border-top-color: #000; +} + +.ffz-chat-separator-3d .theatre .conversation-chat-lines > div:before, +.ffz-chat-separator-3d.ffz-dark .conversation-chat-lines > div:before, +.ffz-chat-separator-3d .app-main.theatre .chat-line:before, +.ffz-chat-separator-3d .chat-container.dark .chat-line:before, +.ffz-chat-separator-3d .chat-container.force-dark .chat-line:before, +.ffz-chat-separator-3d .ember-chat-container.dark .chat-line:before, +.ffz-chat-separator-3d .ember-chat-container.force-dark .chat-line:before { + border-top-color: rgba(255,255,255,0.1); +} + +.ffz-chat-separator-3d-inset .theatre .conversation-chat-lines > div:before, +.ffz-chat-separator-3d-inset.ffz-dark .conversation-chat-lines > div:before, +.ffz-chat-separator-3d-inset .app-main.theatre .chat-line:before, +.ffz-chat-separator-3d-inset .chat-container.dark .chat-line:before, +.ffz-chat-separator-3d-inset .chat-container.force-dark .chat-line:before, +.ffz-chat-separator-3d-inset .ember-chat-container.dark .chat-line:before, +.ffz-chat-separator-3d-inset .ember-chat-container.force-dark .chat-line:before { + border-bottom-color: rgba(255,255,255,0.1); + border-top-color: #000; +} + +.ffz-chat-background .conversation-chat-lines > div:nth-child(2n+0):before, +.ffz-chat-background .chat-history .chat-line.ffz-alternate:before, +.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-alternate:before { + background-color: rgba(0,0,0, 0.1); +} + +.ffz-chat-background .chat-history .chat-line.ffz-mentioned:before, +.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-mentioned:before { + background-color: rgba(255,127,127, 0.2); +} + +.ffz-chat-background .chat-history .chat-line.ffz-mentioned-ffz-alternate:before, +.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate:before { + background-color: rgba(255,127,127, 0.4); +} + +.ffz-chat-background .theatre .conversation-chat-lines > div:nth-child(2n+0):before, +.ffz-chat-background.ffz-dark .conversation-chat-lines > div:nth-child(2n+0):before, + +.ffz-chat-background .app-main.theatre .chat-history .chat-line.ffz-alternate:before, +.ffz-chat-background .chat-container.dark .chat-history .chat-line.ffz-alternate:before, +.ffz-chat-background .ember-chat-container.dark .chat-history .chat-line.ffz-alternate:before, +.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .chat-line.ffz-alternate:before, +.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-alternate:before, +.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .chat-line.ffz-alternate:before { + background-color: rgba(255,255,255, 0.05); +} + + +.ffz-chat-background .app-main.theatre .chat-history .chat-line.ffz-mentioned:before, +.ffz-chat-background .chat-container.dark .chat-history .chat-line.ffz-mentioned:before, +.ffz-chat-background .ember-chat-container.dark .chat-history .chat-line.ffz-mentioned:before, +.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .chat-line.ffz-mentioned:before, +.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned:before, +.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned:before { + background-color: rgba(255,0,0, 0.2); +} + +.ffz-chat-background .app-main.theatre .chat-history .chat-line.ffz-mentioned.ffz-alternate:before, +.ffz-chat-background .chat-container.dark .chat-history .chat-line.ffz-mentioned.ffz-alternate:before, +.ffz-chat-background .ember-chat-container.dark .chat-history .chat-line.ffz-mentioned.ffz-alternate:before, +.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate:before, +.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate:before, +.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate:before { + background-color: rgba(255,0,0, 0.3); +} +*/ + +/* The New Whispers */ + +.ffz-chat-background .ember-chat .chat-messages .whisper-line { + padding-left: 16px; + border-left-width: 4px !important; +} + +.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .whisper-line.whisper-incoming:before, +.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming:before, +.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming:before { + /* 675980 */ + background-color: rgba(78,51,128, 0.4); +} + +.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .whisper-line.whisper-incoming.ffz-alternate:before, +.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming.ffz-alternate:before, +.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming.ffz-alternate:before { + /* 675980 */ + background-color: rgba(78,51,128, 0.5); +} + +.ffz-chat-background .ember-chat .chat-messages .whisper-line.whisper-incoming:before { + background-color: rgba(205,178,255, 0.4); +} + +.ffz-chat-background .ember-chat .chat-messages .whisper-line.whisper-incoming.ffz-alternate:before { + background-color: rgba(205,178,255, 0.6); +} + + + +/* Temporary Fix */ + +.chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming, +.app-main.theatre .chat-container .ember-chat .chat-messages .whisper-line.whisper-incoming, +.chat-container.force-dark .ember-chat .chat-messages .whisper-line.whisper-incoming, +.ember-chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming, +.app-main.theatre .ember-chat-container.chat-container .ember-chat .chat-messages .whisper-line.whisper-incoming, +.ember-chat-container.force-dark .ember-chat .chat-messages .whisper-line.whisper-incoming { + background-color: #101014; + border-left: 2px solid #a68ed2 +} + + +/* Emoticon Tooltips */ + +.ffz-wide-tip .tipsy-inner { + min-width: 300px; + max-width: 600px; + text-align: left; + position: relative; +} + +.ffz-wide-tip span.stat { + float: right; + margin-left: 5px; +} + +.ffz-wide-tip b { margin-right: 20px; } + +.ffz-wide-tip span.stat svg { + float: left; + margin: 1px; +} + +.ffz-wide-tip svg path { fill: #fff; } +.ffz-wide-tip span.playing { + opacity: 0.7; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + display: block; + position: relative; + left: 0; + right: 0; +} + +.tipsy .tipsy-inner { + white-space: pre-wrap; +} + +/* Menu Page Loader */ + +.ffz-ui-sub-menu-page:empty, +.ffz-ui-menu-page:empty { + overflow: hidden; +} + +.ffz-ui-sub-menu-page:empty::after, +.ffz-ui-menu-page:empty::after { + content: " "; + display: block; + width: 80px; + height: 63px; + + background-image: url("//cdn.frankerfacez.com/script/spinner-dark.png"); + + margin: 50px auto; + -webkit-animation: ffz-rotateplane 1.2s infinite linear; + animation: ffz-rotateplane 1.2s infinite linear; +} + +@-webkit-keyframes ffz-rotateplane { + 0% { -webkit-transform: perspective(120px) rotateY(90deg) } + 25% { -webkit-transform: perspective(120px) rotateY(180deg) } + 75% { -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg) } + 100% { -webkit-transform: perspective(120px) rotateY(90deg) rotateX(180deg) } +} + +@keyframes ffz-rotateplane { + 0% { transform: perspective(120px) rotateY(90deg) } + 25% { transform: perspective(120px) rotateY(180deg) } + 75% { transform: perspective(120px) rotateY(180deg) rotateX(180deg) } + 100% { transform: perspective(120px) rotateY(90deg) rotateX(180deg) } +} + +/* Menu About Page */ + +.ffz-about-table { + width: 100%; +} + +.ffz-about-table td:first-child { + text-align: left; + width: 100%; +} + +.ffz-about-table .debug td { + padding-top: 10px; + opacity: 0.8; + font-size: 10px; +} + +.ffz-about-subheading { + /*text-transform: uppercase;*/ + letter-spacing: 2px; + margin: -5px 0 5px; +} + +.button.ffz-news, +.button.ffz-donate { + margin-left: 10px; + color: #fff !important; + padding: 0 10px; + font-size: 12px; +} + +.button.ffz-donate { background: #00b132; } +.button.ffz-donate:not(.disabled):hover { background: #08c43d; } + +.button.ffz-news { background: #755000; } +.button.ffz-news:not(.disabled):hover { background: #8a5f03; } + + +/* Dumb Fixes */ + +.ffz-bttv .no-bttv { display: none; } + +.chat-container.dark, .app-main.theatre .chat-container, +.chat-container.force-dark, .ember-chat-container.dark, +.app-main.theatre .ember-chat-container.chat-container, +.ember-chat-container.force-dark { + box-shadow: none; +} + + +/* Unsafe Links */ + +a.unsafe-link { + color: #a64141 !important; +} + +.chat-container.dark .chat-line a.unsafe-link { + color: #d28e8e !important; +} + +/* Chat Menu */ + +.ffz-room-list > div.ffz + ul.room-list { display: block !important; } + +.ffz-room-list > div:not(.ffz), +.ffz-room-list > ul:not(.ffz) { + display: none !important; +} + +.ffz-room-list > table { + padding: 15px 0 0; +} + +.ffz-room-list > table + table { + margin-top: 10px; +} + +.ffz-room-list > table th { + padding: 2px 5px; + color: #8c8c8c; + font-weight: normal; + text-transform: uppercase; +} + +.ffz-room-list > table > tbody tr { + line-height: 26px; +} + +.ffz-room-list > table td { + padding: 2px 0; + text-align: center; +} + +.ffz-room-list > table th:first-child, +.ffz-room-list > table td:nth-child(0n+2) { + width: 100%; + text-align: left; +} + +.ffz-room-row { + cursor: pointer; +} + +.ffz-room-list > table th:first-child, +.ffz-room-list > table td:first-child { + padding-left: 18px; +} + +.ffz-room-list > table th:last-child, +.ffz-room-list > table td:last-child { + padding-right: 18px; +} + +.ffz-room-list td svg { + margin: 5px; + float: left; +} + +.ffz-dark .ffz-room-row { color: #a68ed2; } +.ffz-dark .ffz-room-row svg path { fill: #a68ed2; } + +.ffz-room-row { color: #6441a5; } +.ffz-room-row svg path { fill: #6441a5; } + +.ffz-room-row:hover svg path, +.ffz-room-row:focus svg path, +.ffz-room-row.active svg path { fill: #fff; } + +.ffz-room-row:hover td, +.ffz-room-row:focus td, +.ffz-room-row.active td { + background-color: #6441A5; + color: #fff !important; +} + +th.ffz-row-switch { + min-width: 40px; +} + +.ffz-room-row a.leave-chat { + float: right; + margin-right: 12px; +} + +.ffz-row-switch .switch { + float: none; + margin: 5px 0 -4px; +} + +.ffz-row-switch .switch.active { + background-color: #362359; +} + + +/* Chat Tabs */ + +#ffz-group-tabs { + padding: 10px 10px 6px; + box-shadow: inset 0 -1px 0 0 rgba(0,0,0,0.2); + display: flex; + flex-wrap: wrap; +} + +.ffz-chat-tab { + flex-grow: 1; + position: relative; + + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + min-width: 70px; + + cursor: pointer; + padding: 5px; + margin: 0 4px 4px 0; + + display: inline-block; + + background-color: rgba(127,127,127,0.1); + color: #6441A5; +} + + +.ffz-chat-tab svg path { + fill: #6441A5; +} + +#ffz-group-tabs .button { + height: 18px; + padding-bottom: 10px; + margin-bottom: -10px; + margin-right: 4px; +} + +#ffz-group-tabs .button.glyph-only svg { + margin: 6px 0; +} + +.ffz-chat-tab svg { + width: 18px; + height: 18px; + margin: -5px 5px -5px 0; +} + +.ffz-chat-tab:hover, +.ffz-chat-tab:focus, +.ffz-chat-tab.active { + background-color: #6441A5; + color: #fff !important; +} + +.ffz-chat-tab.tab-mentioned { + background-color: rgba(128,50,50,0.1); + color: red !important; +} + +.ffz-chat-tab.tab-mentioned:not(.active):hover, +.ffz-chat-tab.tab-mentioned:not(.active):focus { + background-color: #a54141; + color: #fff !important; +} + +.ffz-chat-tab:not(.active):hover, +.ffz-chat-tab:not(.active):focus { + background-color: #7550ba; +} + +.ffz-chat-tab:hover svg path, +.ffz-chat-tab:focus svg path, +.ffz-chat-tab.active svg path { + fill: #fff !important; +} + +.ffz-chat-tab.active { + cursor: default; +} + +.ffz-chat-tab span:empty { display: none; } + +.ffz-chat-tab span { + padding: 0 4px; + display: inline-block; + border-radius: 2px; + text-align: center; + background-color: #f2f2f2; + color: #666; + position: absolute; + right: 5px; +} + + +/* Dark Group Tabs */ + +.app-main.theatre #ffz-group-tabs, +.chat-container.dark #ffz-group-tabs, +.ember-chat-container.dark #ffz-group-tabs { + box-shadow: inset 0 -1px 0 0 #32323e; +} + +.app-main.theatre .ffz-chat-tab, +.chat-container.dark .ffz-chat-tab, +.ember-chat-container.dark .ffz-chat-tab { + color: #B9A3E3; +} + +.app-main.theatre .ffz-chat-tab span, +.chat-container.dark .ffz-chat-tab span, +.ember-chat-container.dark .ffz-chat-tab span { + background-color: #19191f; + color: #fff; +} + +.app-main.theatre .ffz-chat-tab svg path, +.chat-container.dark .ffz-chat-tab svg path, +.ember-chat-container.dark .ffz-chat-tab svg path { + fill: #B9A3E3; +} + +/* Minimalistic Chat */ + +body.ffz-minimal-chat-head .ember-chat > .chat-header, +body.ffz-minimal-chat-head .ember-chat #ffz-group-tabs, +body.ffz-minimal-chat-input .ember-chat .chat-buttons-container { + display: none !important; +} + +/*body.ffz-minimal-chat .ember-chat .chat-messages, +body.ffz-minimal-chat .ember-chat .chat-interface .emoticon-selector { + bottom: 33px; +}*/ + +body.ffz-minimal-chat-input .ember-chat .chat-interface .emoticon-selector { + right: 10px; +} + +body.ffz-minimal-chat-input .ember-chat .chat-interface .emoticon-selector .dropmenu { + margin-bottom: 10px; +} + +body.ffz-minimal-chat-head .ember-chat .chat-room { + top: 0 !important; +} + +body.ffz-minimal-chat-input .ember-chat .chat-interface { + /*height: 33px !important;*/ + padding: 0; +} + +body.ffz-minimal-chat-input .ember-chat .chat-interface .textarea-contain { + top: 0 !important; + margin: 0 !important; + height: auto; +} + +body.ffz-minimal-chat-input .ember-chat .chat-interface .textarea-contain textarea { + /*height: 33px !important;*/ + overflow: hidden; + border-bottom: 0 !important; + border-left: 0; + border-right: 0; +} + +/* Chat Pause */ + +.ember-chat .chat-interface .more-messages-indicator.ffz-freeze-indicator { + opacity: 1; + cursor: default; + top: 0; +} + +/* Chat History */ + +.ember-chat .moderation-card .chat-history, +.chat-history { + list-style-type: none; + padding: 0; + max-height: 200px; + overflow-y: scroll; +} + +.chat-history.interface li:first-child { padding-top: 10px; } +.chat-history.interface li:last-child { padding-bottom: 10px; } + +.chat-history .chat-line { + line-height: 20px; + padding: 4px 10px; + word-wrap: break-word; + list-style-position: unset; +} + +.ember-chat .moderation-card .interface.chat-history .chat-line.action { + float: none; + margin-right: 0px; +} + +.chat-history .chat-line.admin .message { color: #666; } + +.chat-history .timestamp { + color: #8c8c8c; + margin-right: 5px; +} + +/* Room State */ + +.ffz.room-state.stat { + line-height: 30px; + margin-left: -10px; + margin-right: 15px; +} + +.ffz.room-state.truncated span { font-size: 8px; } + +.button.primary.ffz-waiting:not(:hover) { + background-color: rgba(0,0,0,0.1); + color: #32323e; +} + +.button.primary.ffz-waiting.ffz-banned:not(:hover) { + background-color: rgba(128,0,0,0.1); + color: #88323e; +} + +.chat-container.dark .button.primary.ffz-waiting:not(:hover), +.app-main.theatre .button-primary.ffz-waiting:not(:hover), +.chat-container.force-dark .button-primary.ffz-waiting:not(:hover), +.ember-chat-container.dark .button-primary.ffz-waiting:not(:hover), +.ember-chat-container.force-dark .button-primary.ffz-waiting:not(:hover) { + background-color: rgba(255,255,255,0.1); + color: #fff; +} + +.chat-container.dark .button.primary.ffz-waiting.ffz-banned:not(:hover), +.app-main.theatre .button-primary.ffz-waiting.ffz-banned:not(:hover), +.chat-container.force-dark .button-primary.ffz-waiting.ffz-banned:not(:hover), +.ember-chat-container.dark .button-primary.ffz-waiting.ffz-banned:not(:hover), +.ember-chat-container.force-dark .button-primary.ffz-waiting.ffz-banned:not(:hover) { + background-color: rgba(255,128,128,0.1); + color: #f66; +} + +/* Swap Sidebars */ + +body[data-current-path^="user."].ffz-portrait #right_close { transform: rotate(90deg); } +body[data-current-path^="user."].ffz-portrait .archives-contain .more-archives { width: 100%; } + +body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-interface .emoticon-selector, +.ffz-sidebar-swap:not(.ffz-portrait) .ember-chat .chat-interface .emoticon-selector { + right: auto; + left: 20px; +} + +.ffz-sidebar-swap #left_col { + left: auto; + right: 0; +} + +.ffz-sidebar-swap #right_col { + right: auto; + left: 0; +} + +.ffz-sidebar-swap:not(.ffz-portrait) #right_close, +.ffz-sidebar-swap #left_close { + transform: scaleX(-1); +} + +.ffz-sidebar-swap #right_close { + right: auto; + left: 5px; +} + +.ffz-sidebar-swap #left_close { + right: auto; + left: -25px; +} + +.ffz-sidebar-swap #main_col { + margin-left: 340px; + margin-right: 240px; +} + +.ffz-sidebar-swap .app-main.theatre #main_col { + margin-left: 340px; + margin-right: 0px; +} + +.ffz-sidebar-swap .app-main.theatre #main_col.expandRight { + margin-left: 0px; +} + + +.ffz-sidebar-swap .exit-theatre { + left: 30px; +} + +.ffz-sidebar-swap #main_col.expandLeft { + margin-right: 50px; +} + +.ffz-sidebar-swap #main_col.expandRight { + margin-left: 0px; +} + +.ffz-sidebar-swap #flyout { + left: auto !important; + right: 50px; +} + +.ffz-sidebar-swap #flyout .content { + right: 10px; +} + +.ffz-sidebar-swap #flyout .point { + left: auto; + right: -1px; +} + +.ffz-sidebar-swap #flyout .point:before { + border-left-color: #fff; + border-right-color: transparent; + right: auto; + left: 0px; +} + +.ffz-sidebar-swap #flyout .point:after { + border-right-color: transparent; + border-left-color: rgba(0,0,0,0.25); + right: auto; + left: 1px; +} + +.ffz-dark.ffz-sidebar-swap #flyout .point:after { + border-left-color: #32323e; + border-right-color: transparent; +} + +.ffz-dark.ffz-sidebar-swap #flyout .point:before { + border-left-color: #101010; + border-right-color: transparent; +} + +/* Badge Styles */ + +.ffz-rounded-badges .conversation-window .badges .badge:not(.subscriber), +.ffz-rounded-badges .ember-chat .badges .badge:not(.subscriber) { border-radius: 2px; } + +.ffz-circular-blank-badges .conversation-window .badges .badge:not(.subscriber), +.ffz-circular-small-badges .conversation-window .badges .badge:not(.subscriber), +.ffz-circular-badges .conversation-window .badges .badge:not(.subscriber), +.ffz-circular-blank-badges .ember-chat .badges .badge:not(.subscriber), +.ffz-circular-small-badges .ember-chat .badges .badge:not(.subscriber), +.ffz-circular-badges .ember-chat .badges .badge:not(.subscriber) { + border-radius: 9px; + background-size: 16px; + background-repeat: no-repeat; + background-position: center center; +} + +.ffz-circular-small-badges .conversation-window .badges .badge:not(.subscriber), +.ffz-circular-blank-badges .conversation-window .badges .badge:not(.subscriber), +.ffz-circular-small-badges .ember-chat .badges .badge:not(.subscriber), +.ffz-circular-blank-badges .ember-chat .badges .badge:not(.subscriber) { + background-size: 0px; +} + +.ffz-circular-small-badges .conversation-window .badges .badge:not(.subscriber), +.ffz-circular-small-badges .ember-chat .badges .badge:not(.subscriber) { + height: 10px; + min-width: 10px; + margin: 5px 3px 5px 0; +} + +.ffz-transparent-badges .conversation-window .badges .badge, +.ffz-transparent-badges .ember-chat .badges .badge { + background-color: transparent !important; +} + +.ffz-transparent-badges:not(.ffz-dark) .app-main:not(.theatre) .conversation-window .badges .badge:not(.ffz-badge-0):not(.subscriber), +.ffz-transparent-badges > .chat-container:not(.dark):not(.force-dark) .ember-chat .badges .badge:not(.ffz-badge-0):not(.subscriber), +.ffz-transparent-badges > .ember-chat-container:not(.dark):not(.force-dark) .ember-chat .badges .badge:not(.ffz-badge-0):not(.subscriber), +.ffz-transparent-badges .app-main:not(.theatre) .chat-container:not(.dark):not(.force-dark) .ember-chat .badges .badge:not(.ffz-badge-0):not(.subscriber), +.ffz-transparent-badges .app-main:not(.theatre) .ember-chat-container:not(.dark):not(.force-dark) .ember-chat .badges .badge:not(.ffz-badge-0):not(.subscriber) { + filter: invert(100%); + -webkit-filter: invert(100%); +} + +/* No Blue */ + +.ffz-no-blue .theatre .conversations-list-icon, +.ffz-no-blue.ffz-dark .conversations-list-icon, +.ffz-no-blue .theatre .conversations-list, +.ffz-no-blue.ffz-dark .conversations-list, +.ffz-no-blue .theatre .conversation-window, +.ffz-no-blue.ffz-dark .conversation-window, +.ffz-no-blue .theatre .conversations-list .conversations-list-header, +.ffz-no-blue.ffz-dark .conversations-list .conversations-list-header, + +.ffz-no-blue #large_nav .content, +.ffz-no-blue #small_nav .content, +.ffz-no-blue .chat-container.dark, +.ffz-no-blue .app-main.theatre .chat-container, +.ffz-no-blue .chat-container.force-dark, +.ffz-no-blue .ember-chat-container.dark, +.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container, +.ffz-no-blue .ember-chat-container.force-dark, +.ffz-no-blue .chat-container.dark .chat-hidden-overlay, +.ffz-no-blue .app-main.theatre .chat-container .chat-hidden-overlay, +.ffz-no-blue .chat-container.force-dark .chat-hidden-overlay, +.ffz-no-blue .ember-chat-container.dark .chat-hidden-overlay, +.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .chat-hidden-overlay, +.ffz-no-blue .ember-chat-container.force-dark .chat-hidden-overlay, +.ffz-no-blue .chat-container.dark .chatters-view, +.ffz-no-blue .app-main.theatre .chat-container .chatters-view, +.ffz-no-blue .chat-container.force-dark .chatters-view, +.ffz-no-blue .ember-chat-container.dark .chatters-view, +.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .chatters-view, +.ffz-no-blue .ember-chat-container.force-dark .chatters-view, +.ffz-no-blue .chat-container.dark .emoticon-selector .emoticon-selector-box, +.ffz-no-blue .app-main.theatre .chat-container .emoticon-selector .emoticon-selector-box, +.ffz-no-blue .chat-container.force-dark .emoticon-selector .emoticon-selector-box, +.ffz-no-blue .ember-chat-container.dark .emoticon-selector .emoticon-selector-box, +.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .emoticon-selector .emoticon-selector-box, +.ffz-no-blue .ember-chat-container.force-dark .emoticon-selector .emoticon-selector-box, +.ffz-no-blue .chat-container.dark .emoticon-selector .emoticon-grid, +.ffz-no-blue .app-main.theatre .chat-container .emoticon-selector .emoticon-grid, +.ffz-no-blue .chat-container.force-dark .emoticon-selector .emoticon-grid, +.ffz-no-blue .ember-chat-container.dark .emoticon-selector .emoticon-grid, +.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .emoticon-selector .emoticon-grid, +.ffz-no-blue .ember-chat-container.force-dark .emoticon-selector .emoticon-grid, +.ffz-no-blue .chat-container.dark .chat-commands-dropdown, +.ffz-no-blue .app-main.theatre .chat-container .chat-commands-dropdown, +.ffz-no-blue .chat-container.force-dark .chat-commands-dropdown, +.ffz-no-blue .ember-chat-container.dark .chat-commands-dropdown, +.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .chat-commands-dropdown, +.ffz-no-blue .ember-chat-container.force-dark .chat-commands-dropdown, +.ffz-no-blue .chat-container.dark .chat-commands-dropdown li, +.ffz-no-blue .app-main.theatre .chat-container .chat-commands-dropdown li, +.ffz-no-blue .chat-container.force-dark .chat-commands-dropdown li, +.ffz-no-blue .ember-chat-container.dark .chat-commands-dropdown li, +.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .chat-commands-dropdown li, +.ffz-no-blue .ember-chat-container.force-dark .chat-commands-dropdown li, +.ffz-no-blue.error_500, +.ffz-no-blue.error_400, +.ffz-no-blue .takeover #carousel, +.ffz-no-blue #carousel_and_background, +.ffz-no-blue #carousel .items .pic img, +.ffz-no-blue #content .turbo_landing { + background-color: #191919; +} + +.ffz-no-blue .chat-container.dark .chat-interface .emoticon-selector .tabs, +.ffz-no-blue .app-main.theatre .chat-container .chat-interface .emoticon-selector .tabs, +.ffz-no-blue .chat-container.force-dark .chat-interface .emoticon-selector .tabs, +.ffz-no-blue .ember-chat-container.dark .chat-interface .emoticon-selector .tabs, +.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .chat-interface .emoticon-selector .tabs, +.ffz-no-blue .ember-chat-container.force-dark .chat-interface .emoticon-selector .tabs { + background-color: #232323; +} + +.ffz-no-blue .theatre .conversations-list-icon, +.ffz-no-blue.ffz-dark .conversations-list-icon, +.ffz-no-blue .theatre .conversations-list .conversation-preview-line, +.ffz-no-blue.ffz-dark .conversations-list .conversation-preview-line, +.ffz-no-blue .theatre .conversation-window, +.ffz-no-blue.ffz-dark .conversation-window { + color: #8c8c8c; +} + +.ffz-no-blue .theatre .conversations-list, +.ffz-no-blue.ffz-dark .conversations-list { + border-color: #323232; +} + +.ffz-no-blue .theatre .converations-list:before, +.ffz-no-blue.ffz-dark .conversations-list:before { + border-color: transparent; + border-top-color: #323232; +} + +.ffz-no-blue .theatre .conversations-list:after, +.ffz-no-blue.ffz-dark .conversations-list:after { + border-color: transparent; + border-top-color: #191919; +} + +.ffz-no-blue .theatre .conversations-list .conversations-list-header, +.ffz-no-blue.ffz-dark .conversations-list .conversations-list-header, +.ffz-no-blue .theatre .conversations-list .conversations-list-item, +.ffz-no-blue.ffz-dark .conversations-list .conversations-list-item { + border-bottom-color: #323232; +} + +.ffz-no-blue .theatre .conversation-header, +.ffz-no-blue.ffz-dark .conversation-header, +.ffz-no-blue .theatre .conversation-window.has-focus .conversation-header, +.ffz-no-blue.ffz-dark .conversation-window.has-focus .conversation-header, +.ffz-no-blue .theatre .conversations-list .conversations-list-item:hover, +.ffz-no-blue.ffz-dark .conversations-list .conversations-list-item:hover { + background-color: #121212; +} + +/* Following Count */ + +li[data-name="following"] a { + position: relative; +} + +.ffz-follow-count:empty { display: none; } + +.ffz-follow-count { + display: inline-block; + border-radius: 2px; + text-align: center; + color: #fff; +} + +#header_following .ffz-follow-count { + margin: 0 5px; + padding: 0 5px; + line-height: 20px; + background-color: rgba(25,25,25,0.5); +} + +#large_nav .ffz-follow-count, +.ffz-dark #header_following .ffz-follow-count { + background-color: rgba(127,127,127,0.5); +} + +#large_nav .ffz-follow-count { + position: absolute; + right: 10px; + top: 8px; + + line-height: 14px; + padding: 2px 5px; +} + +#large_nav .game_filter.selected .ffz-follow-count { right: 13px; } + +#small_nav .ffz-follow-count { + position: absolute; + bottom: 2px; + right: 2px; + padding: 0 2px; + font-size: 10px; + background-color: #191919; + color: rgba(255,255,255,0.5); +} + +#small_nav .game_filter.selected a .ffz-follow-count, +#small_nav .content ul li a:hover .ffz-follow-count { + background-color: #101014; +} + +#small_nav .game_filter.selected .ffz-follow-count { right: 5px; } + +/* Legacy Badges */ + +.ffz-legacy-mod-badges .ember-chat .badges .moderator, +.ffz-legacy-badges .ember-chat .badges .moderator { + background-color: #068c10; + background-image: url('//cdn.frankerfacez.com/script/legacy-mod.png'); +} + +.ffz-legacy-badges .ember-chat .badges .staff { + background-color: #6441a5; + background-image: url('//cdn.frankerfacez.com/script/legacy-staff.png'); +} + +.ffz-legacy-badges .ember-chat .badges .broadcaster { + background-color: #000; + background-image: url('//cdn.frankerfacez.com/script/legacy-broadcaster.png'); +} + +.ffz-legacy-badges .ember-chat .badges .admin { + background-color: #ff0303; + background-image: url('//cdn.frankerfacez.com/script/legacy-admin.png'); +} + +.ffz-legacy-turbo-badges .ember-chat .badges .turbo, +.ffz-legacy-badges .ember-chat .badges .turbo { + background-color: #6441a3; + background-image: url('//cdn.frankerfacez.com/script/legacy-turbo.png'); +} + +/* High Contrast Chat */ + +.ffz-high-contrast-chat-text .chat-container, +.ffz-high-contrast-chat-text .ember-chat-container { + color: "#000"; +} + +.ffz-high-contrast-chat-bg .chat-container, +.ffz-high-contrast-chat-bg .ember-chat-container { + background-color: #fff; +} + +.ffz-high-contrast-chat-bold .ember-chat .chat-messages .chat-line .from, +.ffz-high-contrast-chat-bold .ember-chat .chat-messages .chat-line .colon, +.ffz-high-contrast-chat-bold .ember-chat .chat-messages .chat-line .message { + font-weight: bold; +} + +/*.ffz-high-contrast-chat .chat-line:before { + background-color: transparent !important; + border: none !important; +}*/ + +.ffz-high-contrast-chat-text .chat-container.dark, +.ffz-high-contrast-chat-text .chat-container.force-dark, +.ffz-high-contrast-chat-text .ember-chat-container.dark, +.ffz-high-contrast-chat-text .ember-chat-container.force-dark, +.ffz-high-contrast-chat-text .app-main.theatre .chat-container, +.ffz-high-contrast-chat-text.ffz-dark .ember-chat-container.dark .chat-line, +.ffz-high-contrast-chat-text.ffz-dark .chat-container.dark .chat-line { + color: #fff; +} + +.ffz-high-contrast-chat-bg .chat-container.dark, +.ffz-high-contrast-chat-bg .chat-container.force-dark, +.ffz-high-contrast-chat-bg .ember-chat-container.dark, +.ffz-high-contrast-chat-bg .ember-chat-container.force-dark, +.ffz-high-contrast-chat-bg .app-main.theatre .chat-container, +.ffz-high-contrast-chat-bg.ffz-dark .ember-chat-container.dark .chat-line, +.ffz-high-contrast-chat-bg.ffz-dark .chat-container.dark .chat-line { + background-color: #000; +} + + +/*.ffz-high-contrast-chat .chat-line .mentioned { + color: #fff !important; + background-color: #000 !important; +} + +.ffz-high-contrast-chat .chat-container.dark .chat-line .mentioned, +.ffz-high-contrast-chat .chat-container.force-dark .chat-line .mentioned, +.ffz-high-contrast-chat .ember-chat-container.dark .chat-line .mentioned, +.ffz-high-contrast-chat .ember-chat-container.force-dark .chat-line .mentioned, +.ffz-high-contrast-chat .app-main.theatre .chat-container .chat-line .mentioned, +.ffz-high-contrast-chat.ffz-dark .ember-chat-container.dark .chat-line .chat-line .mentioned, +.ffz-high-contrast-chat.ffz-dark .chat-container.dark .chat-line .chat-line .mentioned { + color: #000 !important; + background-color: #fff !important; +}*/ + +.ffz-image-hover { + border:none; + max-width: 186px; + max-height: 186px; + overflow: hidden; +} + +.emoticon.ffz-image-hover { + display: block; + margin: 5px auto; +} + +.ffz-yt-thumb { + max-height: 90px; +} + +/* Classic Player */ + +.ffz-classic-player .player .player-video { + position: absolute; + top: 0; bottom: 32px; + left: 0; right: 0; +} + +.ffz-classic-player .player.player-isvod .player-video { + bottom: 36px; +} + +.ffz-classic-player .player .player-controls-bottom { + opacity: 1; + + padding-top: 0; + border-top: 1px solid #000; + border-bottom: 1px solid #000; + + background: -webkit-linear-gradient(bottom, #252525, #666); + background: linear-gradient(to top, #252525, #666); +} + +.ffz-classic-player .app-main.theatre .player .player-video, +.ffz-classic-player .player[data-fullscreen="true"] .player-video { + bottom: 0; +} + +.ffz-classic-player .app-main.theatre .player .player-controls-bottom, +.ffz-classic-player .player[data-fullscreen="true"] .player-controls-bottom { + margin-bottom: -32px; + -webkit-transition: margin-bottom .2s ease-out, padding-bottom .2s ease-out; + transition: margin-bottom .2s ease-out, padding-bottom .2s ease-out; +} + +.ffz-classic-player:not(.ffz-top-conversations) .app-main.theatre .player .player-controls-bottom, +.ffz-classic-player .app-main.theatre .player[data-fullscreen="true"] .player-controls-bottom { + padding-bottom: 0; +} + +.ffz-classic-player .app-main.theatre .player.player-isvod .player-controls-bottom, +.ffz-classic-player .player.player-isvod[data-fullscreen="true"] .player-controls-bottom { + margin-bottom: -36px; +} + +.ffz-classic-player .app-main.theatre .player-column:hover .player .player-controls-bottom, +.ffz-classic-player .app-main.theatre .player-column:focus .player .player-controls-bottom, +.ffz-classic-player .player[data-fullscreen="true"][data-controls="true"] .player-controls-bottom { + margin-bottom: 0; +} + +.ffz-classic-player:not(.ffz-top-conversations) .app-main.theatre .player-column:hover .player[data-fullscreen="false"] .player-controls-bottom { + padding-bottom: 40px; +} + +.ffz-classic-player .player .player-button { + padding-bottom: 0; + height: 30px; +} + + +.ffz-classic-player .player .player-slider:before, +.ffz-classic-player .player .player-button, +.ffz-classic-player .player .player-slider .ui-slider-handle, +.ffz-classic-player .player .player-seek .player-seek__time { + -webkit-filter: drop-shadow(0px 0px 1px #000); + filter: drop-shadow(0px 0px 1px #000); +} + + +.ffz-classic-player .player .player-slider .ui-slider-handle { background-color: #aeaeae; } +.ffz-classic-player .player .player-button svg { fill: #aeaeae; } +.ffz-classic-player .player .player-seek .player-seek__time { color: #ddd; } + +.ffz-classic-player .player .player-volume__slider-container { + width: auto; +} + + +.ffz-classic-player .player .player-seek { + padding: 0; +} + +.ffz-classic-player .player .player-seek .player-slider { + margin: -1em 0; +} + +.ffz-classic-player .player .player-seek .player-seek__time-container { + position: absolute; + bottom: -12px; + left: 210px; +} + +.ffz-classic-player .player .player-seek .player-seek__time + .player-seek__time:before { + content: "/"; + padding: 0 5px; + opacity: 0.8; +} + +/* Directory Logos */ + +.ffz-directory-logo .meta p { width: auto; } + +.ffz-directory-logo .profile-photo { + float: left; + height: 46px; + width: 46px; + margin-right: 10px; +} + +.ffz-directory-logo .profile-photo.is-csgo { + margin-bottom: 20px; +} + +/* Flip Dashboard */ + +.ffz-flip-dashboard #dash_main #controls_column { + float: right; + margin-left: 20px; + margin-right: 0; +} + +.ffz-flip-dashboard #dash_main .dash-chat-column { + right: inherit; + left: 0; + margin-right: 20px; +} + +/* Conversations */ + +.conversation-preview-line .badges, +body.ffz-conv-title-clickable .conversation-header span.conversation-header-name, +body:not(.ffz-conv-title-clickable) .conversation-header a.conversation-header-name { display:none } + +.conversation-window.has-unread .conversation-header .conversation-header-name { color: #fff !important; } + +.ffz-top-conversations .conversation-window.collapsed .conversation-header, +.conversations-list .conversations-list-item:last-of-type { + border-bottom: none !important; +} + +.ffz-top-conversations .conversations-content .conversations-list-icon, +.ffz-top-conversations .conversation-window { + border-top: 0; + border-bottom: 1px solid #dedede; +} + +.ffz-top-conversations.ffz-dark .conversations-content .conversations-list-icon, +.ffz-top-conversations.ffz-dark .conversation-window, +.ffz-top-conversations .theatre .conversations-content .conversations-list-icon, +.ffz-top-conversations .theatre .conversation-window { + border-bottom-color: rgba(255,255,255,0.2); +} + +.ffz-top-conversations .conversations-content { + left: 30px; + right: 30px; +} + +.ffz-top-conversations .conversation-window, +.ffz-top-conversations .conversations-content { + bottom: inherit; + top: 0px; +} + +.ffz-top-conversations .conversations-list { + bottom: inherit; + top: 46px; +} + +.ffz-top-conversations .conversations-list:before, +.ffz-top-conversations .conversations-list:after { + display:none; +} + +.ffz-top-conversations .theatre .player-controls-bottom { + padding-bottom: 0; +} + +.ffz-top-conversations .theatre .player-livestatus { + top: 40px; +} + +.ffz-top-conversations #directory-list { padding-top: 50px; } + +/* Following Page */ + +.user.item { position: relative; } + +.user.item .overlay_info.length { + position: absolute; + top: 5px; + right: 25px; + z-index: 1; + + display: inline-block; + + padding: 0 5px; + font-size: 11px; + line-height: 22px; + + background: black; + color: #fff; + opacity: 0.75; +} + +.user.item .overlay_info.length svg { + float: left; + margin: 3px 5px 3px 0; +} + +.user.item .actions .follow svg path, +.user.item .overlay_info.length svg path { fill: #fff; } + +.user.item .actions { + margin-top: -15px; + margin-bottom: 20px; + margin-right: 20px; + display: flex; + flex-wrap: nowrap; +} + +.user.item .actions button { + display: block; + font-size: 11px; + text-align: center; + height: 25px; + line-height: 25px; +} + +.user:not(.followed) .actions .follow { width: 100%; } + +.user.item .actions .notifications { + flex-grow: 1; +} + +.user.item .actions button:hover, +.user.item .actions .notifications-on { + background-color: #6441A5; + color: #fff !important; +} + +.user.followed .actions .follow span, +.user.item:not(.followed) .actions .notifications, +.user:not(.followed) .actions .follow .svg-unheart, +.user.followed .actions .follow:not(:hover) .svg-unheart, +.user.followed .actions .follow:hover .svg-heart { display: none; } + +.user.followed .actions .follow { + float: left; + width: 25px; + margin-right: 5px; + background-color: #00b132; +} + +.user.followed .actions .follow:hover { + background-color: #d44949; +} + +.user.item .actions .follow svg { + margin: 4.5px 0 -4.5px -1px; +} \ No newline at end of file From 3958a37f385ede034da899a4a15ec2883d981f3f Mon Sep 17 00:00:00 2001 From: SirStendec Date: Wed, 11 Nov 2015 02:06:02 -0500 Subject: [PATCH 3/5] Big changes to how CSS works! Hopefully it'll improve performance. --- gulpfile.js | 34 +-- src/badges.js | 33 ++- src/colors.js | 4 +- src/ember/chatview.js | 179 +++++++----- src/ember/line.js | 107 ++----- src/ember/moderation-card.js | 7 +- src/ember/room.js | 36 +-- src/ext/betterttv.js | 29 +- src/main.js | 8 +- src/styles/badges-blank.css | 3 + src/styles/badges-circular-small.css | 5 + src/styles/badges-circular.css | 6 + src/styles/badges-legacy-mod.css | 4 + src/styles/badges-legacy-turbo.css | 4 + src/styles/badges-legacy.css | 14 + src/styles/badges-rounded.css | 4 + src/styles/badges-transparent.css | 12 + src/styles/chat-background.css | 96 ++++++ src/styles/chat-colors-gray.css | 4 + src/styles/chat-hc-background.css | 16 + src/styles/chat-hc-bold.css | 6 + src/styles/chat-hc-text.css | 15 + src/styles/chat-padding.css | 15 + src/styles/chat-separator-3d-inset.css | 19 ++ src/styles/chat-separator-3d.css | 17 ++ src/styles/chat-separator-wide.css | 17 ++ src/styles/chat-separator.css | 31 ++ src/styles/chat-setup.css | 18 ++ src/ui/styles.js | 22 +- style.css | 389 ++++--------------------- 30 files changed, 563 insertions(+), 591 deletions(-) create mode 100644 src/styles/badges-blank.css create mode 100644 src/styles/badges-circular-small.css create mode 100644 src/styles/badges-circular.css create mode 100644 src/styles/badges-legacy-mod.css create mode 100644 src/styles/badges-legacy-turbo.css create mode 100644 src/styles/badges-legacy.css create mode 100644 src/styles/badges-rounded.css create mode 100644 src/styles/badges-transparent.css create mode 100644 src/styles/chat-background.css create mode 100644 src/styles/chat-colors-gray.css create mode 100644 src/styles/chat-hc-background.css create mode 100644 src/styles/chat-hc-bold.css create mode 100644 src/styles/chat-hc-text.css create mode 100644 src/styles/chat-padding.css create mode 100644 src/styles/chat-separator-3d-inset.css create mode 100644 src/styles/chat-separator-3d.css create mode 100644 src/styles/chat-separator-wide.css create mode 100644 src/styles/chat-separator.css create mode 100644 src/styles/chat-setup.css diff --git a/gulpfile.js b/gulpfile.js index 411e6b64..97ff6c69 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -44,22 +44,22 @@ gulp.task('prepare', ['clean'], function() { }); -gulp.task('templates', ['prepare'], function() { - gulp.src(['build/templates/**/*.hbs']) - .pipe(jsEscape()) - .pipe(wrap('Handlebars.compile(<%= contents %>)')) - .pipe(declare({ - root: 'exports', - noRedeclare: true, - processName: function(filePath) { - var match = filePath.match(/build[\\\/]templates[\\\/](.*)\.hbs$/); - return declare.processNameByPath((match && match.length > 1) ? match[1] : filePath); - } - })) - .pipe(concat('templates.js')) - .pipe(gulp.dest('build/')) - .on('error', util.log); -}); +//gulp.task('templates', ['prepare'], function() { +// gulp.src(['build/templates/**/*.hbs']) +// .pipe(jsEscape()) +// .pipe(wrap('Handlebars.compile(<%= contents %>)')) +// .pipe(declare({ +// root: 'exports', +// noRedeclare: true, +// processName: function(filePath) { +// var match = filePath.match(/build[\\\/]templates[\\\/](.*)\.hbs$/); +// return declare.processNameByPath((match && match.length > 1) ? match[1] : filePath); +// } +// })) +// .pipe(concat('templates.js')) +// .pipe(gulp.dest('build/')) +// .on('error', util.log); +//}); gulp.task('styles', ['prepare'], function() { @@ -80,7 +80,7 @@ gulp.task('styles', ['prepare'], function() { }); -gulp.task('scripts', ['prepare', 'templates', 'styles'], function() { +gulp.task('scripts', ['prepare', 'styles'], function() { gulp.src(['build/main.js']) .pipe(browserify()) .pipe(concat('script.js')) diff --git a/src/badges.js b/src/badges.js index c4ce8098..8069db51 100644 --- a/src/badges.js +++ b/src/badges.js @@ -43,9 +43,9 @@ FFZ.settings_info.legacy_badges = { }, on_update: function(val) { - document.body.classList.toggle("ffz-legacy-mod-badges", val !== 0); - document.body.classList.toggle("ffz-legacy-turbo-badges", val > 1); - document.body.classList.toggle("ffz-legacy-badges", val === 3); + this.toggle_style('badges-legacy', val === 3); + this.toggle_style('badges-legacy-mod', val !== 0); + this.toggle_style('badges-legacy-turbo', val > 1); } }; @@ -83,11 +83,11 @@ FFZ.settings_info.transparent_badges = { if ( this.has_bttv ) return; - document.body.classList.toggle("ffz-rounded-badges", val === 1); - document.body.classList.toggle("ffz-circular-badges", val === 2); - document.body.classList.toggle("ffz-circular-blank-badges", val === 3); - document.body.classList.toggle("ffz-circular-small-badges", val === 4); - document.body.classList.toggle("ffz-transparent-badges", val === 5); + this.toggle_style('badges-rounded', val === 1); + this.toggle_style('badges-circular', val === 2 || val === 3 || val === 4); + this.toggle_style('badges-blank', val === 3 || val === 4); + this.toggle_style('badges-circular-small', val === 4); + this.toggle_style('badges-transparent', val === 5); } }; @@ -98,16 +98,17 @@ FFZ.settings_info.transparent_badges = { FFZ.prototype.setup_badges = function() { if ( ! this.has_bttv ) { - document.body.classList.toggle("ffz-rounded-badges", this.settings.transparent_badges === 1); - document.body.classList.toggle("ffz-circular-badges", this.settings.transparent_badges === 2); - document.body.classList.toggle("ffz-circular-blank-badges", this.settings.transparent_badges === 3); - document.body.classList.toggle("ffz-circular-small-badges", this.settings.transparent_badges === 4); - document.body.classList.toggle("ffz-transparent-badges", this.settings.transparent_badges === 5); + var val = this.settings.transparent_badges; + this.toggle_style('badges-rounded', val === 1); + this.toggle_style('badges-circular', val === 2 || val === 3 || val === 4); + this.toggle_style('badges-blank', val === 3 || val === 4); + this.toggle_style('badges-circular-small', val === 4); + this.toggle_style('badges-transparent', val === 5); } - document.body.classList.toggle("ffz-legacy-mod-badges", this.settings.legacy_badges !== 0); - document.body.classList.toggle("ffz-legacy-turbo-badges", this.settings.legacy_badges > 1); - document.body.classList.toggle("ffz-legacy-badges", this.settings.legacy_badges === 3); + this.toggle_style('badges-legacy', this.settings.legacy_badges === 3); + this.toggle_style('badges-legacy-mod', this.settings.legacy_badges !== 0); + this.toggle_style('badges-legacy-turbo', this.settings.legacy_badges > 1); this.log("Preparing badge system."); this.badges = {}; diff --git a/src/colors.js b/src/colors.js index a0d09ad4..e05ece22 100644 --- a/src/colors.js +++ b/src/colors.js @@ -45,7 +45,7 @@ FFZ.settings_info.fix_color = { }, on_update: function(val) { - document.body.classList.toggle("ffz-chat-colors-gray", !this.has_bttv && (val === '-1')); + this.toggle_style('chat-colors-gray', !this.has_bttv && val === '-1'); if ( ! this.has_bttv && val !== '-1' ) this._rebuild_colors(); @@ -114,6 +114,8 @@ FFZ.settings_info.color_blind = { // -------------------- FFZ.prototype.setup_colors = function() { + this.toggle_style('chat-colors-gray', !this.has_bttv && this.settings.fix_color === '-1'); + this._colors = {}; this._rebuild_contrast(); diff --git a/src/ember/chatview.js b/src/ember/chatview.js index 6bcaadfd..4170960e 100644 --- a/src/ember/chatview.js +++ b/src/ember/chatview.js @@ -280,20 +280,6 @@ FFZ.settings_info.group_tabs = { }; -FFZ.settings_info.top_conversations = { - type: "boolean", - value: false, - no_mobile: true, - - category: "Chat Appearance", - name: "Conversations on Top", - help: "Display the new conversation-style whisper UI at the top of the window instead of the bottom.", - on_update: function(val) { - document.body.classList.toggle('ffz-top-conversations', val); - } - }; - - FFZ.settings_info.pinned_rooms = { value: [], visible: false, @@ -312,7 +298,6 @@ FFZ.settings_info.visible_rooms = { FFZ.prototype.setup_chatview = function() { document.body.classList.toggle("ffz-minimal-chat-head", this.settings.minimal_chat === 1 || this.settings.minimal_chat === 3); document.body.classList.toggle("ffz-minimal-chat-input", this.settings.minimal_chat === 2 || this.settings.minimal_chat === 3); - document.body.classList.toggle('ffz-top-conversations', this.settings.top_conversations); this.log("Hooking the Ember Chat controller."); @@ -430,7 +415,7 @@ FFZ.prototype._modify_cview = function(view) { ffzInit: function() { f._chatv = this; this.$('.textarea-contain').append(f.build_ui_link(this)); - this.$('.chat-messages').find('.html-tooltip').tipsy({live: true, html: true, gravity: jQuery.fn.tipsy.autoNS}); + this.$('.chat-messages').find('.html-tooltip').tipsy({live: true, html: true, gravity: jQuery.fn.tipsy.autoNS}); if ( !f.has_bttv && f.settings.group_tabs ) this.ffzEnableTabs(); @@ -462,23 +447,32 @@ FFZ.prototype._modify_cview = function(view) { var room = this.get('controller.currentRoom'), rows; room && room.resetUnreadCount(); + if ( room._ffz_was_unread ) { + room._ffz_was_unread = false; + + var el = this.get('element'), + unread_display = el && el.querySelector('#ffz-group-tabs .button .notifications'), + unread_count = unread_display ? parseInt(unread_display.textContent) : 0; + + unread_count--; + if ( unread_display ) + unread_display.textContent = unread_count || ''; + } + if ( this._ffz_chan_table ) { rows = jQuery(this._ffz_chan_table); rows.children('.ffz-room-row').removeClass('active'); - if ( room ) - rows.children('.ffz-room-row[data-room="' + room.get('id') + '"]').addClass('active').children('span').text(''); } if ( this._ffz_group_table ) { rows = jQuery(this._ffz_group_table); rows.children('.ffz-room-row').removeClass('active'); - if ( room ) - rows.children('.ffz-room-row[data-room="' + room.get('id') + '"]').addClass('active').children('span').text(''); } if ( !f.has_bttv && f.settings.group_tabs && this._ffz_tabs ) { var tabs = jQuery(this._ffz_tabs); tabs.children('.ffz-chat-tab').removeClass('active'); + if ( room && room._ffz_tab ) { room._ffz_tab.classList.remove('tab-mentioned'); room._ffz_tab.classList.remove('hidden'); @@ -488,6 +482,15 @@ FFZ.prototype._modify_cview = function(view) { sp.innerHTML = ''; } + if ( room && room._ffz_row ) { + room._ffz_row.classList.remove('row-mentioned'); + room._ffz_row.classList.remove('hidden'); + room._ffz_row.classList.add('active'); + var sp = room._ffz_row.querySelector('span'); + if ( sp ) + sp.innerHTML = ''; + } + // Invite Link var can_invite = room && room.get('canInvite'); this._ffz_invite && this._ffz_invite.classList.toggle('hidden', !can_invite); @@ -501,9 +504,7 @@ FFZ.prototype._modify_cview = function(view) { // Better Menu ffzRebuildMenu: function() { - return; - - var el = this.get('element'), + /*var el = this.get('element'), room_list = el && el.querySelector('.chat-rooms .tse-content'); if ( ! room_list ) @@ -533,7 +534,7 @@ FFZ.prototype._modify_cview = function(view) { tbl.setAttribute('cellspacing', 0); tbl.id = 'ffz-channel-table'; tbl.className = 'ffz'; - tbl.innerHTML = 'ChannelsJoinPin'; + tbl.innerHTML = 'ChannelsPin'; room_list.insertBefore(tbl, room_list.firstChild); chan_table = this._ffz_chan_table = tbl.querySelector('tbody'); @@ -571,7 +572,7 @@ FFZ.prototype._modify_cview = function(view) { tbl.setAttribute('cellspacing', 0); tbl.id = 'ffz-group-table'; tbl.className = 'ffz'; - tbl.innerHTML = 'Group ChatsPin'; + tbl.innerHTML = 'Group Chats'; var before = room_list.querySelector('#ffz-channel-table'); room_list.insertBefore(tbl, before.nextSibling); @@ -590,30 +591,29 @@ FFZ.prototype._modify_cview = function(view) { // Change Create Tooltip var create_btn = el.querySelector('.button.create'); if ( create_btn ) - create_btn.title = 'Create a Group Room'; + create_btn.title = 'Create a Group Room';*/ }, - ffzBuildRow: function(view, room, current_channel, host_channel) { + /*ffzBuildRow: function(view, room, current_channel, host_channel) { var row = document.createElement('tr'), icon = document.createElement('td'), name_el = document.createElement('td'), btn, toggle_pinned = document.createElement('td'), - toggle_visible = document.createElement('td'), group = room.get('isGroupRoom'), current = room === view.get('controller.currentRoom'), - //unread = format_unread(current ? 0 : room.get('unreadCount')), + unread = utils.format_unread(current ? 0 : room.get('unreadCount')), name = room.get('tmiRoom.displayName') || (group ? room.get('tmiRoom.name') : FFZ.get_capitalization(room.get('id'), function(name) { f.log("Name for Row: " + name); - //unread = format_unread(current ? 0 : room.get('unreadCount')); - name_el.innerHTML = utils.sanitize(name); + unread = utils.format_unread(current ? 0 : room.get('unreadCount')); + name_el.innerHTML = utils.sanitize(name) + ' ' + unread + ''; })); name_el.className = 'ffz-room'; - name_el.innerHTML = utils.sanitize(name); + name_el.innerHTML = utils.sanitize(name) + ' ' + unread + ''; if ( current_channel ) { icon.innerHTML = constants.CAMERA; @@ -625,10 +625,9 @@ FFZ.prototype._modify_cview = function(view) { icon.className = name_el.className = 'tooltip'; } - toggle_pinned.className = toggle_visible.className = 'ffz-row-switch'; + toggle_pinned.className = 'ffz-row-switch'; toggle_pinned.innerHTML = ''; - toggle_visible.innerHTML = ''; row.setAttribute('data-room', room.get('id')); @@ -677,34 +676,16 @@ FFZ.prototype._modify_cview = function(view) { }); } - row.appendChild(toggle_visible); - btn = toggle_visible.querySelector('a.switch'); - btn.addEventListener('click', function(e) { - e.preventDefault(); - e.stopPropagation && e.stopPropagation(); - - var room_id = room.get('id'), - visible_rooms = f.settings.visible_rooms, - is_visible = visible_rooms.indexOf(room_id) !== -1; - - if ( is_visible ) - visible_rooms.removeObject(room_id); - else - visible_rooms.push(room_id); - - f.settings.set('visible_rooms', visible_rooms); - this.classList.toggle('active', !is_visible); - view.ffzRebuildTabs(); - }); - row.addEventListener('click', function() { var controller = view.get('controller'); controller.focusRoom(room); controller.set('showList', false); }); + + room._ffz_row = row; return row; - }, + },*/ // Group Tabs~! @@ -735,11 +716,23 @@ FFZ.prototype._modify_cview = function(view) { tabs.innerHTML = ""; var link = document.createElement('a'), - view = this; + view = this, + total_unread = 0; + + for(var room_id in f.rooms) { + var room = f.rooms[room_id] && f.rooms[room_id].room, + is_unread = room && room.get('unreadCount') > 0; + + if ( is_unread ) { + room._ffz_was_unread = true; + total_unread++; + } else if ( room ) + room._ffz_was_unread = false; + } link.className = 'button glyph-only tooltip'; link.title = "Chat Room Management"; - link.innerHTML = constants.ROOMS; + link.innerHTML = constants.ROOMS + '' + (total_unread || '') + ''; link.addEventListener('click', function() { var controller = view.get('controller'); @@ -821,38 +814,64 @@ FFZ.prototype._modify_cview = function(view) { }, ffzTabUnread: function(room_id) { - // TODO: Update menu. - - if ( f.has_bttv || ! f.settings.group_tabs ) - return; - - var tabs = this._ffz_tabs || this.get('element').querySelector('#ffz-group-tabs'), - current_id = this.get('controller.currentRoom.id'); - - if ( ! tabs ) - return; + var current_id = this.get('controller.currentRoom.id'); if ( room_id ) { var room = f.rooms && f.rooms[room_id] && f.rooms[room_id].room, - tab = room && room._ffz_tab; + row = room && room._ffz_row, + tab = room && room._ffz_tab, - if ( tab ) { - var unread = utils.format_unread(room_id === current_id ? 0 : room.get('unreadCount')); - tab.querySelector('span').innerHTML = unread; + unread_count = room_id === current_id ? 0 : room.get('unreadCount'), + is_unread = unread_count > 0, + unread = utils.format_unread(unread_count); + + if ( ! room._ffz_was_unread && is_unread ) { + room._ffz_was_unread = true; + + var el = this.get('element'), + unread_display = el && el.querySelector('#ffz-group-tabs .button .notifications'), + unread_count = unread_display ? parseInt(unread_display.textContent) : 0; + + unread_count++; + if ( unread_display ) + unread_display.textContent = unread_count || ''; } + + if ( row ) + row.querySelector('span').innerHTML = unread; + + if ( tab ) + tab.querySelector('span').innerHTML = unread; + + return; } - var children = tabs.querySelectorAll('.ffz-chat-tab'); - for(var i=0; i < children.length; i++) { - var tab = children[i], - room_id = tab.getAttribute('data-room'), - room = f.rooms && f.rooms[room_id] && f.rooms[room_id]; + for(var room_id in f.rooms) { + var room = f.rooms[room_id] && f.rooms[room_id].room, + row = room && room._ffz_row, + tab = room && room._ffz_tab, - if ( ! room ) - continue; + unread_count = room_id === current_id ? 0 : room.get('unreadCount'), + is_unread = unread_count > 0, + unread = utils.format_unread(unread_count); - var unread = utils.format_unread(room_id === current_id ? 0 : room.room.get('unreadCount')); - tab.querySelector('span').innerHTML = unread; + if ( ! room._ffz_was_unread && is_unread ) { + room._ffz_was_unread = true; + + var el = this.get('element'), + unread_display = el && el.querySelector('#ffz-group-tabs .button .notifications'), + unread_count = unread_display ? parseInt(unread_display.textContent) : 0; + + unread_count++; + if ( unread_display ) + unread_display.textContent = unread_count || ''; + } + + if ( row ) + row.querySelector('span').innerHTML = unread; + + if ( tab ) + tab.querySelector('span').innerHTML = unread; } }, diff --git a/src/ember/line.js b/src/ember/line.js index 699618c9..b2e7b53a 100644 --- a/src/ember/line.js +++ b/src/ember/line.js @@ -269,7 +269,10 @@ FFZ.settings_info.chat_rows = { name: "Chat Line Backgrounds", help: "Display alternating background colors for lines in chat.", - on_update: function(val) { document.body.classList.toggle("ffz-chat-background", !this.has_bttv && val); } + on_update: function(val) { + this.toggle_style('chat-background', !this.has_bttv && val); + this.toggle_style('chat-setup', !this.has_bttv && (val || this.settings.chat_separators)); + } }; @@ -301,10 +304,12 @@ FFZ.settings_info.chat_separators = { help: "Display thin lines between chat messages for further visual separation.", on_update: function(val) { - document.body.classList.toggle("ffz-chat-separator", !this.has_bttv && val !== 0); - document.body.classList.toggle("ffz-chat-separator-3d", !this.has_bttv && val === 2); - document.body.classList.toggle("ffz-chat-separator-3d-inset", !this.has_bttv && val === 3); - document.body.classList.toggle("ffz-chat-separator-wide", !this.has_bttv && val === 4); + this.toggle_style('chat-setup', !this.has_bttv && (val || this.settings.chat_rows)); + + this.toggle_style('chat-separator', !this.has_bttv && val); + this.toggle_style('chat-separator-3d', !this.has_bttv && val === 2); + this.toggle_style('chat-separator-3d-inset', !this.has_bttv && val === 3); + this.toggle_style('chat-separator-wide', !this.has_bttv && val === 4); } }; @@ -319,7 +324,7 @@ FFZ.settings_info.chat_padding = { name: "Reduced Chat Line Padding", help: "Reduce the amount of padding around chat messages to fit more on-screen at once.", - on_update: function(val) { document.body.classList.toggle("ffz-chat-padding", !this.has_bttv && val); } + on_update: function(val) { this.toggle_style('chat-padding', !this.has_bttv && val); } }; @@ -352,9 +357,9 @@ FFZ.settings_info.high_contrast_chat = { }, on_update: function(val) { - document.body.classList.toggle("ffz-high-contrast-chat-text", !this.has_bttv && val[2] === '1'); - document.body.classList.toggle("ffz-high-contrast-chat-bold", !this.has_bttv && val[1] === '1'); - document.body.classList.toggle("ffz-high-contrast-chat-bg", !this.has_bttv && val[0] === '1'); + this.toggle_style('chat-hc-text', !this.has_bttv && val[2] === '1'); + this.toggle_style('chat-hc-bold', !this.has_bttv && val[1] === '1'); + this.toggle_style('chat-hc-background', !this.has_bttv && val[0] === '1'); } }; @@ -526,19 +531,19 @@ FFZ.prototype.setup_line = function() { // Chat Enhancements - document.body.classList.toggle("ffz-chat-colors", !this.has_bttv && this.settings.fix_color !== '-1'); - document.body.classList.toggle("ffz-chat-colors-gray", !this.has_bttv && this.settings.fix_color === '-1'); + this.toggle_style('chat-setup', !this.has_bttv && (this.settings.chat_rows || this.settings.chat_separators)); + this.toggle_style('chat-padding', !this.has_bttv && this.settings.chat_padding); - document.body.classList.toggle('ffz-chat-background', !this.has_bttv && this.settings.chat_rows); - document.body.classList.toggle("ffz-chat-separator", !this.has_bttv && this.settings.chat_separators !== 0); - document.body.classList.toggle("ffz-chat-separator-wide", !this.has_bttv && this.settings.chat_separators === 4); - document.body.classList.toggle("ffz-chat-separator-3d", !this.has_bttv && this.settings.chat_separators === 2); - document.body.classList.toggle("ffz-chat-separator-3d-inset", !this.has_bttv && this.settings.chat_separators === 3); - document.body.classList.toggle("ffz-chat-padding", !this.has_bttv && this.settings.chat_padding); + this.toggle_style('chat-background', !this.has_bttv && this.settings.chat_rows); - document.body.classList.toggle("ffz-high-contrast-chat-text", !this.has_bttv && this.settings.high_contrast_chat[2] === '1'); - document.body.classList.toggle("ffz-high-contrast-chat-bold", !this.has_bttv && this.settings.high_contrast_chat[1] === '1'); - document.body.classList.toggle("ffz-high-contrast-chat-bg", !this.has_bttv && this.settings.high_contrast_chat[0] === '1'); + this.toggle_style('chat-separator', !this.has_bttv && this.settings.chat_separators); + this.toggle_style('chat-separator-3d', !this.has_bttv && this.settings.chat_separators === 2); + this.toggle_style('chat-separator-3d-inset', !this.has_bttv && this.settings.chat_separators === 3); + this.toggle_style('chat-separator-wide', !this.has_bttv && this.settings.chat_separators === 4); + + this.toggle_style('chat-hc-text', !this.has_bttv && this.settings.high_contrast_chat[2] === '1'); + this.toggle_style('chat-hc-bold', !this.has_bttv && this.settings.high_contrast_chat[1] === '1'); + this.toggle_style('chat-hc-background', !this.has_bttv && this.settings.high_contrast_chat[0] === '1'); this._last_row = {}; @@ -567,67 +572,6 @@ FFZ.prototype.save_aliases = function() { } -FFZ.prototype._modify_conversation_line = function(component) { - var f = this, - - Layout = App.__container__.lookup('controller:layout'), - Settings = App.__container__.lookup('controller:settings'); - - component.reopen({ - tokenizedMessage: function() { - try { - return f.tokenize_conversation_line(this.get('message')); - } catch(err) { - f.error("convo-line tokenizedMessage: " + err); - return this._super(); - } - - }.property("message", "currentUsername"), - - click: function(e) { - if ( e.target && e.target.classList.contains('deleted-link') ) - return f._deleted_link_click.bind(e.target)(e); - - if ( f._click_emote(e.target, e) ) - return; - - return this._super(e); - }, - - render: function(e) { - var user = this.get('message.from.username'), - raw_color = this.get('message.from.color'), - colors = raw_color && f._handle_color(raw_color), - - is_dark = (Layout && Layout.get('isTheatreMode')) || f.settings.dark_twitch; - - e.push('
'); - - var alias = f.aliases[user], - name = this.get('message.from.displayName') || (user && user.capitalize()) || "unknown user", - style = colors && 'color:' + (is_dark ? colors[1] : colors[0]), - colored = style ? ' has-color' : ''; - - if ( alias ) - e.push('' + utils.sanitize(alias) + ''); - else - e.push('' + utils.sanitize(name) + ''); - - e.push(': '); - - if ( ! this.get('isActionMessage') ) { - style = ''; - colored = ''; - } - - e.push(''); - e.push(f.render_tokens(this.get('tokenizedMessage'), true)); - e.push(''); - } - }); -} - - FFZ.prototype._modify_line = function(component) { var f = this, @@ -840,7 +784,6 @@ FFZ.prototype._modify_line = function(component) { }, classNameBindings: [ - 'msgObject.ffz_alternate:ffz-alternate', 'msgObject.ffz_has_mention:ffz-mentioned', 'ffzWasDeleted:ffz-deleted', 'ffzHasOldMessages:clearfix', diff --git a/src/ember/moderation-card.js b/src/ember/moderation-card.js index d8dc6cd4..83929d55 100644 --- a/src/ember/moderation-card.js +++ b/src/ember/moderation-card.js @@ -728,8 +728,7 @@ FFZ.prototype.setup_mod_card = function() { user_history = ffz_room && ffz_room.user_history && ffz_room.user_history[controller.get('cardInfo.user.id')]; if ( user_history && user_history.length ) { - var history = document.createElement('ul'), - alternate = false; + var history = document.createElement('ul'); history.className = 'interface clearfix chat-history'; for(var i=0; i < user_history.length; i++) { @@ -737,8 +736,6 @@ FFZ.prototype.setup_mod_card = function() { l_el = document.createElement('li'); l_el.className = 'message-line chat-line clearfix'; - l_el.classList.toggle('ffz-alternate', alternate); - alternate = !alternate; if ( line.style ) l_el.classList.add(line.style); @@ -756,8 +753,6 @@ FFZ.prototype.setup_mod_card = function() { el.appendChild(history); - this.ffz_alternate = alternate; - // Lazy scroll-to-bottom history.scrollTop = history.scrollHeight; } diff --git a/src/ember/room.js b/src/ember/room.js index 4c3c30ef..079a9c97 100644 --- a/src/ember/room.js +++ b/src/ember/room.js @@ -115,8 +115,6 @@ FFZ.prototype.setup_room = function() { FFZ.prototype._modify_rview = function(view) { var f = this; view.reopen({ - alternate: false, - didInsertElement: function() { this._super(); @@ -136,10 +134,6 @@ FFZ.prototype._modify_rview = function(view) { this._super(); }, - ffzUpdateAlternate: function() { - this.get('element').classList.toggle('ffz-alternate', this.get('ffzAlternate')); - }.observes("ffzAlternate"), - ffzInit: function() { f._roomv = this; @@ -743,11 +737,7 @@ FFZ.prototype._insert_history = function(room_id, data) { age = (now - last_date) / 1000, is_old = age > 300, - i = data.length, - alternation = r.get('messages.0.ffz_alternate') || false; - - if ( is_old ) - alternation = ! alternation; + i = data.length; var i = data.length; while(i--) { @@ -760,7 +750,6 @@ FFZ.prototype._insert_history = function(room_id, data) { if ( typeof msg.date === "string" || typeof msg.date === "number" ) msg.date = utils.parse_date(msg.date); - msg.ffz_alternate = alternation = ! alternation; if ( ! msg.room ) msg.room = room_id; @@ -828,7 +817,6 @@ FFZ.prototype._insert_history = function(room_id, data) { if ( is_old ) { var msg = { - ffz_alternate: ! alternation, color: "#755000", date: new Date(), from: "frankerfacez_admin", @@ -1007,8 +995,7 @@ FFZ.prototype._modify_room = function(room) { var msgs = t.get('messages'), total = msgs.get('length'), - i = total, - alternate; + i = total; // Delete visible messages while(i--) { @@ -1016,8 +1003,6 @@ FFZ.prototype._modify_room = function(room) { if ( msg.from === user ) { if ( f.settings.remove_deleted ) { - if ( alternate === undefined ) - alternate = ! msg.ffz_alternate; msgs.removeAt(i); continue; } @@ -1026,13 +1011,6 @@ FFZ.prototype._modify_room = function(room) { if ( ! f.settings.prevent_clear ) t.set('messages.' + i + '.deleted', true); } - - if ( alternate === undefined ) - alternate = msg.ffz_alternate; - else { - alternate = ! alternate; - t.set('messages.' + i + '.ffz_alternate', alternate); - } } // Delete pending messages @@ -1108,13 +1086,6 @@ FFZ.prototype._modify_room = function(room) { ffzActualPushMessage: function (msg) { if ( this.shouldShowMessage(msg) && this.ffzShouldShowMessage(msg) ) { - var row_type = msg.ffz_alternate; - if ( row_type === undefined ) { - var room_id = this.get('id'); - row_type = f._last_row[room_id] = f._last_row.hasOwnProperty(room_id) ? !f._last_row[room_id] : false; - msg.ffz_alternate = row_type; - } - this.get("messages").pushObject(msg); this.trimMessages(); @@ -1233,9 +1204,6 @@ FFZ.prototype._modify_room = function(room) { var l_el = document.createElement('li'); l_el.className = 'message-line chat-line clearfix'; - l_el.classList.toggle('ffz-alternate', f._mod_card.ffz_alternate); - f._mod_card.ffz_alternate = !f._mod_card.ffz_alternate; - if ( msg.style ) l_el.classList.add(msg.style); diff --git a/src/ext/betterttv.js b/src/ext/betterttv.js index 84d5d8af..8ea6a260 100644 --- a/src/ext/betterttv.js +++ b/src/ext/betterttv.js @@ -59,22 +59,27 @@ FFZ.prototype.setup_bttv = function(delay) { this._roomv.ffzUpdateStatus(); } + // Disable style blocks. + this.toggle_style('chat-setup'); + this.toggle_style('chat-padding'); + this.toggle_style('chat-background'); + + this.toggle_style('chat-separator'); + this.toggle_style('chat-separator-3d'); + this.toggle_style('chat-separator-3d-inset'); + this.toggle_style('chat-separator-wide'); + + this.toggle_style('chat-hc-text'); + this.toggle_style('chat-hc-bold'); + this.toggle_style('chat-hc-background'); + + this.toggle_style('chat-colors-gray'); + this.toggle_style('badges-transparent'); + // Disable other features too. - document.body.classList.remove("ffz-chat-colors"); - document.body.classList.remove("ffz-chat-colors-gray"); - document.body.classList.remove("ffz-chat-background"); - document.body.classList.remove("ffz-chat-padding"); - document.body.classList.remove("ffz-chat-separator"); - document.body.classList.remove("ffz-chat-separator-3d"); - document.body.classList.remove("ffz-chat-separator-wide"); - document.body.classList.remove("ffz-chat-separator-3d-inset"); document.body.classList.remove("ffz-sidebar-swap"); document.body.classList.remove("ffz-portrait"); document.body.classList.remove("ffz-flip-dashboard"); - document.body.classList.remove("ffz-transparent-badges"); - document.body.classList.remove("ffz-high-contrast-chat-text"); - document.body.classList.remove("ffz-high-contrast-chat-bg"); - document.body.classList.remove("ffz-high-contrast-chat-bold"); // Remove Following Count if ( this.settings.following_count ) { diff --git a/src/main.js b/src/main.js index 3609f2f6..2459a354 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: 5, revision: 62, + major: 3, minor: 5, revision: 63, toString: function() { return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); } @@ -243,6 +243,7 @@ FFZ.prototype.init_normal = function(delay, no_socket) { // Start this early, for quick loading. this.setup_dark(); + this.setup_css(); if ( ! no_socket ) this.ws_create(); @@ -253,7 +254,6 @@ FFZ.prototype.init_normal = function(delay, no_socket) { this.setup_notifications(); this.setup_following_count(false); - this.setup_css(); this.setup_menu(); this.find_bttv(10); @@ -280,6 +280,7 @@ FFZ.prototype.init_dashboard = function(delay) { // Start this early, for quick loading. this.setup_dark(); + this.setup_css(); this.ws_create(); this.setup_colors(); @@ -289,7 +290,6 @@ FFZ.prototype.init_dashboard = function(delay) { this.setup_tokenization(); this.setup_notifications(); this.setup_following_count(false); - this.setup_css(); this.setup_menu(); this._update_subscribers(); @@ -321,6 +321,7 @@ FFZ.prototype.init_ember = function(delay) { // Start this early, for quick loading. this.setup_dark(); + this.setup_css(); this.ws_create(); this.setup_emoticons(); @@ -347,7 +348,6 @@ FFZ.prototype.init_ember = function(delay) { //this.setup_teams(); this.setup_notifications(); - this.setup_css(); this.setup_menu(); this.setup_my_emotes(); this.setup_following(); diff --git a/src/styles/badges-blank.css b/src/styles/badges-blank.css new file mode 100644 index 00000000..1709f1a8 --- /dev/null +++ b/src/styles/badges-blank.css @@ -0,0 +1,3 @@ +.badges .badge:not(.subscriber) { + background-size: 0px; +} \ No newline at end of file diff --git a/src/styles/badges-circular-small.css b/src/styles/badges-circular-small.css new file mode 100644 index 00000000..ec67a3f5 --- /dev/null +++ b/src/styles/badges-circular-small.css @@ -0,0 +1,5 @@ +.badges .badge:not(.subscriber) { + height: 10px; + min-width: 10px; + margin: 5px 3px 5px 0; +} \ No newline at end of file diff --git a/src/styles/badges-circular.css b/src/styles/badges-circular.css new file mode 100644 index 00000000..0cbc892c --- /dev/null +++ b/src/styles/badges-circular.css @@ -0,0 +1,6 @@ +.badges .badge:not(.subscriber) { + border-radius: 9px; + background-size: 16px; + background-repeat: no-repeat; + background-position: center; +} \ No newline at end of file diff --git a/src/styles/badges-legacy-mod.css b/src/styles/badges-legacy-mod.css new file mode 100644 index 00000000..fbf3de28 --- /dev/null +++ b/src/styles/badges-legacy-mod.css @@ -0,0 +1,4 @@ +.badges .moderator { + background-color: #068c10; + background-image: url('//cdn.frankerfacez.com/script/legacy-mod.png'); +} \ No newline at end of file diff --git a/src/styles/badges-legacy-turbo.css b/src/styles/badges-legacy-turbo.css new file mode 100644 index 00000000..ba684d64 --- /dev/null +++ b/src/styles/badges-legacy-turbo.css @@ -0,0 +1,4 @@ +.badges .turbo { + background-color: #6441a3; + background-image: url('//cdn.frankerfacez.com/script/legacy-turbo.png'); +} \ No newline at end of file diff --git a/src/styles/badges-legacy.css b/src/styles/badges-legacy.css new file mode 100644 index 00000000..cbb69d14 --- /dev/null +++ b/src/styles/badges-legacy.css @@ -0,0 +1,14 @@ +.badges .staff { + background-color: #6441a5; + background-image: url('//cdn.frankerfacez.com/script/legacy-staff.png'); +} + +.badges .broadcaster { + background-color: #000; + background-image: url('//cdn.frankerfacez.com/script/legacy-broadcaster.png'); +} + +.badges .admin { + background-color: #ff0303; + background-image: url('//cdn.frankerfacez.com/script/legacy-admin.png'); +} \ No newline at end of file diff --git a/src/styles/badges-rounded.css b/src/styles/badges-rounded.css new file mode 100644 index 00000000..17c4826c --- /dev/null +++ b/src/styles/badges-rounded.css @@ -0,0 +1,4 @@ +/* Rounded Badges */ +.badges .badge:not(.subscriber) { + border-radius: 2px; +} \ No newline at end of file diff --git a/src/styles/badges-transparent.css b/src/styles/badges-transparent.css new file mode 100644 index 00000000..73d607b5 --- /dev/null +++ b/src/styles/badges-transparent.css @@ -0,0 +1,12 @@ +.badges .badge { + background-color: transparent !important; +} + + +/* Invert Some Badges */ +body:not(.ffz-dark) .app-main:not(.theatre) .conversation-window .badges .badge:not(.subscriber):not(.ffz-badge-0), +.app-main:not(.theatre) .chat-container:not(.dark):not(.force-dark) .badges .badge:not(.subscriber):not(.ffz-badge-0), +.app-main:not(.theatre) .ember-chat-container:not(.dark):not(.force-dark) .badges .badge:not(.subscriber):not(.ffz-badge-0) { + filter: invert(100%); + -webkit-filter: invert(100%); +} \ No newline at end of file diff --git a/src/styles/chat-background.css b/src/styles/chat-background.css new file mode 100644 index 00000000..3df6b9d3 --- /dev/null +++ b/src/styles/chat-background.css @@ -0,0 +1,96 @@ +/* Regular Alternating Background */ +.conversation-chat-lines > div:nth-child(2n+0):before, +.chat-history .chat-line:nth-child(2n+0):before, +.ember-chat .chat-lines > div:nth-child(2n+0) .chat-line:before { + background-color: rgba(0,0,0, 0.1); +} + + +/* Dark: Alternating Background */ +.ffz-dark .conversation-chat-lines > div:nth-child(2n+0):before, +.ffz-dark .chat-history .chat-line:nth-child(2n+0):before, + +.theatre .conversation-chat-lines > div:nth-child(2n+0):before, +.theatre .chat-history .chat-line:nth-child(2n+0):before, +.theatre .ember-chat .chat-lines > div:nth-child(2n+0) .chat-line:before, + +.chat-container.dark .chat-lines > div:nth-child(2n+0) .chat-line:before, +.ember-chat-container.dark .chat-lines > div:nth-child(2n+0) .chat-line:before, +.chat-container.force-dark .chat-lines > div:nth-child(2n+0) .chat-line:before, +.ember-chat-container.force-dark .chat-lines > div:nth-child(2n+0) .chat-line:before { + background-color: rgba(255,255,255, 0.05); +} + + + +/* DEPRECIATED: Mention Backgrounds */ +.chat-history .chat-line.ffz-mentioned:before, +.ember-chat .chat-line.ffz-mentioned:before { + background-color: rgba(255,127,127,0.2); +} + +.chat-history .chat-line.ffz-mentioned:nth-child(2n+0):before, +.ember-chat .chat-lines > div:nth-child(2n+0) .chat-line.ffz-mentioned:before { + background-color: rgba(255,127,127, 0.4); +} + + +/* DEPRECIATED: DARK THEME: Mention Backgrounds */ +.ffz-dark .chat-history .chat-line.ffz-mentioned:before, + +.theatre .ember-chat .chat-line.ffz-mentioned:before, +.chat-container.dark .chat-line.ffz-mentioned:before, +.chat-container.force-dark .chat-line.ffz-mentioned:before, +.ember-chat-container.dark .chat-line.ffz-mentioned:before, +.ember-chat-container.force-dark .chat-line.ffz-mentioned:before { + background-color: rgba(255,0,0, 0.2) !important; +} + + +.theatre .chat-lines > div:nth-child(2n+0) .chat-line.ffz-mentioned:before, + +.chat-container.dark .chat-lines > div:nth-child(2n+0) .chat-line.ffz-mentioned:before, +.ember-chat-container.dark .chat-lines > div:nth-child(2n+0) .chat-line.ffz-mentioned:before, +.chat-container.force-dark .chat-lines > div:nth-child(2n+0) .chat-line.ffz-mentioned:before, +.ember-chat-container.force-dark .chat-lines > div:nth-child(2n+0) .chat-line.ffz-mentioned:before { + background-color: rgba(255,0,0, 0.3) !important; +} + + + +/* Chat Mentions */ +/* TODO: Move this by itself */ + +.ember-chat .mentioned:empty, +.ember-chat .mentioning:empty, +.chat-history .mentioned:empty, +.chat-history .mentioning:empty { + display: none; +} + +.ember-chat .chat-line .mentioned, +.ember-chat .chat-line .mentioning, +.chat-history .chat-line .mentioned, +.chat-history .chat-line .mentioning { + border-radius: 10px; + padding: 3px 7px; + font-weight: bold; + color: #323232; + background-color: rgba(255,255,255, 0.75); +} + +/* DARK THEME: Chat Mentions */ +.ffz-dark .chat-history .mentioned, +.ffz-dark .chat-history .mentioning, + +.chat-container.dark .chat-line .mentioned, +.chat-container.dark .chat-line .mentioning, +.chat-container.force-dark .chat-line .mentioned, +.chat-container.force-dark .chat-line .mentioning, +.ember-chat-container.dark .chat-line .mentioned, +.ember-chat-container.dark .chat-line .mentioning, +.ember-chat-container.force-dark .chat-line .mentioned, +.ember-chat-container.force-dark .chat-line .mentioning { + color: #8c8c8c; + background-color: rgba(16,16,16, 0.75); +} \ No newline at end of file diff --git a/src/styles/chat-colors-gray.css b/src/styles/chat-colors-gray.css new file mode 100644 index 00000000..b0c596f3 --- /dev/null +++ b/src/styles/chat-colors-gray.css @@ -0,0 +1,4 @@ +.chat-line:not(.admin):not(.notification) span.from, +.chat-line:not(.admin):not(.notification) span.message { + color: inherit !important +} \ No newline at end of file diff --git a/src/styles/chat-hc-background.css b/src/styles/chat-hc-background.css new file mode 100644 index 00000000..71ff193a --- /dev/null +++ b/src/styles/chat-hc-background.css @@ -0,0 +1,16 @@ +/* High-Contrast Background */ +.chat-container, +.ember-chat-container { + background-color: #fff; +} + + +/* Dark: High-Contrast Background */ +.theatre .chat-container, +.theatre .ember-chat-container, +.chat-container.dark, +.chat-container.force-dark, +.ember-chat-container.dark, +.ember-chat-container.force-dark { + background-color: #000; +} \ No newline at end of file diff --git a/src/styles/chat-hc-bold.css b/src/styles/chat-hc-bold.css new file mode 100644 index 00000000..5fdee8f5 --- /dev/null +++ b/src/styles/chat-hc-bold.css @@ -0,0 +1,6 @@ +/* High-Contrast Bold */ +.chat-line .from, +.chat-line .colon, +.chat-line .message { + font-weight: bold; +} \ No newline at end of file diff --git a/src/styles/chat-hc-text.css b/src/styles/chat-hc-text.css new file mode 100644 index 00000000..687bd48c --- /dev/null +++ b/src/styles/chat-hc-text.css @@ -0,0 +1,15 @@ +/* High-Contrast Text */ +.chat-container, +.ember-chat-container { + color: #000; +} + +/* Dark: High-Contrast Text */ +.theatre .chat-container, +.theatre .ember-chat-container, +.chat-container.dark, +.chat-container.force-dark, +.ember-chat-container.dark, +.ember-chat-container.force-dark { + color: #fff; +} \ No newline at end of file diff --git a/src/styles/chat-padding.css b/src/styles/chat-padding.css new file mode 100644 index 00000000..e89f59a3 --- /dev/null +++ b/src/styles/chat-padding.css @@ -0,0 +1,15 @@ +/* Chat Line Padding */ +.ember-chat .chat-messages .chat-line, +.ember-chat .chat-messages .chat-line.admin, + +.conversation-window .conversation-system-messages, +.conversation-window .conversation-chat-line, +.conversation-window .timestamp-line { + padding: 5px; +} + + +/* Remove Extra Conversation Padding */ +.conversation-window .conversation-chat-lines { + padding-top: 0; +} \ No newline at end of file diff --git a/src/styles/chat-separator-3d-inset.css b/src/styles/chat-separator-3d-inset.css new file mode 100644 index 00000000..207c57a5 --- /dev/null +++ b/src/styles/chat-separator-3d-inset.css @@ -0,0 +1,19 @@ +/* 3D Inset Separators */ +.conversation-chat-lines > div:before, +.chat-line:before { + border-top: 1px solid #aaa; + border-bottom-color: rgba(255,255,255, 0.5); +} + +/* Dark: 3D Inset Separators */ +.ffz-dark .conversation-chat-lines > div:before, +.theatre .conversation-chat-lines > div:before, + +.theatre .chat-line:before, +.chat-container.dark .chat-line:before, +.chat-container.force-dark .chat-line:before, +.ember-chat-container.dark .chat-line:before, +.ember-chat-container.force-dark .chat-line:before { + border-top-color: #000; + border-bottom-color: rgba(255,255,255, 0.1); +} \ No newline at end of file diff --git a/src/styles/chat-separator-3d.css b/src/styles/chat-separator-3d.css new file mode 100644 index 00000000..92d17ce5 --- /dev/null +++ b/src/styles/chat-separator-3d.css @@ -0,0 +1,17 @@ +/* 3D Separators */ +.conversation-chat-lines > div:before, +.chat-line:before { + border-top: 1px solid rgba(255,255,255, 0.5); +} + +/* Dark: 3D Separators */ +.ffz-dark .conversation-chat-lines > div:before, +.theatre .conversation-chat-lines > div:before, + +.theatre .chat-line:before, +.chat-container.dark .chat-line:before, +.chat-container.force-dark .chat-line:before, +.ember-chat-container.dark .chat-line:before, +.ember-chat-container.force-dark .chat-line:before { + border-top-color: rgba(255,255,255, 0.1); +} \ No newline at end of file diff --git a/src/styles/chat-separator-wide.css b/src/styles/chat-separator-wide.css new file mode 100644 index 00000000..287dd1bf --- /dev/null +++ b/src/styles/chat-separator-wide.css @@ -0,0 +1,17 @@ +/* Wide Separators */ +.conversation-chat-lines > div:before, +.chat-line:before { + border-top: 1px solid #aaa; +} + +/* Dark: Wide Separators */ +.ffz-dark .conversation-chat-lines > div:before, +.theatre .conversation-chat-lines > div:before, + +.theatre .chat-line:before, +.chat-container.dark .chat-line:before, +.chat-container.force-dark .chat-line:before, +.ember-chat-container.dark .chat-line:before, +.ember-chat-container.force-dark .chat-line:before { + border-top-color: #000; +} \ No newline at end of file diff --git a/src/styles/chat-separator.css b/src/styles/chat-separator.css new file mode 100644 index 00000000..ca798fee --- /dev/null +++ b/src/styles/chat-separator.css @@ -0,0 +1,31 @@ +/* Simple Separators */ +.conversation-chat-lines > div:before, +.chat-line:before { + border-bottom: 1px solid #aaa; +} + +/* Dark: Simple Separators */ +.ffz-dark .conversation-chat-lines > div:before, +.theatre .conversation-chat-lines > div:before, + +.theatre .chat-line:before, +.chat-container.dark .chat-line:before, +.chat-container.force-dark .chat-line:before, +.ember-chat-container.dark .chat-line:before, +.ember-chat-container.force-dark .chat-line:before { + border-bottom-color: #000; +} + + + +/* Hide First Line */ +.conversation-chat-lines > div:first-child:before, +.chat-lines > div:first-child .chat-line:before { + border-top-color: transparent; +} + +/* Hide Last Line */ +.conversation-chat-lines > div:last-child:nth-child(odd):before, +.chat-lines > div:last-child:nth-child(odd) .chat-line:before { + border-bottom-color: transparent; +} \ No newline at end of file diff --git a/src/styles/chat-setup.css b/src/styles/chat-setup.css new file mode 100644 index 00000000..ed57617a --- /dev/null +++ b/src/styles/chat-setup.css @@ -0,0 +1,18 @@ +.conversation-chat-lines > div, +.chat-line { + position: relative; + z-index: 1; +} + +.conversation-chat-lines > div:before, +.chat-line:before { + content: ""; + position: absolute; + z-index: -1; + left: 0; right: 0; + top: 2px; bottom: 1px; +} + +.chat-history .chat-line:before { + top: 0; bottom: 0; +} \ No newline at end of file diff --git a/src/ui/styles.js b/src/ui/styles.js index 56a134f9..39465d82 100644 --- a/src/ui/styles.js +++ b/src/ui/styles.js @@ -1,6 +1,7 @@ var FFZ = window.FrankerFaceZ, + utils = require('../utils'), constants = require('../constants'); - //styles = require('../styles'); + styles = require('../styles'); FFZ.prototype.setup_css = function() { document.body.classList.toggle('ffz-flip-dashboard', this.settings.flip_dashboard); @@ -13,6 +14,14 @@ FFZ.prototype.setup_css = function() { s.setAttribute('href', constants.DIRECT_SERVER + "script/style.css?_=" + (constants.DEBUG ? Date.now() : FFZ.version_info)); document.head.appendChild(s); + this.log("Readying toggleable styles."); + this._toggle_style_state = {}; + + s = this._toggle_style = document.createElement('style'); + s.type = "text/css"; + s.id = "ffz-toggle-css"; + document.head.appendChild(s); + /*var s = this._main_style = document.createElement('style'); s.textContent = styles.style; @@ -31,4 +40,15 @@ FFZ.prototype.setup_css = function() { onClose: function() {} } }; +} + + +FFZ.prototype.toggle_style = function(key, enabled) { + var state = this._toggle_style_state[key]; + if ( (enabled && state) || (!enabled && !state) ) + return; + + this._toggle_style_state[key] = enabled; + + utils.update_css(this._toggle_style, key, enabled ? styles[key] || null : null); } \ No newline at end of file diff --git a/style.css b/style.css index dae3d975..847cd8fe 100644 --- a/style.css +++ b/style.css @@ -445,6 +445,11 @@ body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-togg /* Menu Options */ +.emoticon-selector .emoticon-selector-box .subscribe-message { + padding: 10px 20px; + margin: 0; +} + .chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content.menu-side-padding { padding-left: 20px; padding-right: 20px; } .emoticon-grid.collapsed span, @@ -866,39 +871,6 @@ span.ffz-handle:after { left: 8px } box-shadow: 0 0 1px 1px rgba(0,0,0,0.25); } - -/* Chat Mentions */ - -.ember-chat .mentioned:empty, -.ember-chat .mentioning:empty { - display: none; -} - -.ffz-chat-colors-gray .chat-line:not(.admin):not(.notification) span.from, -.ffz-chat-colors-gray .chat-line:not(.admin):not(.notification) span.message { - color: inherit !important -} - -.ffz-chat-background .ember-chat .mentioning, -.ffz-chat-background .ember-chat .mentioned { - border-radius: 10px; - padding: 3px 7px; - font-weight: bold; - color: #32323e; - background-color: rgba(255,255,255, 0.75); -} - -.ffz-chat-background .app-main.theatre .chat-container .chat-line .mentioned, -.ffz-chat-background .ember-chat-container.dark .chat-line .mentioned, -.ffz-chat-background .chat-container.dark .chat-line .mentioned, -.ffz-chat-background .app-main.theatre .chat-container .chat-line .mentioning, -.ffz-chat-background .ember-chat-container.dark .chat-line .mentioning, -.ffz-chat-background .chat-container.dark .chat-line .mentioning { - color: #8c8c9c; - background-color: rgba(16,16,20, 0.75); -} - - /* Fix Moderation Cards */ img.channel_background[src="null"] { display: none; } @@ -1029,228 +1001,19 @@ body:not(.ffz-chat-purge-icon) .ember-chat .mod-icons .purge { display: none; } text-decoration: none; } -.ffz-chat-background .more-messages-indicator { +.more-messages-indicator { /* This looks better when it's full width. */ margin: 0 -20px; } -.ffz-chat-background .chat-line .message { +.chat-line .message { word-break: break-word; } -.ffz-chat-background .ember-chat .chat-messages .tse-scroll-content { +.ember-chat .chat-messages .tse-scroll-content { padding: 0; } -/* This cuts off emotes. -.ffz-chat-background .ember-chat .chat-messages .chat-line { - padding: 3px 20px; - margin: 0px 0px; -} */ - -.ffz-chat-separator .conversation-chat-lines > div, -.ffz-chat-background .conversation-chat-lines > div, -.ffz-chat-separator .chat-line, -.ffz-chat-background .chat-line { - position: relative; - z-index: 1; -} - -.ffz-chat-padding .conversation-window .conversation-chat-lines { - padding-top: 0; -} - -.ffz-chat-padding .ember-chat .chat-messages .chat-line, -.ffz-chat-padding .ember-chat .chat-messages .chat-line.admin, -.ffz-chat-padding .conversation-window .conversation-system-messages, -.ffz-chat-padding .conversation-window .conversation-chat-line, -.ffz-chat-padding .conversation-window .timestamp-line { - padding: 5px; -} - -.ffz-chat-separator .conversation-chat-lines > div:before, -.ffz-chat-background .conversation-chat-lines > div:before, -.ffz-chat-separator .chat-line:before, -.ffz-chat-background .chat-line:before { - content: ""; - position: absolute; - z-index: -1; - left: 0; right: 0; - top: 2px; bottom: 1px; -} - -.ffz-chat-background .chat-history .chat-line:before { - top: 0; bottom: 0; -} - - -.ffz-chat-separator .conversation-chat-lines > div:before, -.ffz-chat-separator .chat-line:before { - border-bottom: 1px solid #aaa; -} - -.ffz-chat-separator-wide .conversation-chat-lines > div:before, -.ffz-chat-separator-wide .chat-line:before { - border-top: 1px solid #aaa; -} - -.ffz-chat-separator-3d .conversation-chat-lines > div:before, -.ffz-chat-separator-3d .chat-line:before { - border-top: 1px solid rgba(255,255,255,0.5); -} - -.ffz-chat-separator-3d-inset .conversation-chat-lines > div:before, -.ffz-chat-separator-3d-inset .chat-line:before { - border-bottom-color: rgba(255,255,255,0.5); - border-top: 1px solid #aaa; -} - -.ffz-chat-separator-wide .conversation-chat-lines > div:first-of-type:before, -.ffz-chat-separator-3d .conversation-chat-lines > div:first-of-type:before, -.ffz-chat-separator-wide ul.chat-lines div:first-of-type .chat-line:before, -.ffz-chat-separator-3d ul.chat-lines div:first-of-type .chat-line:before { - border-top: none; -} - -.ffz-chat-separator:not(.ffz-chat-background) .conversation-chat-lines > div:last-of-type:before, -.ffz-chat-separator:not(.ffz-chat-background) ul.chat-lines div:last-of-type .chat-line:before, -.ffz-chat-separator ul.chat-lines div:last-of-type .chat-line:not(.ffz-alternate):before { - border-bottom: none; -} - -.ffz-chat-separator .theatre .conversation-chat-lines > div:before, -.ffz-chat-separator.ffz-dark .conversation-chat-lines > div:before, -.ffz-chat-separator .app-main.theatre .chat-line:before, -.ffz-chat-separator .chat-container.dark .chat-line:before, -.ffz-chat-separator .chat-container.force-dark .chat-line:before, -.ffz-chat-separator .ember-chat-container.dark .chat-line:before, -.ffz-chat-separator .ember-chat-container.force-dark .chat-line:before { - border-bottom-color: #000; -} - -.ffz-chat-separator-wide .theatre .conversation-chat-lines > div:before, -.ffz-chat-separator-wide.ffz-dark .conversation-chat-lines > div:before, -.ffz-chat-separator-wide .app-main.theatre .chat-line:before, -.ffz-chat-separator-wide .chat-container.dark .chat-line:before, -.ffz-chat-separator-wide .chat-container.force-dark .chat-line:before, -.ffz-chat-separator-wide .ember-chat-container.dark .chat-line:before, -.ffz-chat-separator-wide .ember-chat-container.force-dark .chat-line:before { - border-top-color: #000; -} - -.ffz-chat-separator-3d .theatre .conversation-chat-lines > div:before, -.ffz-chat-separator-3d.ffz-dark .conversation-chat-lines > div:before, -.ffz-chat-separator-3d .app-main.theatre .chat-line:before, -.ffz-chat-separator-3d .chat-container.dark .chat-line:before, -.ffz-chat-separator-3d .chat-container.force-dark .chat-line:before, -.ffz-chat-separator-3d .ember-chat-container.dark .chat-line:before, -.ffz-chat-separator-3d .ember-chat-container.force-dark .chat-line:before { - border-top-color: rgba(255,255,255,0.1); -} - -.ffz-chat-separator-3d-inset .theatre .conversation-chat-lines > div:before, -.ffz-chat-separator-3d-inset.ffz-dark .conversation-chat-lines > div:before, -.ffz-chat-separator-3d-inset .app-main.theatre .chat-line:before, -.ffz-chat-separator-3d-inset .chat-container.dark .chat-line:before, -.ffz-chat-separator-3d-inset .chat-container.force-dark .chat-line:before, -.ffz-chat-separator-3d-inset .ember-chat-container.dark .chat-line:before, -.ffz-chat-separator-3d-inset .ember-chat-container.force-dark .chat-line:before { - border-bottom-color: rgba(255,255,255,0.1); - border-top-color: #000; -} - -.ffz-chat-background .conversation-chat-lines > div:nth-child(2n+0):before, -.ffz-chat-background .chat-history .chat-line.ffz-alternate:before, -.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-alternate:before { - background-color: rgba(0,0,0, 0.1); -} - -.ffz-chat-background .chat-history .chat-line.ffz-mentioned:before, -.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-mentioned:before { - background-color: rgba(255,127,127, 0.2); -} - -.ffz-chat-background .chat-history .chat-line.ffz-mentioned-ffz-alternate:before, -.ffz-chat-background .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate:before { - background-color: rgba(255,127,127, 0.4); -} - -.ffz-chat-background .theatre .conversation-chat-lines > div:nth-child(2n+0):before, -.ffz-chat-background.ffz-dark .conversation-chat-lines > div:nth-child(2n+0):before, - -.ffz-chat-background .app-main.theatre .chat-history .chat-line.ffz-alternate:before, -.ffz-chat-background .chat-container.dark .chat-history .chat-line.ffz-alternate:before, -.ffz-chat-background .ember-chat-container.dark .chat-history .chat-line.ffz-alternate:before, -.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .chat-line.ffz-alternate:before, -.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-alternate:before, -.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .chat-line.ffz-alternate:before { - background-color: rgba(255,255,255, 0.05); -} - - -.ffz-chat-background .app-main.theatre .chat-history .chat-line.ffz-mentioned:before, -.ffz-chat-background .chat-container.dark .chat-history .chat-line.ffz-mentioned:before, -.ffz-chat-background .ember-chat-container.dark .chat-history .chat-line.ffz-mentioned:before, -.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .chat-line.ffz-mentioned:before, -.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned:before, -.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned:before { - background-color: rgba(255,0,0, 0.2); -} - -.ffz-chat-background .app-main.theatre .chat-history .chat-line.ffz-mentioned.ffz-alternate:before, -.ffz-chat-background .chat-container.dark .chat-history .chat-line.ffz-mentioned.ffz-alternate:before, -.ffz-chat-background .ember-chat-container.dark .chat-history .chat-line.ffz-mentioned.ffz-alternate:before, -.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate:before, -.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate:before, -.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .chat-line.ffz-mentioned.ffz-alternate:before { - background-color: rgba(255,0,0, 0.3); -} -*/ - -/* The New Whispers */ - -.ffz-chat-background .ember-chat .chat-messages .whisper-line { - padding-left: 16px; - border-left-width: 4px !important; -} - -.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .whisper-line.whisper-incoming:before, -.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming:before, -.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming:before { - /* 675980 */ - background-color: rgba(78,51,128, 0.4); -} - -.ffz-chat-background .app-main.theatre .ember-chat .chat-messages .whisper-line.whisper-incoming.ffz-alternate:before, -.ffz-chat-background .chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming.ffz-alternate:before, -.ffz-chat-background .ember-chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming.ffz-alternate:before { - /* 675980 */ - background-color: rgba(78,51,128, 0.5); -} - -.ffz-chat-background .ember-chat .chat-messages .whisper-line.whisper-incoming:before { - background-color: rgba(205,178,255, 0.4); -} - -.ffz-chat-background .ember-chat .chat-messages .whisper-line.whisper-incoming.ffz-alternate:before { - background-color: rgba(205,178,255, 0.6); -} - - - -/* Temporary Fix */ - -.chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming, -.app-main.theatre .chat-container .ember-chat .chat-messages .whisper-line.whisper-incoming, -.chat-container.force-dark .ember-chat .chat-messages .whisper-line.whisper-incoming, -.ember-chat-container.dark .ember-chat .chat-messages .whisper-line.whisper-incoming, -.app-main.theatre .ember-chat-container.chat-container .ember-chat .chat-messages .whisper-line.whisper-incoming, -.ember-chat-container.force-dark .ember-chat .chat-messages .whisper-line.whisper-incoming { - background-color: #101014; - border-left: 2px solid #a68ed2 -} - - /* Emoticon Tooltips */ .ffz-wide-tip .tipsy-inner { @@ -1379,7 +1142,11 @@ a.unsafe-link { color: #a64141 !important; } -.chat-container.dark .chat-line a.unsafe-link { +.theatre a.unsafe-link, +.chat-container.dark a.unsafe-link, +.chat-container.force-dark a.unsafe-link, +.ember-chat-container.dark a.unsafe-link, +.ember-chat-container.force-dark a.unsafe-link { color: #d28e8e !important; } @@ -1560,8 +1327,11 @@ th.ffz-row-switch { cursor: default; } +#ffz-group-tabs .button .notifications:empty, +.ffz-room-row td > span:empty, .ffz-chat-tab span:empty { display: none; } +.ffz-room-row td > span, .ffz-chat-tab span { padding: 0 4px; display: inline-block; @@ -1573,6 +1343,29 @@ th.ffz-row-switch { right: 5px; } +.ffz-room-row td { + position: relative; +} + +.ffz-room-row td > span { + line-height: 16px; + margin: 5px 0; +} + +#ffz-group-tabs .button .notifications { + background-color: #d44949; + top: 0; + right: 0; + position: absolute; + height: 12px; + line-height: 12px; + padding: 0 3px; + width: auto; + color: #fff; + font-size: 9px; + vertical-align: middle; + margin: 0; +} /* Dark Group Tabs */ @@ -1588,6 +1381,7 @@ th.ffz-row-switch { color: #B9A3E3; } +.ffz-dark .ffz-room-row td > span, .app-main.theatre .ffz-chat-tab span, .chat-container.dark .ffz-chat-tab span, .ember-chat-container.dark .ffz-chat-tab span { @@ -1826,10 +1620,10 @@ body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-inter /* Badge Styles */ -.ffz-rounded-badges .conversation-window .badges .badge:not(.subscriber), -.ffz-rounded-badges .ember-chat .badges .badge:not(.subscriber) { border-radius: 2px; } +/*.ffz-rounded-badges .conversation-window .badges .badge:not(.subscriber), +.ffz-rounded-badges .ember-chat .badges .badge:not(.subscriber) { border-radius: 2px; }*/ -.ffz-circular-blank-badges .conversation-window .badges .badge:not(.subscriber), +/*.ffz-circular-blank-badges .conversation-window .badges .badge:not(.subscriber), .ffz-circular-small-badges .conversation-window .badges .badge:not(.subscriber), .ffz-circular-badges .conversation-window .badges .badge:not(.subscriber), .ffz-circular-blank-badges .ember-chat .badges .badge:not(.subscriber), @@ -1867,7 +1661,7 @@ body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-inter .ffz-transparent-badges .app-main:not(.theatre) .ember-chat-container:not(.dark):not(.force-dark) .ember-chat .badges .badge:not(.ffz-badge-0):not(.subscriber) { filter: invert(100%); -webkit-filter: invert(100%); -} +}*/ /* No Blue */ @@ -1912,6 +1706,12 @@ body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-inter .ffz-no-blue .ember-chat-container.dark .emoticon-selector .emoticon-grid, .ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .emoticon-selector .emoticon-grid, .ffz-no-blue .ember-chat-container.force-dark .emoticon-selector .emoticon-grid, +/*.ffz-no-blue .chat-container.dark .emoticon-selector .subscribe-message, +.ffz-no-blue .app-main.theatre .chat-container .emoticon-selector .subscribe-message, +.ffz-no-blue .chat-container.force-dark .emoticon-selector .subscribe-message, +.ffz-no-blue .ember-chat-container.dark .emoticon-selector .subscribe-message, +.ffz-no-blue .app-main.theatre .ember-chat-container.chat-container .emoticon-selector .subscribe-message, +.ffz-no-blue .ember-chat-container.force-dark .emoticon-selector .subscribe-message,*/ .ffz-no-blue .chat-container.dark .chat-commands-dropdown, .ffz-no-blue .app-main.theatre .chat-container .chat-commands-dropdown, .ffz-no-blue .chat-container.force-dark .chat-commands-dropdown, @@ -2039,94 +1839,7 @@ li[data-name="following"] a { #small_nav .game_filter.selected .ffz-follow-count { right: 5px; } -/* Legacy Badges */ - -.ffz-legacy-mod-badges .ember-chat .badges .moderator, -.ffz-legacy-badges .ember-chat .badges .moderator { - background-color: #068c10; - background-image: url('//cdn.frankerfacez.com/script/legacy-mod.png'); -} - -.ffz-legacy-badges .ember-chat .badges .staff { - background-color: #6441a5; - background-image: url('//cdn.frankerfacez.com/script/legacy-staff.png'); -} - -.ffz-legacy-badges .ember-chat .badges .broadcaster { - background-color: #000; - background-image: url('//cdn.frankerfacez.com/script/legacy-broadcaster.png'); -} - -.ffz-legacy-badges .ember-chat .badges .admin { - background-color: #ff0303; - background-image: url('//cdn.frankerfacez.com/script/legacy-admin.png'); -} - -.ffz-legacy-turbo-badges .ember-chat .badges .turbo, -.ffz-legacy-badges .ember-chat .badges .turbo { - background-color: #6441a3; - background-image: url('//cdn.frankerfacez.com/script/legacy-turbo.png'); -} - -/* High Contrast Chat */ - -.ffz-high-contrast-chat-text .chat-container, -.ffz-high-contrast-chat-text .ember-chat-container { - color: "#000"; -} - -.ffz-high-contrast-chat-bg .chat-container, -.ffz-high-contrast-chat-bg .ember-chat-container { - background-color: #fff; -} - -.ffz-high-contrast-chat-bold .ember-chat .chat-messages .chat-line .from, -.ffz-high-contrast-chat-bold .ember-chat .chat-messages .chat-line .colon, -.ffz-high-contrast-chat-bold .ember-chat .chat-messages .chat-line .message { - font-weight: bold; -} - -/*.ffz-high-contrast-chat .chat-line:before { - background-color: transparent !important; - border: none !important; -}*/ - -.ffz-high-contrast-chat-text .chat-container.dark, -.ffz-high-contrast-chat-text .chat-container.force-dark, -.ffz-high-contrast-chat-text .ember-chat-container.dark, -.ffz-high-contrast-chat-text .ember-chat-container.force-dark, -.ffz-high-contrast-chat-text .app-main.theatre .chat-container, -.ffz-high-contrast-chat-text.ffz-dark .ember-chat-container.dark .chat-line, -.ffz-high-contrast-chat-text.ffz-dark .chat-container.dark .chat-line { - color: #fff; -} - -.ffz-high-contrast-chat-bg .chat-container.dark, -.ffz-high-contrast-chat-bg .chat-container.force-dark, -.ffz-high-contrast-chat-bg .ember-chat-container.dark, -.ffz-high-contrast-chat-bg .ember-chat-container.force-dark, -.ffz-high-contrast-chat-bg .app-main.theatre .chat-container, -.ffz-high-contrast-chat-bg.ffz-dark .ember-chat-container.dark .chat-line, -.ffz-high-contrast-chat-bg.ffz-dark .chat-container.dark .chat-line { - background-color: #000; -} - - -/*.ffz-high-contrast-chat .chat-line .mentioned { - color: #fff !important; - background-color: #000 !important; -} - -.ffz-high-contrast-chat .chat-container.dark .chat-line .mentioned, -.ffz-high-contrast-chat .chat-container.force-dark .chat-line .mentioned, -.ffz-high-contrast-chat .ember-chat-container.dark .chat-line .mentioned, -.ffz-high-contrast-chat .ember-chat-container.force-dark .chat-line .mentioned, -.ffz-high-contrast-chat .app-main.theatre .chat-container .chat-line .mentioned, -.ffz-high-contrast-chat.ffz-dark .ember-chat-container.dark .chat-line .chat-line .mentioned, -.ffz-high-contrast-chat.ffz-dark .chat-container.dark .chat-line .chat-line .mentioned { - color: #000 !important; - background-color: #fff !important; -}*/ +/* Image Tooltips */ .ffz-image-hover { border:none; From 0cabebdf196a41be1fe996844969a5a5285c9ce9 Mon Sep 17 00:00:00 2001 From: SirStendec Date: Wed, 11 Nov 2015 16:03:27 -0500 Subject: [PATCH 4/5] More style tweaking. Did a bit of work on the Chat Room Management menu (still disabled). Added server history to moderation cards. Fixed gulpfile to actually work with the new styles that are compiled into the script. --- dark.css | 40 +--- gulpfile.js | 15 +- src/badges.js | 2 + src/ember/chatview.js | 10 +- src/ember/moderation-card.js | 111 ++++++++-- src/ember/room.js | 15 +- src/ext/betterttv.js | 1 + src/main.js | 2 +- src/styles/chat-background.css | 39 ++-- src/styles/chat-separator-3d-inset.css | 6 +- src/styles/chat-separator-3d.css | 6 +- src/styles/chat-separator-wide.css | 6 +- src/styles/chat-separator.css | 6 +- src/ui/styles.js | 4 +- style.css | 295 ++++++++++++++++--------- 15 files changed, 336 insertions(+), 222 deletions(-) diff --git a/dark.css b/dark.css index 0f33d367..696bc969 100644 --- a/dark.css +++ b/dark.css @@ -63,35 +63,6 @@ color: #fff !important; } -/* moderation card */ - -.ember-chat-container.dark .ember-chat .ffz-moderation-card, -.chat-container.dark .ember-chat .ffz-moderation-card, -.app-main.theatre .ember-chat .ffz-moderation-card { - border-color: #1b1b20; -} - -.ember-chat-container.dark .ember-chat .moderation-card:focus, -.chat-container.dark .ember-chat .moderation-card:focus, -.app-main.theatre .ember-chat .moderation-card:focus { - border-color: #cbcbcb; -} - -.ember-chat-container.dark .ember-chat .moderation-card .interface, -.chat-container.dark .ember-chat .moderation-card .interface, -.app-main.theatre .ember-chat .moderation-card .interface { - background-color: #232329; -} - -.ffz-no-blue .ember-chat-container.dark .ember-chat .moderation-card .interface, -.ffz-no-blue .chat-container.dark .ember-chat .moderation-card .interface, -.ffz-no-blue .app-main.theatre .ember-chat .moderation-card .interface { - background-color: #232323; -} - -.moderation-card h3.name a { color: #fff !important; } - - /* stats */ .ffz-dark .stats-and-actions, .ffz-dark #main_col .content #stats_and_actions { @@ -531,7 +502,7 @@ /* FrankerFaceZ Menu */ -.ffz-dark .ember-chat .chat-menu .list-header { +/*.ffz-dark .ember-chat .chat-menu .list-header { border-top-color: rgba(255,255,255,0.2); } @@ -553,7 +524,7 @@ .ffz-dark .ffz-ui-popup ul.menu li.active a { border-top-color: rgb(16,16,16); -} +}*/ /* New User Prompt */ @@ -975,7 +946,7 @@ } .ffz-dark .conversations-list .conversations-list-header { - background: #19191f; + background: #121218; border-bottom: 1px solid #32323e; color: #fff } @@ -989,7 +960,7 @@ } .ffz-dark .conversations-list .conversations-list-item:hover { - background-color: #121217 + background-color: #121218; } .ffz-dark .conversation-window { @@ -1007,6 +978,9 @@ .ffz-dark .conversation-header { background: #121217; box-shadow: none; +} + +.ffz-dark .conversation-window:not(.collapsed) .conversation-header { border-bottom: 1px solid rgba(255,255,255,0.2); } diff --git a/gulpfile.js b/gulpfile.js index 97ff6c69..071873ab 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -45,7 +45,7 @@ gulp.task('prepare', ['clean'], function() { //gulp.task('templates', ['prepare'], function() { -// gulp.src(['build/templates/**/*.hbs']) +// return gulp.src(['build/templates/**/*.hbs']) // .pipe(jsEscape()) // .pipe(wrap('Handlebars.compile(<%= contents %>)')) // .pipe(declare({ @@ -63,7 +63,7 @@ gulp.task('prepare', ['clean'], function() { gulp.task('styles', ['prepare'], function() { - gulp.src(['build/styles/**/*.css']) + return gulp.src(['build/styles/**/*.css']) .pipe(minifyCss()) .pipe(jsEscape()) .pipe(declare({ @@ -74,14 +74,14 @@ gulp.task('styles', ['prepare'], function() { return declare.processNameByPath((match && match.length > 1) ? match[1] : filePath); } })) - .pipe(concat('styles.js')) + .pipe(concat('compiled_styles.js')) .pipe(gulp.dest('build/')) .on('error', util.log) }); -gulp.task('scripts', ['prepare', 'styles'], function() { - gulp.src(['build/main.js']) +gulp.task('scripts', ['styles'], function() { + return gulp.src(['build/main.js']) .pipe(browserify()) .pipe(concat('script.js')) .pipe(header('(function(window) {')) @@ -94,7 +94,7 @@ gulp.task('scripts', ['prepare', 'styles'], function() { }); gulp.task('watch', ['default', 'server'], function() { - gulp.watch('src/**/*', ['default']); + return gulp.watch('src/**/*', ['default']); }); gulp.task('default', ['scripts']); @@ -130,7 +130,7 @@ gulp.task('upload', ['default'], function() { .on('error', util.log); }); -gulp.task('clear_cache', ['upload'], function() { +gulp.task('clear_cache', ['upload'], function(cb) { // Load credentials from an external file. var contents = fs.readFileSync('credentials.json', 'utf8'), cred = JSON.parse(contents); @@ -167,6 +167,7 @@ gulp.task('clear_cache', ['upload'], function() { return util.log("[FAIL] Non-200 Status: " + request.statusCode); util.log("[SUCCESS] Cache cleared."); + cb(); }); }); diff --git a/src/badges.js b/src/badges.js index 8069db51..453e0301 100644 --- a/src/badges.js +++ b/src/badges.js @@ -88,6 +88,7 @@ FFZ.settings_info.transparent_badges = { this.toggle_style('badges-blank', val === 3 || val === 4); this.toggle_style('badges-circular-small', val === 4); this.toggle_style('badges-transparent', val === 5); + document.body.classList.toggle('ffz-transparent-badges', val === 5); } }; @@ -104,6 +105,7 @@ FFZ.prototype.setup_badges = function() { this.toggle_style('badges-blank', val === 3 || val === 4); this.toggle_style('badges-circular-small', val === 4); this.toggle_style('badges-transparent', val === 5); + document.body.classList.toggle('ffz-transparent-badges', val === 5); } this.toggle_style('badges-legacy', this.settings.legacy_badges === 3); diff --git a/src/ember/chatview.js b/src/ember/chatview.js index 4170960e..e49f0c1d 100644 --- a/src/ember/chatview.js +++ b/src/ember/chatview.js @@ -716,10 +716,10 @@ FFZ.prototype._modify_cview = function(view) { tabs.innerHTML = ""; var link = document.createElement('a'), - view = this, - total_unread = 0; + view = this; + //total_unread = 0; - for(var room_id in f.rooms) { + /*for(var room_id in f.rooms) { var room = f.rooms[room_id] && f.rooms[room_id].room, is_unread = room && room.get('unreadCount') > 0; @@ -728,11 +728,11 @@ FFZ.prototype._modify_cview = function(view) { total_unread++; } else if ( room ) room._ffz_was_unread = false; - } + }*/ link.className = 'button glyph-only tooltip'; link.title = "Chat Room Management"; - link.innerHTML = constants.ROOMS + '' + (total_unread || '') + ''; + link.innerHTML = constants.ROOMS; // + '' + (total_unread || '') + ''; link.addEventListener('click', function() { var controller = view.get('controller'); diff --git a/src/ember/moderation-card.js b/src/ember/moderation-card.js index 83929d55..536dafc8 100644 --- a/src/ember/moderation-card.js +++ b/src/ember/moderation-card.js @@ -724,38 +724,82 @@ FFZ.prototype.setup_mod_card = function() { if ( f.settings.mod_card_history ) { var Chat = App.__container__.lookup('controller:chat'), room = Chat && Chat.get('currentRoom'), - ffz_room = room && f.rooms && f.rooms[room.get('id')], - user_history = ffz_room && ffz_room.user_history && ffz_room.user_history[controller.get('cardInfo.user.id')]; + tmiSession = room.tmiSession || (window.TMI && TMI._sessions && TMI._sessions[0]), + room_id = room.get('id'), + user_id = controller.get('cardInfo.user.id'), + ffz_room = room && f.rooms && f.rooms[room_id], + user_history = ffz_room && ffz_room.user_history && ffz_room.user_history[user_id] || [], - if ( user_history && user_history.length ) { - var history = document.createElement('ul'); - history.className = 'interface clearfix chat-history'; + history = document.createElement('ul'); - for(var i=0; i < user_history.length; i++) { - var line = user_history[i], - l_el = document.createElement('li'); + history.className = 'interface clearfix chat-history'; - l_el.className = 'message-line chat-line clearfix'; + if ( user_history.length < 20 ) { + var before = user_history.length > 0 ? user_history[0].date.getTime() : Date.now(); + f.ws_send("user_history", [room_id, user_id, 50 - user_history.length], function(success, data) { + if ( ! success ) + return; - if ( line.style ) - l_el.classList.add(line.style); + var i = data.length, + was_at_top = history && history.scrollTop >= (history.scrollHeight - history.clientHeight), + first = true; - l_el.innerHTML = (helpers ? '' + helpers.getTime(line.date) + ' ' : '') + '' + (line.style === 'action' ? '*' + line.from + ' ' : '') + f.render_tokens(line.cachedTokens) + ''; + while(i--) { + var msg = data[i]; + if ( ! msg ) + continue; - // Interactivity - jQuery('a.deleted-link', l_el).click(f._deleted_link_click); - jQuery('img.emoticon', l_el).click(function(e) { f._click_emote(this, e) }); - jQuery('.html-tooltip', l_el).tipsy({html:true}); + if ( typeof msg.date === "string" || typeof msg.date === "number" ) + msg.date = utils.parse_date(msg.date); - // Append - history.appendChild(l_el); - } + if ( ! msg.date || msg.date.getTime() >= before ) + continue; - el.appendChild(history); + if ( first ) { + first = false; + history.insertBefore(f._build_mod_card_history({ + date: msg.date, + from: "jtv", + style: "admin", + cachedTokens: ["(Server History Above)"] + }), history.firstElementChild); + } - // Lazy scroll-to-bottom - history.scrollTop = history.scrollHeight; + if ( ! msg.style ) { + if ( msg.from === "jtv" ) + msg.style = "admin"; + else if ( msg.from === "twitchnotify" ) + msg.style = "notification"; + } + + if ( msg.tags && typeof msg.tags.emotes === "string" ) + try { + msg.tags.emotes = JSON.parse(msg.tags.emotes); + } catch(err) { + f.log("Error Parsing JSON Emotes: " + err); + msg.tags.emotes = {}; + } + + if ( ! msg.cachedTokens || ! msg.cachedTokens.length ) + f.tokenize_chat_line(msg, true, room.get('roomProperties.hide_chat_links')); + + history.insertBefore(f._build_mod_card_history(msg), history.firstElementChild); + if ( history.childElementCount >= 50 ) + break; + } + + if ( was_at_top ) + setTimeout(function() { history.scrollTop = history.scrollHeight; }); + }); } + + for(var i=0; i < user_history.length; i++) + history.appendChild(f._build_mod_card_history(user_history[i])); + + el.appendChild(history); + + // Lazy scroll-to-bottom + history.scrollTop = history.scrollHeight; } // Reposition the menu if it's off-screen. @@ -785,6 +829,29 @@ FFZ.prototype.setup_mod_card = function() { } +FFZ.prototype._build_mod_card_history = function(line) { + var l_el = document.createElement('li'), + f = this; + + l_el.className = 'message-line chat-line clearfix'; + + if ( line.ffz_has_mention ) + l_el.classList.add('ffz-mentioned'); + + if ( line.style ) + l_el.classList.add(line.style); + + l_el.innerHTML = (helpers ? '' + helpers.getTime(line.date) + ' ' : '') + '' + (line.style === 'action' ? '*' + line.from + ' ' : '') + f.render_tokens(line.cachedTokens) + ''; + + // Interactivity + jQuery('a.deleted-link', l_el).click(f._deleted_link_click); + jQuery('img.emoticon', l_el).click(function(e) { f._click_emote(this, e) }); + jQuery('.html-tooltip', l_el).tipsy({html:true}); + + return l_el; +} + + // ---------------- // Aliases // ---------------- diff --git a/src/ember/room.js b/src/ember/room.js index 079a9c97..885366d7 100644 --- a/src/ember/room.js +++ b/src/ember/room.js @@ -1201,20 +1201,7 @@ FFZ.prototype._modify_room = function(room) { was_at_top = history && history.scrollTop >= (history.scrollHeight - history.clientHeight); if ( history ) { - var l_el = document.createElement('li'); - l_el.className = 'message-line chat-line clearfix'; - - if ( msg.style ) - l_el.classList.add(msg.style); - - l_el.innerHTML = (helpers ? '' + helpers.getTime(msg.date) + ' ' : '') + '' + (msg.style === 'action' ? '*' + msg.from + ' ' : '') + f.render_tokens(msg.cachedTokens) + ''; - - // Interactivity - jQuery('a.deleted-link', l_el).click(f._deleted_link_click); - jQuery('img.emoticon', l_el).click(function(e) { f._click_emote(this, e) }); - jQuery('.html-tooltip', l_el).tipsy({html:true}); - - history.appendChild(l_el); + history.appendChild(f._build_mod_card_history(msg)); if ( was_at_top ) setTimeout(function() { history.scrollTop = history.scrollHeight; }) diff --git a/src/ext/betterttv.js b/src/ext/betterttv.js index 8ea6a260..06d2637c 100644 --- a/src/ext/betterttv.js +++ b/src/ext/betterttv.js @@ -77,6 +77,7 @@ FFZ.prototype.setup_bttv = function(delay) { this.toggle_style('badges-transparent'); // Disable other features too. + document.body.classList.remove('ffz-transparent-badges'); document.body.classList.remove("ffz-sidebar-swap"); document.body.classList.remove("ffz-portrait"); document.body.classList.remove("ffz-flip-dashboard"); diff --git a/src/main.js b/src/main.js index 2459a354..ed9f7ae0 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: 5, revision: 63, + major: 3, minor: 5, revision: 65, toString: function() { return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); } diff --git a/src/styles/chat-background.css b/src/styles/chat-background.css index 3df6b9d3..1b6246bc 100644 --- a/src/styles/chat-background.css +++ b/src/styles/chat-background.css @@ -14,10 +14,10 @@ .theatre .chat-history .chat-line:nth-child(2n+0):before, .theatre .ember-chat .chat-lines > div:nth-child(2n+0) .chat-line:before, -.chat-container.dark .chat-lines > div:nth-child(2n+0) .chat-line:before, -.ember-chat-container.dark .chat-lines > div:nth-child(2n+0) .chat-line:before, -.chat-container.force-dark .chat-lines > div:nth-child(2n+0) .chat-line:before, -.ember-chat-container.force-dark .chat-lines > div:nth-child(2n+0) .chat-line:before { +.dark .chat-history .chat-line:nth-child(2n+0):before, +.force-dark .chat-history .chat-line:nth-child(2n+0):before, +.dark .chat-lines > div:nth-child(2n+0) .chat-line:before, +.force-dark .chat-lines > div:nth-child(2n+0) .chat-line:before { background-color: rgba(255,255,255, 0.05); } @@ -38,21 +38,20 @@ /* DEPRECIATED: DARK THEME: Mention Backgrounds */ .ffz-dark .chat-history .chat-line.ffz-mentioned:before, -.theatre .ember-chat .chat-line.ffz-mentioned:before, -.chat-container.dark .chat-line.ffz-mentioned:before, -.chat-container.force-dark .chat-line.ffz-mentioned:before, -.ember-chat-container.dark .chat-line.ffz-mentioned:before, -.ember-chat-container.force-dark .chat-line.ffz-mentioned:before { +.theatre .chat-line.ffz-mentioned:before, +.dark .chat-line.ffz-mentioned:before, +.force-dark .chat-line.ffz-mentioned:before { background-color: rgba(255,0,0, 0.2) !important; } .theatre .chat-lines > div:nth-child(2n+0) .chat-line.ffz-mentioned:before, -.chat-container.dark .chat-lines > div:nth-child(2n+0) .chat-line.ffz-mentioned:before, -.ember-chat-container.dark .chat-lines > div:nth-child(2n+0) .chat-line.ffz-mentioned:before, -.chat-container.force-dark .chat-lines > div:nth-child(2n+0) .chat-line.ffz-mentioned:before, -.ember-chat-container.force-dark .chat-lines > div:nth-child(2n+0) .chat-line.ffz-mentioned:before { +.dark .chat-history .chat-line.ffz-mentioned:nth-child(2n+0):before, +.force-dark .chat-history .chat-line.ffz-mentioned:nth-child(2n+0):before, + +.dark .chat-lines > div:nth-child(2n+0) .chat-line.ffz-mentioned:before, +.force-dark .chat-lines > div:nth-child(2n+0) .chat-line.ffz-mentioned:before { background-color: rgba(255,0,0, 0.3) !important; } @@ -61,17 +60,13 @@ /* Chat Mentions */ /* TODO: Move this by itself */ -.ember-chat .mentioned:empty, -.ember-chat .mentioning:empty, -.chat-history .mentioned:empty, -.chat-history .mentioning:empty { +.mentioned:empty, +.mentioning:empty { display: none; } -.ember-chat .chat-line .mentioned, -.ember-chat .chat-line .mentioning, -.chat-history .chat-line .mentioned, -.chat-history .chat-line .mentioning { +.chat-line .mentioned, +.chat-line .mentioning { border-radius: 10px; padding: 3px 7px; font-weight: bold; @@ -83,6 +78,8 @@ .ffz-dark .chat-history .mentioned, .ffz-dark .chat-history .mentioning, +.app-main.theatre .chat-container .chat-line .mentioned, +.app-main.theatre .chat-container .chat-line .mentioning, .chat-container.dark .chat-line .mentioned, .chat-container.dark .chat-line .mentioning, .chat-container.force-dark .chat-line .mentioned, diff --git a/src/styles/chat-separator-3d-inset.css b/src/styles/chat-separator-3d-inset.css index 207c57a5..0f64d2ca 100644 --- a/src/styles/chat-separator-3d-inset.css +++ b/src/styles/chat-separator-3d-inset.css @@ -10,10 +10,8 @@ .theatre .conversation-chat-lines > div:before, .theatre .chat-line:before, -.chat-container.dark .chat-line:before, -.chat-container.force-dark .chat-line:before, -.ember-chat-container.dark .chat-line:before, -.ember-chat-container.force-dark .chat-line:before { +.dark .chat-line:before, +.force-dark .chat-line:before { border-top-color: #000; border-bottom-color: rgba(255,255,255, 0.1); } \ No newline at end of file diff --git a/src/styles/chat-separator-3d.css b/src/styles/chat-separator-3d.css index 92d17ce5..a4b17c1a 100644 --- a/src/styles/chat-separator-3d.css +++ b/src/styles/chat-separator-3d.css @@ -9,9 +9,7 @@ .theatre .conversation-chat-lines > div:before, .theatre .chat-line:before, -.chat-container.dark .chat-line:before, -.chat-container.force-dark .chat-line:before, -.ember-chat-container.dark .chat-line:before, -.ember-chat-container.force-dark .chat-line:before { +.dark .chat-line:before, +.force-dark .chat-line:before { border-top-color: rgba(255,255,255, 0.1); } \ No newline at end of file diff --git a/src/styles/chat-separator-wide.css b/src/styles/chat-separator-wide.css index 287dd1bf..d7d22f18 100644 --- a/src/styles/chat-separator-wide.css +++ b/src/styles/chat-separator-wide.css @@ -9,9 +9,7 @@ .theatre .conversation-chat-lines > div:before, .theatre .chat-line:before, -.chat-container.dark .chat-line:before, -.chat-container.force-dark .chat-line:before, -.ember-chat-container.dark .chat-line:before, -.ember-chat-container.force-dark .chat-line:before { +.dark .chat-line:before, +.force-dark .chat-line:before { border-top-color: #000; } \ No newline at end of file diff --git a/src/styles/chat-separator.css b/src/styles/chat-separator.css index ca798fee..2aad25cd 100644 --- a/src/styles/chat-separator.css +++ b/src/styles/chat-separator.css @@ -9,10 +9,8 @@ .theatre .conversation-chat-lines > div:before, .theatre .chat-line:before, -.chat-container.dark .chat-line:before, -.chat-container.force-dark .chat-line:before, -.ember-chat-container.dark .chat-line:before, -.ember-chat-container.force-dark .chat-line:before { +.dark .chat-line:before, +.force-dark .chat-line:before { border-bottom-color: #000; } diff --git a/src/ui/styles.js b/src/ui/styles.js index 39465d82..b8b8a4b0 100644 --- a/src/ui/styles.js +++ b/src/ui/styles.js @@ -1,7 +1,7 @@ var FFZ = window.FrankerFaceZ, utils = require('../utils'), constants = require('../constants'); - styles = require('../styles'); + styles = require('../compiled_styles'); FFZ.prototype.setup_css = function() { document.body.classList.toggle('ffz-flip-dashboard', this.settings.flip_dashboard); @@ -49,6 +49,6 @@ FFZ.prototype.toggle_style = function(key, enabled) { return; this._toggle_style_state[key] = enabled; - + utils.update_css(this._toggle_style, key, enabled ? styles[key] || null : null); } \ No newline at end of file diff --git a/style.css b/style.css index 847cd8fe..0a3af431 100644 --- a/style.css +++ b/style.css @@ -290,7 +290,7 @@ body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-togg .ffz-theater-stats .app-main.theatre .channel-stats .stat { color: #aaa; } .ffz-theater-stats .app-main.theatre .channel-stats span:not(.live-count) svg path { - fill: rgba(255,255,255,0.35) !important; + fill: rgba(255,255,255,0.35); } .ffz-theater-stats .app-main.theatre .follow-button .notify:before, @@ -443,6 +443,76 @@ body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-togg #ffz-race-popup table th { border-bottom: 1px solid; } +/* Dark Menu */ + +#ffz-chat-menu { background-color: transparent !important; } + +.ffz-dark .ember-chat .chat-menu .list-header, +.theatre .ember-chat .chat-menu .list-header, +.dark .ember-chat .chat-menu .list-header, +.force-dark .ember-chat .chat-menu .list-header { + border-top-color: rgba(255,255,255, 0.2); +} + +.ffz-dark .chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading, +.theatre .chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading, +.dark .chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading, +.force-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, +.theatre .chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid .heading, +.dark .chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid .heading, +.force-dark .chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid .heading, + +.ffz-dark .ffz-ui-popup ul.menu, +.theatre .ffz-ui-popup ul.menu, +.dark .ffz-ui-popup ul.menu, +.force-dark .ffz-ui-popup ul.menu, + +.ffz-dark .ffz-ui-popup ul.menu a, +.theatre .ffz-ui-popup ul.menu a, +.dark .ffz-ui-popup ul.menu a, +.force-dark .ffz-ui-popup ul.menu a, + +.ffz-sidebar-swap.ffz-dark .ffz-ui-popup ul.menu a, +.ffz-sidebar-swap .theatre .ffz-ui-popup ul.menu a, +.ffz-sidebar-swap .dark .ffz-ui-popup ul.menu a, +.ffz-sidebar-swap .force-dark .ffz-ui-popup ul.menu a { + border-color: #32323e; +} + +.ffz-dark .ffz-ui-popup ul.menu, +.theatre .ffz-ui-popup ul.menu, +.dark .ffz-ui-popup ul.menu, +.force-dark .ffz-ui-popup ul.menu { + background-color: #212121; +} + +.ffz-dark .ffz-ui-popup ul.menu li.active, +.theatre .ffz-ui-popup ul.menu li.active, +.dark .ffz-ui-popup ul.menu li.active, +.force-dark .ffz-ui-popup ul.menu li.active { + background-color: #101010; +} + +.ffz-dark .ffz-ui-popup ul.menu li.active a, +.theatre .ffz-ui-popup ul.menu li.active a, +.dark .ffz-ui-popup ul.menu li.active a, +.force-dark .ffz-ui-popup ul.menu li.active a { + border-top-color: #101010; +} + +.ffz-dark .ffz-ui-popup.emoticon-selector .emoticon-selector-box, +.theatre .ffz-ui-popup.emoticon-selector .emoticon-selector-box, +.dark .ffz-ui-popup.emoticon-selector .emoticon-selector-box, +.force-dark .ffz-ui-popup.emoticon-selector .emoticon-selector-box { + background-color: #101010; + color: #c3c3c3; + border-color: #32323e; +} + + + /* Menu Options */ .emoticon-selector .emoticon-selector-box .subscribe-message { @@ -598,7 +668,7 @@ body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-togg pointer-events: auto; } -.ember-chat .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box .emoticon-grid { background-color: transparent; } +.ember-chat .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box .emoticon-grid { background-color: transparent !important; } .app-main.theatre .ffz-ui-popup ul.menu, .chat-container.dark .ffz-ui-popup ul.menu, @@ -852,21 +922,27 @@ span.ffz-handle:after { left: 8px } box-shadow: 0 0 1px 1px rgba(255,255,255,0.25); } -.ffz-dark .chat-history::-webkit-scrollbar-thumb, .ffz-dark .table::-webkit-scrollbar-thumb, .ffz-dark .conversation-window .conversation-content::-webkit-scrollbar-thumb, .ffz-dark .conversations-list .conversations-list-inner::-webkit-scrollbar-thumb, -.app-main.theatre .conversation-window .conversation-content::-webkit-scrollbar-thumb, -.app-main.theatre .conversations-list .conversations-list-inner::-webkit-scrollbar-thumb, -.ember-chat-container.dark .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, -.chat-container.dark .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, -.app-main.theatre .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, -.ember-chat-container.dark .ffz-ui-menu-page::-webkit-scrollbar-thumb, -.chat-container.dark .ffz-ui-menu-page::-webkit-scrollbar-thumb, -.app-main.theatre .ffz-ui-menu-page::-webkit-scrollbar-thumb, -.ember-chat-container.dark .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb, -.chat-container.dark .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb, -.app-main.theatre .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb { + +.theatre .conversation-window .conversation-content::-webkit-scrollbar-thumb, +.theatre .conversations-list .conversations-list-inner::-webkit-scrollbar-thumb, + +.theatre .chat-history::-webkit-scrollbar-thumb, +.theatre .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, +.theatre .ffz-ui-menu-page::-webkit-scrollbar-thumb, +.theatre .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb + +.dark .chat-history::-webkit-scrollbar-thumb, +.dark .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, +.dark .ffz-ui-menu-page::-webkit-scrollbar-thumb, +.dark .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb, + +.force-dark .chat-history::-webkit-scrollbar-thumb, +.force-dark .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, +.force-dark .ffz-ui-menu-page::-webkit-scrollbar-thumb, +.force-dark .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.6); box-shadow: 0 0 1px 1px rgba(0,0,0,0.25); } @@ -875,25 +951,25 @@ span.ffz-handle:after { left: 8px } img.channel_background[src="null"] { display: none; } -.ember-chat .ffz-moderation-card { +.ffz-moderation-card { border: 2px solid #cbcbcb; max-width: 340px; /*box-shadow: #808080 0 0 5px;*/ } -.ember-chat .ffz-moderation-card .extra-interface { +.ffz-moderation-card .extra-interface { padding-top: 0; } -.ember-chat .ffz-moderation-card .extra-interface + .extra-interface { +.ffz-moderation-card .extra-interface + .extra-interface { margin-top: -10px; } -.ember-chat .ffz-moderation-card.ffz-has-info h3.name { +.ffz-moderation-card.ffz-has-info h3.name { margin-top: 0; } -.ember-chat .ffz-moderation-card .info { +.ffz-moderation-card .info { float: none; position: relative; z-index: 4; @@ -902,72 +978,101 @@ img.channel_background[src="null"] { display: none; } line-height: 18px; } -.ember-chat .ffz-moderation-card .info.channel-stats .stat { - color: #fff; +.ffz-moderation-card .info.channel-stats .stat { + color: #fff !important; } -.ember-chat .ffz-moderation-card .info.channel-stats .stat svg { +.ffz-moderation-card .info.channel-stats .stat svg { margin: 1px 5px 1px 0; pointer-events: none; } -.ember-chat .ffz-moderation-card .info svg path { fill: #fff; } +.ffz-moderation-card .info svg path { fill: #fff !important; } -.ember-chat .ffz-moderation-card button { +.ffz-moderation-card button { margin: 0; padding: 0 5px; } -.ember-chat .ffz-moderation-card button:not(.glyph-only):hover, -.ember-chat .ffz-moderation-card button:not(.glyph-only):focus { +.ffz-moderation-card button:not(.glyph-only):hover, +.ffz-moderation-card button:not(.glyph-only):focus { color: #fff; background-color: rgba(117,80,186, 1); } -.ember-chat .ffz-moderation-card button.message { +.ffz-moderation-card button.message { height: 30px; width: 28px; } -.ember-chat .ffz-moderation-card.ffz-is-mod .interface .mod-controls:last-of-type, -.ember-chat .ffz-moderation-card .interface span.right { +.ffz-moderation-card.ffz-is-mod .interface .mod-controls:last-of-type, +.ffz-moderation-card .interface span.right { float: right; } -.ember-chat .ffz-moderation-card:focus { +.ffz-moderation-card:focus { outline: none; border-color: #444; /*box-shadow: #000 0 0 5px;*/ } -.ember-chat .ffz-moderation-card .interface:not(:last-of-type) { +.ffz-moderation-card .interface:not(:last-of-type) { border-bottom: none; } -.ember-chat .ffz-moderation-card .interface { +.ffz-moderation-card .interface { border-top: none; } -.ember-chat .ffz-moderation-card h3.name { display: inline-block; } +.ffz-moderation-card h3.name { display: inline-block; } -.ember-chat .ffz-moderation-card .info, -.ember-chat .ffz-moderation-card h3.name { +.ffz-moderation-card .info, +.ffz-moderation-card h3.name { text-shadow: black 0 0 5px; } -.ember-chat .ffz-moderation-card .channel_background { +.ffz-moderation-card .channel_background { width: 100%; top: 0; } -body:not(.ffz-chat-purge-icon) .ember-chat .mod-icons .purge { display: none; } +/* dark moderation card */ -.ember-chat .mod-icons .purge { +.dark .ffz-moderation-card, +.force-dark .ffz-moderation-card, +.theatre .ffz-moderation-card { + border-color: #1b1b20; +} + +.dark .ffz-moderation-card:focus, +.force-dark .ffz-moderation-card:focus, +.theatre .ffz-moderation-card:focus { + border-color: #cbcbcb; +} + +.dark .ffz-moderation-card .interface, +.force-dark .ffz-moderation-card .interface, +.theatre .ffz-moderation-card .interface { + background-color: #232329; +} + +.ffz-no-blue .dark .ember-chat .moderation-card .interface, +.ffz-no-blue .force-dark .ember-chat .moderation-card .interface, +.ffz-no-blue .theatre .ember-chat .moderation-card .interface { + background-color: #232323; +} + +.moderation-card h3.name a { color: #fff !important; } + + +/* purge icon */ + +.mod-icons .purge { background-image: url('//cdn.frankerfacez.com/script/PurgeButton.svg'); background-repeat: no-repeat; } -.ember-chat .mod-icons .custom { +.mod-icons .custom { text-indent: 0; text-align: center; text-decoration: none; @@ -1454,7 +1559,7 @@ body.ffz-minimal-chat-input .ember-chat .chat-interface .textarea-contain textar list-style-type: none; padding: 0; max-height: 200px; - overflow-y: scroll; + overflow-y: auto; } .chat-history.interface li:first-child { padding-top: 10px; } @@ -1618,51 +1723,6 @@ body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-inter border-right-color: transparent; } -/* Badge Styles */ - -/*.ffz-rounded-badges .conversation-window .badges .badge:not(.subscriber), -.ffz-rounded-badges .ember-chat .badges .badge:not(.subscriber) { border-radius: 2px; }*/ - -/*.ffz-circular-blank-badges .conversation-window .badges .badge:not(.subscriber), -.ffz-circular-small-badges .conversation-window .badges .badge:not(.subscriber), -.ffz-circular-badges .conversation-window .badges .badge:not(.subscriber), -.ffz-circular-blank-badges .ember-chat .badges .badge:not(.subscriber), -.ffz-circular-small-badges .ember-chat .badges .badge:not(.subscriber), -.ffz-circular-badges .ember-chat .badges .badge:not(.subscriber) { - border-radius: 9px; - background-size: 16px; - background-repeat: no-repeat; - background-position: center center; -} - -.ffz-circular-small-badges .conversation-window .badges .badge:not(.subscriber), -.ffz-circular-blank-badges .conversation-window .badges .badge:not(.subscriber), -.ffz-circular-small-badges .ember-chat .badges .badge:not(.subscriber), -.ffz-circular-blank-badges .ember-chat .badges .badge:not(.subscriber) { - background-size: 0px; -} - -.ffz-circular-small-badges .conversation-window .badges .badge:not(.subscriber), -.ffz-circular-small-badges .ember-chat .badges .badge:not(.subscriber) { - height: 10px; - min-width: 10px; - margin: 5px 3px 5px 0; -} - -.ffz-transparent-badges .conversation-window .badges .badge, -.ffz-transparent-badges .ember-chat .badges .badge { - background-color: transparent !important; -} - -.ffz-transparent-badges:not(.ffz-dark) .app-main:not(.theatre) .conversation-window .badges .badge:not(.ffz-badge-0):not(.subscriber), -.ffz-transparent-badges > .chat-container:not(.dark):not(.force-dark) .ember-chat .badges .badge:not(.ffz-badge-0):not(.subscriber), -.ffz-transparent-badges > .ember-chat-container:not(.dark):not(.force-dark) .ember-chat .badges .badge:not(.ffz-badge-0):not(.subscriber), -.ffz-transparent-badges .app-main:not(.theatre) .chat-container:not(.dark):not(.force-dark) .ember-chat .badges .badge:not(.ffz-badge-0):not(.subscriber), -.ffz-transparent-badges .app-main:not(.theatre) .ember-chat-container:not(.dark):not(.force-dark) .ember-chat .badges .badge:not(.ffz-badge-0):not(.subscriber) { - filter: invert(100%); - -webkit-filter: invert(100%); -}*/ - /* No Blue */ .ffz-no-blue .theatre .conversations-list-icon, @@ -1671,8 +1731,6 @@ body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-inter .ffz-no-blue.ffz-dark .conversations-list, .ffz-no-blue .theatre .conversation-window, .ffz-no-blue.ffz-dark .conversation-window, -.ffz-no-blue .theatre .conversations-list .conversations-list-header, -.ffz-no-blue.ffz-dark .conversations-list .conversations-list-header, .ffz-no-blue #large_nav .content, .ffz-no-blue #small_nav .content, @@ -1777,6 +1835,8 @@ body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-inter .ffz-no-blue .theatre .conversation-header, .ffz-no-blue.ffz-dark .conversation-header, +.ffz-no-blue .theatre .conversations-list .conversations-list-header, +.ffz-no-blue.ffz-dark .conversations-list .conversations-list-header, .ffz-no-blue .theatre .conversation-window.has-focus .conversation-header, .ffz-no-blue.ffz-dark .conversation-window.has-focus .conversation-header, .ffz-no-blue .theatre .conversations-list .conversations-list-item:hover, @@ -1993,22 +2053,25 @@ body:not(.ffz-conv-title-clickable) .conversation-header a.conversation-header-n .conversation-window.has-unread .conversation-header .conversation-header-name { color: #fff !important; } -.ffz-top-conversations .conversation-window.collapsed .conversation-header, -.conversations-list .conversations-list-item:last-of-type { +.ffz-top-conversations:not(.ffz-bttv) .conversation-window.collapsed .conversation-header { + box-shadow: none; +} + +.conversations-list:not(.ffz-bttv) .conversations-list-item:last-of-type { border-bottom: none !important; } -.ffz-top-conversations .conversations-content .conversations-list-icon, -.ffz-top-conversations .conversation-window { +.ffz-top-conversations:not(.ffz-bttv) .conversations-content .conversations-list-icon, +.ffz-top-conversations:not(.ffz-bttv) .conversation-window { + border: 1px solid #dedede; border-top: 0; - border-bottom: 1px solid #dedede; } -.ffz-top-conversations.ffz-dark .conversations-content .conversations-list-icon, -.ffz-top-conversations.ffz-dark .conversation-window, -.ffz-top-conversations .theatre .conversations-content .conversations-list-icon, -.ffz-top-conversations .theatre .conversation-window { - border-bottom-color: rgba(255,255,255,0.2); +.ffz-top-conversations.ffz-dark:not(.ffz-bttv) .conversations-content .conversations-list-icon, +.ffz-top-conversations.ffz-dark:not(.ffz-bttv) .conversation-window, +.ffz-top-conversations:not(.ffz-bttv) .theatre .conversations-content .conversations-list-icon, +.ffz-top-conversations:not(.ffz-bttv) .theatre .conversation-window { + border-color: rgba(255,255,255,0.2); } .ffz-top-conversations .conversations-content { @@ -2024,14 +2087,44 @@ body:not(.ffz-conv-title-clickable) .conversation-header a.conversation-header-n .ffz-top-conversations .conversations-list { bottom: inherit; - top: 46px; + top: 54px; } -.ffz-top-conversations .conversations-list:before, -.ffz-top-conversations .conversations-list:after { - display:none; +.ffz-top-conversations.ffz-bttv .conversations-list { top: 46px; } + +.ffz-top-conversations.ffz-bttv .conversations-list:before, +.ffz-top-conversations.ffz-bttv .conversations-list:after { display: none; } + +.ffz-top-conversations:not(.ffz-bttv) .conversations-list:before, +.ffz-top-conversations:not(.ffz-bttv) .conversations-list:after { + bottom: 100%; + top: auto; } +.ffz-top-conversations:not(.ffz-bttv) .conversations-list:before { + border-top-color: transparent; + border-bottom-color: #dedede; +} + +.ffz-top-conversations:not(.ffz-bttv) .conversations-list:after { + border-top-color: transparent; + border-bottom-color: #f2f2f2; +} + + +.ffz-dark.ffz-top-conversations:not(.ffz-bttv) .conversations-list:before, +.ffz-top-conversations:not(.ffz-bttv) .theatre .conversations-list:before { + border-top-color: transparent; + border-bottom-color: #32323e; +} + +.ffz-dark.ffz-top-conversations:not(.ffz-bttv) .conversations-list:after, +.ffz-top-conversations:not(.ffz-bttv) .theatre .conversations-list:after { + border-top-color: transparent; + border-bottom-color: #121212; +} + + .ffz-top-conversations .theatre .player-controls-bottom { padding-bottom: 0; } From a050063c812fcbf92a99b4f8e053134fae1a26e2 Mon Sep 17 00:00:00 2001 From: SirStendec Date: Sat, 14 Nov 2015 23:52:49 -0500 Subject: [PATCH 5/5] 3.5.66 to 3.5.77. Fixed a performance issue with chat scrolling. Fixed CSS issues introduced in the refactor. Added ReChat support. Fixed all tooltip positioning. Fixed emote usage reporting. Fix support for conversations beta. Fix Do Not Show Again link on portrait mode warning. Fix following data not loading on non-ember pages. Added emoji rendering when BTTV is detected. Made standard chat settings menu scroll. Added support for multiple commands with one button to in-line moderation icons. --- dark.css | 23 +++ src/badges.js | 4 + src/colors.js | 40 +++++ src/constants.js | 3 + src/ember/channel.js | 38 ++-- src/ember/chatview.js | 4 +- src/ember/conversations.js | 66 ++----- src/ember/directory.js | 2 +- src/ember/following.js | 2 +- src/ember/layout.js | 2 +- src/ember/line.js | 35 ++-- src/ember/moderation-card.js | 25 ++- src/ember/player.js | 2 +- src/ember/room.js | 38 +++- src/emoticons.js | 124 ++++++++----- src/ext/betterttv.js | 28 +-- src/ext/rechat.js | 277 ++++++++++++++++++++++++++++++ src/main.js | 28 ++- src/styles/chat-background.css | 12 +- src/styles/chat-hc-background.css | 4 +- src/styles/chat-hc-text.css | 10 +- src/tokenize.js | 116 ++++--------- src/ui/dark.js | 3 + src/ui/following-count.js | 33 +++- src/ui/menu.js | 32 +++- src/ui/my_emotes.js | 16 +- src/ui/sub_count.js | 2 +- src/ui/tooltips.js | 38 ++++ src/ui/viewer_count.js | 2 +- src/utils.js | 107 ++++++++++++ style.css | 44 ++++- 31 files changed, 885 insertions(+), 275 deletions(-) create mode 100644 src/ext/rechat.js create mode 100644 src/ui/tooltips.js diff --git a/dark.css b/dark.css index 696bc969..40e00dd1 100644 --- a/dark.css +++ b/dark.css @@ -902,6 +902,26 @@ /* Conversations */ +.ffz-dark .conversation-input-bar .emoticon-selector-toggle svg path { + fill: rgba(255,255,255,0.2); +} + +.ffz-dark .conversation-input-bar .emoticon-selector-toggle:hover svg path { + fill: rgba(255,255,255,0.5); +} + +.ffz-dark .conversation-input-bar .emoticon-selector-box .emote-set { + border-color: #323232; +} + +.ffz-dark .conversation-input-bar .emoticon-selector-box .emoticon-grid { + background-color: #191919; +} + +.ffz-dark .ember-chat .chat-settings .experimental-options { + border-top-color: rgba(255,255,255, 0.2); +} + .ffz-dark .conversation-settings-menu .options-divider { border-bottom-color: rgba(255,255,255,0.2); } @@ -1012,5 +1032,8 @@ background-color: #6441a5 } +.ffz-dark .conversation-window .timestamp-line span, .ffz-dark .conversation-window .new-message-divider span { background: transparent; } + +.ffz-dark .conversation-window .timestamp-line:after, .ffz-dark .conversation-window .new-message-divider:after { display: none; } \ No newline at end of file diff --git a/src/badges.js b/src/badges.js index 453e0301..1cf59849 100644 --- a/src/badges.js +++ b/src/badges.js @@ -260,6 +260,10 @@ FFZ.prototype.render_badges = function(component, badges) { var user = component.get('msgObject.from') || component.get('message.from.username'), room_id = component.get('msgObject.room') || App.__container__.lookup('controller:chat').get('currentRoom.id'); + return this._render_badges(user, room_id, badges, component); +} + +FFZ.prototype._render_badges = function(user, room_id, badges, component) { var data = this.users[user]; if ( ! data || ! data.badges ) return badges; diff --git a/src/colors.js b/src/colors.js index e05ece22..8b844339 100644 --- a/src/colors.js +++ b/src/colors.js @@ -187,6 +187,43 @@ RGBColor.prototype.eq = function(rgb) { return rgb.r === this.r && rgb.g === this.g && rgb.b === this.b; } +RGBColor.fromCSS = function(rgb) { + rgb = rgb.trim(); + + if ( rgb.charAt(0) === '#' ) + return RGBColor.fromHex(rgb); + + var match = /rgba?\( *(\d+%?) *, *(\d+%?) *, *(\d+%?) *(?:,[^\)]+)?\)/.exec(rgb); + if ( match ) { + var r = match[1], + g = match[2], + b = match[3]; + + if ( r.charAt(r.length-1) === '%' ) + r = 255 * (parseInt(r) / 100); + else + r = parseInt(r); + + if ( g.charAt(g.length-1) === '%' ) + g = 255 * (parseInt(g) / 100); + else + g = parseInt(g); + + if ( b.charAt(b.length-1) === '%' ) + b = 255 * (parseInt(b) / 100); + else + b = parseInt(b); + + return new RGBColor( + Math.min(Math.max(0, r), 255), + Math.min(Math.max(0, g), 255), + Math.min(Math.max(0, b), 255) + ); + } + + return null; +} + RGBColor.fromHex = function(code) { var raw = parseInt(code.charAt(0) === '#' ? code.substr(1) : code, 16); return new RGBColor( @@ -587,6 +624,9 @@ FFZ.prototype._update_colors = function(darkness_only) { FFZ.prototype._handle_color = function(color) { + if ( color instanceof RGBColor ) + color = color.toHex(); + if ( ! color || this._colors.hasOwnProperty(color) ) return this._colors[color]; diff --git a/src/constants.js b/src/constants.js index d8422d59..66f91022 100644 --- a/src/constants.js +++ b/src/constants.js @@ -17,6 +17,8 @@ module.exports = { 2: ["ws://localhost:8001/"] }, + TOOLTIP_DISTANCE: 50, + KNOWN_CODES: { "#-?[\\\\/]": "#-/", ":-?(?:7|L)": ":-7", @@ -42,6 +44,7 @@ module.exports = { "Gr(a|e)yFace": "GrayFace" }, + TWITCH_BASE: 'http://static-cdn.jtvnw.net/emoticons/v1/', EMOTE_MIRROR_BASE: SERVER + "twitch-emote-mirror/", EMOTE_REPLACEMENT_BASE: SERVER + "script/replacements/", diff --git a/src/ember/channel.js b/src/ember/channel.js index 20f02e1e..f7c6f07b 100644 --- a/src/ember/channel.js +++ b/src/ember/channel.js @@ -215,7 +215,13 @@ FFZ.prototype._modify_cindex = function(view) { el.classList.add('ffz-channel'); // Try changing the theater mode tooltip. - this.$('.theatre-button a').attr('title', 'Theater Mode (Alt+T)'); + var tb = this.$('.theatre-button > a'), + opts = tb.data('tipsy'); + + tb.attr('title', 'Theater Mode (Alt+T)'); + if ( opts && opts.options && typeof opts.options.gravity !== "function" ) + opts.options.gravity = utils.tooltip_placement(constants.TOOLTIP_DISTANCE, opts.options.gravity || 'n'); + this.ffzFixTitle(); this.ffzUpdateUptime(); @@ -283,7 +289,7 @@ FFZ.prototype._modify_cindex = function(view) { if ( ! btn ) { btn = document.createElement('span'); btn.id = 'ffz-ui-host-button'; - btn.className = 'button action tooltip'; + btn.className = 'button action'; btn.addEventListener('click', this.ffzClickHost.bind(btn, this, false)); @@ -295,6 +301,8 @@ FFZ.prototype._modify_cindex = function(view) { container.insertBefore(btn, before); else container.appendChild(btn); + + jQuery(btn).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); } btn.classList.remove('disabled'); @@ -321,7 +329,7 @@ FFZ.prototype._modify_cindex = function(view) { if ( ! btn ) { btn = document.createElement('span'); btn.id = 'ffz-ui-host-button'; - btn.className = 'button action tooltip'; + btn.className = 'button action'; btn.addEventListener('click', this.ffzClickHost.bind(btn, this, true)); @@ -333,6 +341,8 @@ FFZ.prototype._modify_cindex = function(view) { container.insertBefore(btn, before); else container.appendChild(btn); + + jQuery(btn).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); } btn.classList.remove('disabled'); @@ -406,7 +416,7 @@ FFZ.prototype._modify_cindex = function(view) { else cont.appendChild(stat); - jQuery(stat).tipsy(); + jQuery(stat).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); } el.innerHTML = utils.number_commas(chatter_count); @@ -438,7 +448,7 @@ FFZ.prototype._modify_cindex = function(view) { else cont.appendChild(stat); - jQuery(stat).tipsy(); + jQuery(stat).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); } el.innerHTML = utils.number_commas(ffz_viewers) + " (" + utils.number_commas(ffz_chatters) + ")"; @@ -473,7 +483,7 @@ FFZ.prototype._modify_cindex = function(view) { if ( ! stat_el ) { stat_el = document.createElement('span'); stat_el.id = 'ffz-ui-player-stats'; - stat_el.className = 'ffz stat tooltip'; + stat_el.className = 'ffz stat'; stat_el.innerHTML = constants.GRAPH + " "; el = document.createElement('span'); @@ -484,16 +494,18 @@ FFZ.prototype._modify_cindex = function(view) { container.insertBefore(stat_el, other.nextSibling); else container.appendChild(stat_el); + + jQuery(stat_el).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); } var delay = parseFloat(stats.hlsLatencyBroadcaster); if ( delay > 180 ) { delay = Math.floor(delay); - stat_el.setAttribute('original-title', 'Video Information\nBroadcast ' + utils.time_to_string(delay, true) + ' Ago\n\nVideo: ' + stats.videoResolution + 'p @ ' + stats.fps + '\nPlayback Rate: ' + stats.playbackRate + ' Kbps') + stat_el.setAttribute('original-title', 'Video Information
Broadcast ' + utils.time_to_string(delay, true) + ' Ago

Video: ' + stats.videoResolution + 'p @ ' + stats.fps + '
Playback Rate: ' + stats.playbackRate + ' Kbps') el.textContent = utils.time_to_string(Math.floor(delay), true, delay > 172800) + ' old'; } else { - stat_el.setAttribute('original-title', 'Stream Latency\nVideo: ' + stats.videoResolution + 'p @ ' + stats.fps + '\nPlayback Rate: ' + stats.playbackRate + ' Kbps'); + stat_el.setAttribute('original-title', 'Stream Latency
Video: ' + stats.videoResolution + 'p @ ' + stats.fps + '
Playback Rate: ' + stats.playbackRate + ' Kbps'); delay = stats.hlsLatencyBroadcaster; var pos = delay.lastIndexOf('.'); @@ -532,7 +544,7 @@ FFZ.prototype._modify_cindex = function(view) { if ( ! stat_el ) { stat_el = document.createElement('span'); stat_el.id = 'ffz-ui-player-stats'; - stat_el.className = 'ffz stat tooltip'; + stat_el.className = 'ffz stat'; stat_el.innerHTML = constants.GRAPH + " "; el = document.createElement('span'); @@ -543,16 +555,18 @@ FFZ.prototype._modify_cindex = function(view) { container.insertBefore(stat_el, other.nextSibling); else container.appendChild(stat_el); + + jQuery(stat_el).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); } var delay = parseFloat(stats.hlsLatencyBroadcaster); if ( delay > 180 ) { delay = Math.floor(delay); - stat_el.setAttribute('original-title', 'Video Information\nBroadcast ' + utils.time_to_string(delay, true) + ' Ago\n\nVideo: ' + stats.videoResolution + 'p @ ' + stats.fps + '\nPlayback Rate: ' + stats.playbackRate + ' Kbps') + stat_el.setAttribute('original-title', 'Video Information
Broadcast ' + utils.time_to_string(delay, true) + ' Ago

Video: ' + stats.videoResolution + 'p @ ' + stats.fps + '
Playback Rate: ' + stats.playbackRate + ' Kbps') el.textContent = utils.time_to_string(Math.floor(delay), true, delay > 172800) + ' old'; } else { - stat_el.setAttribute('original-title', 'Stream Latency\nVideo: ' + stats.videoResolution + 'p @ ' + stats.fps + '\nPlayback Rate: ' + stats.playbackRate + ' Kbps'); + stat_el.setAttribute('original-title', 'Stream Latency
Video: ' + stats.videoResolution + 'p @ ' + stats.fps + '
Playback Rate: ' + stats.playbackRate + ' Kbps'); delay = stats.hlsLatencyBroadcaster; var pos = delay.lastIndexOf('.'); @@ -624,7 +638,7 @@ FFZ.prototype._modify_cindex = function(view) { } } - jQuery(stat).tipsy({html: true}); + jQuery(stat).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); } el.innerHTML = utils.time_to_string(uptime, false, false, false, f.settings.stream_uptime === 1 || f.settings.stream_uptime === 3); diff --git a/src/ember/chatview.js b/src/ember/chatview.js index e49f0c1d..9cfee7e4 100644 --- a/src/ember/chatview.js +++ b/src/ember/chatview.js @@ -415,7 +415,7 @@ FFZ.prototype._modify_cview = function(view) { ffzInit: function() { f._chatv = this; this.$('.textarea-contain').append(f.build_ui_link(this)); - this.$('.chat-messages').find('.html-tooltip').tipsy({live: true, html: true, gravity: jQuery.fn.tipsy.autoNS}); + this.$('.chat-messages').find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')}); if ( !f.has_bttv && f.settings.group_tabs ) this.ffzEnableTabs(); @@ -447,7 +447,7 @@ FFZ.prototype._modify_cview = function(view) { var room = this.get('controller.currentRoom'), rows; room && room.resetUnreadCount(); - if ( room._ffz_was_unread ) { + if ( room && room._ffz_was_unread ) { room._ffz_was_unread = false; var el = this.get('element'), diff --git a/src/ember/conversations.js b/src/ember/conversations.js index f73996b2..b9c1ef2a 100644 --- a/src/ember/conversations.js +++ b/src/ember/conversations.js @@ -7,23 +7,11 @@ var FFZ = window.FrankerFaceZ, // Settings // --------------- -FFZ.settings_info.conv_title_clickable = { - type: "boolean", - value: false, - no_mobile: true, - - category: "Conversations", - name: "Clickable Header Name", - help: "Make the conversation header a link that takes you to that person's page.", - on_update: function(val) { - document.body.classList.toggle('ffz-conv-title-clickable', val); - } - }; - FFZ.settings_info.conv_focus_on_click = { type: "boolean", value: false, no_mobile: true, + visible: false, category: "Conversations", name: "Focus Input on Click", @@ -43,19 +31,6 @@ FFZ.settings_info.top_conversations = { } }; -FFZ.settings_info.conv_beta_enable = { - type: "boolean", - value: false, - no_mobile: true, - - category: "Conversations", - name: "Enable Conversations", - help: "Twitch hasn't enabled them yet, but they're in the code for testing. Try them out!", - on_update: function(val) { - App.__container__.lookup('route:application').controller.set('isConversationsEnabled', val); - } - }; - // --------------- // Initialization @@ -63,10 +38,6 @@ FFZ.settings_info.conv_beta_enable = { FFZ.prototype.setup_conversations = function() { document.body.classList.toggle('ffz-top-conversations', this.settings.top_conversations); - document.body.classList.toggle('ffz-conv-title-clickable', this.settings.conv_title_clickable);; - - if ( this.settings.conv_beta_enable ) - App.__container__.lookup('route:application').controller.set('isConversationsEnabled', true); this.log("Hooking the Ember Conversation Window component."); var ConvWindow = App.__container__.resolve('component:conversation-window'); @@ -78,6 +49,9 @@ FFZ.prototype.setup_conversations = function() { var ConvLine = App.__container__.resolve('component:conversation-line'); if ( ConvLine ) this._modify_conversation_line(ConvLine); + + // TODO: Make this better later. + jQuery('.conversations-list').find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')}); } @@ -88,14 +62,8 @@ FFZ.prototype._modify_conversation_window = function(component) { Settings = App.__container__.lookup('controller:settings'); component.reopen({ - onConversationClick: Ember.on('click', function() { - this.markConversationRead(); - if ( f.settings.conv_focus_on_click ) - this.$(".conversation-input-bar textarea").focus(); - }), - - headerBadges: Ember.computed("conversation.participants", "currentUsername", function() { - var e = this.get("conversation.participants").rejectBy("username", this.get("currentUsername")).objectAt(0), + headerBadges: Ember.computed("thread.participants", "currentUsername", function() { + var e = this.get("thread.participants").rejectBy("username", this.get("currentUsername")).objectAt(0), badges = {}, ut = e.get("userType"); @@ -164,28 +132,18 @@ FFZ.prototype._modify_conversation_window = function(component) { header = el && el.querySelector('.conversation-header'), header_name = header && header.querySelector('.conversation-header-name'), - new_header_name = document.createElement('span'), - raw_color = this.get('otherUser.color'), colors = raw_color && f._handle_color(raw_color), is_dark = (Layout && Layout.get('isTheatreMode')) || f.settings.dark_twitch; - if ( header_name ) { - new_header_name.className = 'conversation-header-name'; - new_header_name.textContent = header_name.textContent; - header.insertBefore(new_header_name, header_name); - - if ( raw_color ) { - header_name.style.color = (is_dark ? colors[1] : colors[0]); - header_name.classList.add('has-color'); - header_name.setAttribute('data-color', raw_color); - - new_header_name.style.color = (is_dark ? colors[1] : colors[0]); - new_header_name.classList.add('has-color'); - new_header_name.setAttribute('data-color', raw_color); - } + if ( header_name && raw_color ) { + header_name.style.color = (is_dark ? colors[1] : colors[0]); + header_name.classList.add('has-color'); + header_name.setAttribute('data-color', raw_color); } + + jQuery(el).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')}); } }); } diff --git a/src/ember/directory.js b/src/ember/directory.js index f3704d36..eba12dd4 100644 --- a/src/ember/directory.js +++ b/src/ember/directory.js @@ -75,7 +75,7 @@ FFZ.prototype._modify_directory_live = function(dir, is_csgo) { var t_el = this._ffz_uptime = document.createElement('div'); t_el.className = 'overlay_info length live'; - jQuery(t_el).tipsy({html: true}); + jQuery(t_el).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 's')}); cap.appendChild(t_el); this._ffz_uptime_timer = setInterval(this.ffzUpdateUptime.bind(this), 1000); diff --git a/src/ember/following.js b/src/ember/following.js index a743749e..21d20985 100644 --- a/src/ember/following.js +++ b/src/ember/following.js @@ -159,7 +159,7 @@ FFZ.prototype.setup_profile_following = function() { return false; t_el.className = 'overlay_info length'; - jQuery(t_el).tipsy({html: true}); + jQuery(t_el).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 's')}); var age = data[0] ? Math.floor((Date.now() - data[0].getTime()) / 1000) : 0; if ( age ) { diff --git a/src/ember/layout.js b/src/ember/layout.js index c77207a7..5da9d789 100644 --- a/src/ember/layout.js +++ b/src/ember/layout.js @@ -228,7 +228,7 @@ FFZ.prototype.setup_layout = function() { return; f._portrait_warning = true; - f.show_message('Twitch\'s Chat Sidebar has been hidden as a result of FrankerFaceZ\'s Portrait Mode because the window is too wide.

Please disable Portrait Mode or make your window narrower.

Do not show this message again'); + f.show_message('Twitch\'s Chat Sidebar has been hidden as a result of FrankerFaceZ\'s Portrait Mode because the window is too wide.

Please disable Portrait Mode or make your window narrower.

Do not show this message again'); }.observes("isTooSmallForRightColumn"), diff --git a/src/ember/line.js b/src/ember/line.js index b2e7b53a..52543528 100644 --- a/src/ember/line.js +++ b/src/ember/line.js @@ -113,7 +113,7 @@ FFZ.settings_info.scrollback_length = { for(var room_id in this.rooms) { var room = this.rooms[room_id]; - room.room.set('messageBufferSize', new_val + ((this._roomv && !this._roomv.get('stuckToBottom') && current_id === room_id) ? 150 : 0)); + room.room && room.room.set('messageBufferSize', new_val + ((this._roomv && !this._roomv.get('stuckToBottom') && current_id === room_id) ? 150 : 0)); } } }; @@ -149,7 +149,6 @@ FFZ.settings_info.banned_words = { category: "Chat Filtering", no_bttv: true, - //visible: function() { return ! this.has_bttv }, name: "Banned Words", help: "Set a list of words that will be locally removed from chat messages.", @@ -181,7 +180,6 @@ FFZ.settings_info.keywords = { category: "Chat Filtering", no_bttv: true, - //visible: function() { return ! this.has_bttv }, name: "Highlight Keywords", help: "Set additional keywords that will be highlighted in chat.", @@ -246,6 +244,21 @@ FFZ.settings_info.link_image_hover = { }; +FFZ.settings_info.emote_image_hover = { + type: "boolean", + value: false, + + category: "Chat Tooltips", + no_mobile: true, + + name: "Emote Preview", + help: "Display scaled up high-DPI emoticon images in tooltips to help see details on low-resolution monitors.", + on_update: function(val) { + this._reset_tooltips(); + } + }; + + FFZ.settings_info.image_hover_all_domains = { type: "boolean", value: false, @@ -402,7 +415,7 @@ FFZ.settings_info.chat_font_family = { var span = document.createElement('span'); span.style.fontFamily = val; - css = ".ember-chat .chat-messages {" + span.style.cssText + "}"; + css = ".timestamp-line,.conversation-chat-line,.conversation-system-messages,.chat-history,.ember-chat .chat-messages {" + span.style.cssText + "}"; } utils.update_css(this._chat_style, "chat_font_family", css); @@ -444,7 +457,7 @@ FFZ.settings_info.chat_font_size = { else { var lh = Math.max(20, Math.round((20/12)*val)), pd = Math.floor((lh - 20) / 2); - css = ".ember-chat .chat-messages .chat-line { font-size: " + val + "px !important; line-height: " + lh + "px !important; }"; + css = ".timestamp-line,.conversation-chat-line,.conversation-system-messages,.chat-history .chat-line,.ember-chat .chat-messages .chat-line { font-size: " + val + "px !important; line-height: " + lh + "px !important; }"; if ( pd ) css += ".ember-chat .chat-messages .chat-line .mod-icons, .ember-chat .chat-messages .chat-line .badges { padding-top: " + pd + "px; }"; } @@ -492,7 +505,7 @@ FFZ.settings_info.chat_ts_size = { css = ""; else { var lh = Math.max(20, Math.round((20/12)*val), Math.round((20/12)*this.settings.chat_font_size)); - css = ".ember-chat .chat-messages .timestamp { font-size: " + val + "px !important; line-height: " + lh + "px !important; }"; + css = ".chat-history .timestamp,.ember-chat .chat-messages .timestamp { font-size: " + val + "px !important; line-height: " + lh + "px !important; }"; } utils.update_css(this._chat_style, "chat_ts_font_size", css); @@ -607,11 +620,13 @@ FFZ.prototype._modify_line = function(component) { if ( e.target.classList.contains('custom') ) { var room_id = this.get('msgObject.room'), room = room_id && f.rooms[room_id] && f.rooms[room_id].room, - cmd = e.target.getAttribute('data-cmd'); if ( room ) { - room.send(cmd, true); + var lines = cmd.split("\n"); + for(var i=0; i < lines.length; i++) + room.send(lines[i], true); + if ( e.target.classList.contains('is-timeout') ) room.clearMessages(this.get('msgObject.from')); } @@ -683,8 +698,8 @@ FFZ.prototype._modify_line = function(component) { else { if ( typeof btn === "string" ) { - cmd = btn.replace(/{user}/g, user); - tip = 'Custom Command\n' + cmd; + cmd = btn.replace(/{user}/g, user).replace(/ * */, "\n"); + tip = 'Custom Command' + (cmd.indexOf('\n') !== -1 ? 's' : '') + '\n' + cmd; } else { cmd = "/timeout " + user + " " + btn; tip = "Timeout User (" + utils.duration_string(btn) + ")"; diff --git a/src/ember/moderation-card.js b/src/ember/moderation-card.js index 536dafc8..dda690af 100644 --- a/src/ember/moderation-card.js +++ b/src/ember/moderation-card.js @@ -182,7 +182,7 @@ FFZ.settings_info.mod_buttons = { old_val += ' ' + prefix + cmd; } - var new_val = prompt("Custom In-Line Moderation Icons\n\nPlease enter a list of commands to be made available as mod icons within chat lines. Commands are separated by spaces. To include spaces in a command, surround the command with double quotes (\"). Use \"{user}\" to insert the user's username into the command, otherwise it will be appended to the end.\n\nExample: !permit \"!reg add {user}\"\n\nNumeric values will become timeout buttons for that number of seconds. The text \"\" is a special value that will act like the normal Ban button in chat.\n\nTo assign a specific letter for use as the icon, specify it at the start of the command followed by an equals sign.\n\nExample: A=\"!reg add\"\n\nDefault: 600", old_val); + var new_val = prompt("Custom In-Line Moderation Icons\n\nPlease enter a list of commands to be made available as mod icons within chat lines. Commands are separated by spaces. To include spaces in a command, surround the command with double quotes (\"). Use \"{user}\" to insert the user's username into the command, otherwise it will be appended to the end.\n\nExample: !permit \"!reg add {user}\"\n\nTo send multiple commands, separate them with \"\".\n\nNumeric values will become timeout buttons for that number of seconds. The text \"\" is a special value that will act like the normal Ban button in chat.\n\nTo assign a specific letter for use as the icon, specify it at the start of the command followed by an equals sign.\n\nExample: A=\"!reg add\"\n\nDefault: 600", old_val); if ( new_val === null || new_val === undefined ) return; @@ -253,8 +253,15 @@ FFZ.settings_info.mod_buttons = { } else had_prefix = true; - if ( typeof val === "string" && val.indexOf('{user}') === -1 ) - val += ' {user}'; + if ( typeof val === "string" ) { + // Split it up for this step. + var lines = val.split(/ * */); + for(var x=0; x < lines.length; x++) { + if ( lines[x].indexOf('{user}') === -1 ) + lines[x] += ' {user}'; + } + val = lines.join(""); + } final.push([prefix, val, had_prefix]); } @@ -475,7 +482,7 @@ FFZ.prototype.setup_mod_card = function() { if ( name ) { name.classList.add('ffz-alias'); name.title = utils.sanitize(controller.get('cardInfo.user.display_name') || user_id.capitalize()); - jQuery(name).tipsy(); + jQuery(name).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); } } @@ -522,7 +529,7 @@ FFZ.prototype.setup_mod_card = function() { btn.innerHTML = utils.sanitize(title); btn.title = utils.sanitize(cmd.replace(/{user}/g, controller.get('cardInfo.user.id') || '{user}')); - jQuery(btn).tipsy(); + jQuery(btn).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); btn.addEventListener('click', add_btn_click.bind(this, cmd)); return btn; }; @@ -601,7 +608,7 @@ FFZ.prototype.setup_mod_card = function() { else if ( f.settings.mod_card_hotkeys && timeout === 1 ) btn.title = "(P)urge - " + btn.title; - jQuery(btn).tipsy(); + jQuery(btn).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); btn.addEventListener('click', btn_click.bind(this, timeout)); return btn; @@ -637,7 +644,7 @@ FFZ.prototype.setup_mod_card = function() { unban_btn.innerHTML = CHECK; unban_btn.title = (f.settings.mod_card_hotkeys ? "(U)" : "U") + "nban User"; - jQuery(unban_btn).tipsy(); + jQuery(unban_btn).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); unban_btn.addEventListener("click", btn_click.bind(this, -1)); jQuery(ban_btn).after(unban_btn); @@ -661,7 +668,7 @@ FFZ.prototype.setup_mod_card = function() { msg_btn.classList.add('message'); msg_btn.title = "Whisper User"; - jQuery(msg_btn).tipsy(); + jQuery(msg_btn).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); var real_msg = document.createElement('button'); @@ -846,7 +853,7 @@ FFZ.prototype._build_mod_card_history = function(line) { // Interactivity jQuery('a.deleted-link', l_el).click(f._deleted_link_click); jQuery('img.emoticon', l_el).click(function(e) { f._click_emote(this, e) }); - jQuery('.html-tooltip', l_el).tipsy({html:true}); + jQuery('.html-tooltip', l_el).tipsy({html:true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')}); return l_el; } diff --git a/src/ember/player.js b/src/ember/player.js index 67c8e888..245dadaf 100644 --- a/src/ember/player.js +++ b/src/ember/player.js @@ -61,7 +61,7 @@ FFZ.prototype.setup_player = function() { this.players = {}; - var Player2 = App && App.__container__.resolve('component:twitch-player2'); + var Player2 = window.App && App.__container__.resolve('component:twitch-player2'); if ( ! Player2 ) return this.log("Unable to find twitch-player2 component."); diff --git a/src/ember/room.js b/src/ember/room.js index 885366d7..d045f5c1 100644 --- a/src/ember/room.js +++ b/src/ember/room.js @@ -134,6 +134,15 @@ FFZ.prototype._modify_rview = function(view) { this._super(); }, + ffzAlternate: function() { + /*if ( ! this._ffz_chat_display ) { + var el = this.get('element'); + this._ffz_chat_display = el && el.querySelector('ul.chat-lines'); + } + + this._ffz_chat_display && this._ffz_chat_display.classList.toggle('ffz-should-alternate');*/ + }, + ffzInit: function() { f._roomv = this; @@ -179,6 +188,9 @@ FFZ.prototype._modify_rview = function(view) { if ( f._roomv === this ) f._roomv = undefined; + if ( this._ffz_chat_display ) + this._ffz_chat_display = undefined; + this.ffzDisableFreeze(); }, @@ -367,12 +379,12 @@ FFZ.prototype._modify_rview = function(view) { } }, - ffzUnfreeze: function() { + ffzUnfreeze: function(from_stuck) { this.ffz_frozen = false; this._ffz_last_move = 0; this.ffzUnwarnPaused(); - if ( this.get('stuckToBottom') ) + if ( ! from_stuck && this.get('stuckToBottom') ) this._scrollToBottom(); }, @@ -434,7 +446,7 @@ FFZ.prototype._modify_rview = function(view) { this.set("stuckToBottom", val); this.get("controller.model") && this.set("controller.model.messageBufferSize", f.settings.scrollback_length + (val ? 0 : 150)); if ( ! val ) - this.ffzUnfreeze(); + this.ffzUnfreeze(true); }, // Warnings~! @@ -728,6 +740,7 @@ FFZ.prototype._insert_history = function(room_id, data) { tmiSession = r.tmiSession || (TMI._sessions && TMI._sessions[0]), tmiRoom = r.tmiRoom, + removed = 0, inserted = 0, purged = {}, @@ -828,10 +841,15 @@ FFZ.prototype._insert_history = function(room_id, data) { this.tokenize_chat_line(msg, true, r.get('roomProperties.hide_chat_links')); if ( r.shouldShowMessage(msg) ) { messages.insertAt(inserted, msg); - while( messages.length > r.get('messageBufferSize') ) + while( messages.length > r.get('messageBufferSize') ) { messages.removeAt(0); + removed++; + } } } + + if ( (removed % 2) && this._roomv && this._roomv.get('context.model.id') === room_id ) + this._roomv.ffzAlternate(); } @@ -995,7 +1013,8 @@ FFZ.prototype._modify_room = function(room) { var msgs = t.get('messages'), total = msgs.get('length'), - i = total; + i = total, + removed = 0; // Delete visible messages while(i--) { @@ -1004,6 +1023,7 @@ FFZ.prototype._modify_room = function(room) { if ( msg.from === user ) { if ( f.settings.remove_deleted ) { msgs.removeAt(i); + removed++; continue; } @@ -1013,6 +1033,9 @@ FFZ.prototype._modify_room = function(room) { } } + if ( (removed % 2) && f._roomv && f._roomv.get('context.model.id') === this.get('id') ) + f._roomv.ffzAlternate(); + // Delete pending messages if (t.ffzPending) { msgs = t.ffzPending; @@ -1064,8 +1087,11 @@ FFZ.prototype._modify_room = function(room) { len = messages.get("length"), limit = this.get("messageBufferSize"); - if ( len > limit ) + if ( len > limit ) { messages.removeAt(0, len - limit); + if ( ((len - limit) % 2) && f._roomv && f._roomv.get('context.model.id') === this.get('id') ) + f._roomv.ffzAlternate(); + } }, // Artificial chat delay diff --git a/src/emoticons.js b/src/emoticons.js index e7b7c9be..34bcea8a 100644 --- a/src/emoticons.js +++ b/src/emoticons.js @@ -4,46 +4,11 @@ var FFZ = window.FrankerFaceZ, constants = require('./constants'), utils = require('./utils'), - - /*check_margins = function(margins, height) { - var mlist = margins.split(/ +/); - if ( mlist.length != 2 ) - return margins; - - mlist[0] = parseFloat(mlist[0]); - mlist[1] = parseFloat(mlist[1]); - - if ( mlist[0] == (height - 18) / -2 && mlist[1] == 0 ) - return null; - - return margins; - }, - - - build_legacy_css = function(emote) { - var margin = emote.margins, srcset = ""; - if ( ! margin ) - margin = ((emote.height - 18) / -2) + "px 0"; - - if ( emote.urls[2] || emote.urls[4] ) { - srcset = 'url("' + emote.urls[1] + '") 1x'; - if ( emote.urls[2] ) - srcset += ', url("' + emote.urls[2] + '") 2x'; - if ( emote.urls[4] ) - srcset += ', url("' + emote.urls[4] + '") 4x'; - - srcset = '-webkit-image-set(' + srcset + '); image-set(' + srcset + ');'; - } - - return ".ffz-emote-" + emote.id + ' { background-image: url("' + emote.urls[1] + '"); height: ' + emote.height + "px; width: " + emote.width + "px; margin: " + margin + (srcset ? '; ' + srcset : '') + (emote.css ? "; " + emote.css : "") + "}\n"; - },*/ - - build_css = function(emote) { if ( ! emote.margins && ! emote.css ) - return ""; //build_legacy_css(emote); + return ""; - return /*build_legacy_css(emote) +*/ 'img[src="' + emote.urls[1] + '"] { ' + (emote.margins ? "margin: " + emote.margins + ";" : "") + (emote.css || "") + " }\n"; + return 'img[src="' + emote.urls[1] + '"] { ' + (emote.margins ? "margin: " + emote.margins + ";" : "") + (emote.css || "") + " }\n"; }, @@ -120,8 +85,15 @@ FFZ.prototype.setup_emoticons = function() { // Emote Usage // ------------------------ -FFZ.prototype.add_usage = function(room_id, emote_id, count) { - var rooms = this.emote_usage[emote_id] = this.emote_usage[emote_id] || {}; +FFZ.prototype.add_usage = function(room_id, emote, count) { + // Only report usage from FFZ emotes. Not extensions to FFZ. + var emote_set = this.emote_sets[emote.set_id]; + if ( ! emote_set || emote_set.source_ext ) + return; + + var emote_id = emote.id, + rooms = this.emote_usage[emote_id] = this.emote_usage[emote_id] || {}; + rooms[room_id] = (rooms[room_id] || 0) + (count || 1); if ( this._emote_report_scheduled ) @@ -260,12 +232,82 @@ FFZ.prototype._emote_tooltip = function(emote) { var set = this.emote_sets[emote.set_id], owner = emote.owner, title = set && set.title || "Global", - source = set && set.source || "FFZ"; + source = set && set.source || "FFZ", - emote._tooltip = "Emoticon: " + (emote.hidden ? "???" : emote.name) + "
" + source + " " + title + (owner ? "
By: " + owner.display_name : ""); + preview_url = this.settings.emote_image_hover ? (emote.urls[4] || emote.urls[2]) : null, + image = preview_url ? '' : ''; + + emote._tooltip = image + "Emoticon: " + (emote.hidden ? "???" : emote.name) + "
" + source + " " + title + (owner ? "
By: " + owner.display_name : ""); return emote._tooltip; } +FFZ.prototype._reset_tooltips = function(twitch_only) { + for(var emote_id in this._twitch_emotes) { + var data = this._twitch_emotes[emote_id]; + if ( data && data.tooltip ) + data.tooltip = null; + } + + if ( ! twitch_only ) { + for(var set_id in this.emote_sets) { + var emote_set = this.emote_sets[set_id]; + for(var emote_id in emote_set.emoticons) { + var emote = emote_set.emoticons[emote_id]; + if ( emote._tooltip ) + emote._tooltip = null; + } + } + } + + var emotes = document.querySelectorAll('img.emoticon'); + for(var i=0; i < emotes.length; i++) { + var emote = emotes[i]; + if ( emote.classList.contains('ffz-image-hover') ) + continue; + + var set_id, + emote_id = emote.getAttribute('data-emote'); + + if ( emote_id ) { + // Twitch Emotes + if ( this.has_bttv ) + continue; + + emote.setAttribute('original-title', utils.build_tooltip.bind(this)(emote_id, false, emote.alt)); + continue; + } + + if ( twitch_only ) + continue; + + // FFZ Emoji + emote_id = emote.getAttribute('data-ffz-emoji'); + if ( emote_id ) { + var emoji = this.emoji_data && this.emoji_data[emote_id], + setting = this.settings.parse_emoji, + + src = emoji ? (setting === 2 ? emoji.noto_src : emoji.tw_src) : null, + image = ''; + + if ( src && this.settings.emote_image_hover ) + image = ''; + + emote.setAttribute('original-title', emoji ? (image + 'Emoji: ' + emote.alt + '
Name: ' + emoji.name + (emoji.short_name ? "
Short Name: :" + emoji.short_name + ":" : "")) : emote.alt); + continue; + } + + // FFZ Emotes + emote_id = emote.getAttribute('data-ffz-emote'); + set_id = emote.getAttribute('data-ffz-set'); + + var emote_set = this.emote_sets[set_id]; + if ( ! emote_set || ! emote_set.emoticons || ! emote_set.emoticons[emote_id] ) + continue; + + emote.setAttribute('original-title', this._emote_tooltip(emote_set.emoticons[emote_id])); + } +} + // --------------------- // Emoji Loading diff --git a/src/ext/betterttv.js b/src/ext/betterttv.js index 06d2637c..8a421127 100644 --- a/src/ext/betterttv.js +++ b/src/ext/betterttv.js @@ -25,8 +25,6 @@ FFZ.prototype.setup_bttv = function(delay) { this.log("BetterTTV was detected after " + delay + "ms. Hooking."); this.has_bttv = true; - // this.track('setCustomVariable', '3', 'BetterTTV', BetterTTV.info.versionString()); - // Disable Dark if it's enabled. document.body.classList.remove("ffz-dark"); if ( this._dark_style ) { @@ -224,14 +222,14 @@ FFZ.prototype.setup_bttv = function(delay) { // Why is emote parsing so bad? ;_; _.each(emotes, function(emote) { var tooltip = f._emote_tooltip(emote), - eo = [''], + eo = [''], old_tokens = tokens; tokens = []; for(var i=0; i < old_tokens.length; i++) { var token = old_tokens[i]; - if ( typeof token != "string" ) { + if ( typeof token !== "string" ) { tokens.push(token); continue; } @@ -248,7 +246,7 @@ FFZ.prototype.setup_bttv = function(delay) { tokens.push(eo); if ( mine && l_room ) - f.add_usage(l_room, emote.id); + f.add_usage(l_room, emote); } else tokens.push(bit); @@ -258,9 +256,10 @@ FFZ.prototype.setup_bttv = function(delay) { } // Sneak in Emojicon Processing - /* if ( f.settings.parse_emoji && f.emoji_data ) { - var old_tokens = tokens; + var old_tokens = tokens, + setting = f.settings.parse_emoji; + tokens = []; for(var i=0; i < old_tokens.length; i++) { @@ -280,20 +279,25 @@ FFZ.prototype.setup_bttv = function(delay) { variant = tbits.shift(); if ( variant === '\uFE0E' ) - bits.push(match); + tokens.push(match); else { var eid = utils.emoji_to_codepoint(match, variant), - data = f.emoji_data[eid]; + data = f.emoji_data[eid], + src = data && (setting === 2 ? data.noto_src : data.tw_src); - if ( data ) { - tokens.push(['' + alt + '']); + if ( data && src ) { + var image = src && f.settings.emote_image_hover ? '' : '', + tooltip = image + "Emoji: " + data.raw + "
Name: " + data.name + (data.short_name ? "
Short Name: :" + data.short_name + ":" : ""), + code = utils.quote_attr(data.raw); + + tokens.push(['' + code + '']); } else tokens.push(match + (variant || "")); } } } } - }*/ + } return tokens; } diff --git a/src/ext/rechat.js b/src/ext/rechat.js new file mode 100644 index 00000000..f024a7f8 --- /dev/null +++ b/src/ext/rechat.js @@ -0,0 +1,277 @@ +var FFZ = window.FrankerFaceZ, + constants = require('../constants'), + utils = require('../utils'); + + +// -------------------- +// Initialization +// -------------------- + +FFZ.prototype.setup_rechat = function() { + if ( this.has_bttv || navigator.userAgent.indexOf('Android') !== -1 ) + return; + + this._rechat_listening = false; + + this.log("Installing ReChat mutation observer."); + + var f = this; + this._rechat_observer = new MutationObserver(function(mutations) { + for(var i=0; i < mutations.length; i++) { + var mutation = mutations[i]; + if ( mutation.type !== "childList" ) + continue; + + for(var x=0; x < mutation.addedNodes.length; x++) { + var added = mutation.addedNodes[x]; + if ( added.nodeType !== added.ELEMENT_NODE || added.tagName !== "DIV" ) + continue; + + // Is this a ReChat line? + if ( added.classList.contains('rechat-chat-line') && ! added.classList.contains('ffz-processed') ) + f.process_rechat_line(added); + } + } + }); + + this.log("Starting ReChat check loop."); + this._rechat_interval = setInterval(this.find_rechat.bind(this), 1000); + this.find_rechat(); +} + + +// -------------------- +// ReChat Detection +// -------------------- + +FFZ.prototype.find_rechat = function() { + var el = !this.has_bttv ? document.querySelector('.rechat-chat-line') : null; + + // If there's no change, don't continue. + if ( !!el === this._rechat_listening ) + return; + + // If we're no longer listening, stop the observer and quit. + if ( ! el ) { + this._rechat_observer.disconnect(); + this._rechat_listening = false; + return; + } + + // We're newly listening. Process all existing ReChat chat lines + // and darken the container if required, also enable the observer. + var container = jQuery(el).parents('.chat-container'); + if ( ! container.length ) + return; + + container = container[0]; + + // Look-up dark mode. + var dark_chat = this.settings.dark_twitch; + if ( ! dark_chat ) { + var model = window.App ? App.__container__.lookup('controller:settings').get('model') : undefined; + dark_chat = model && model.get('darkMode'); + } + + container.classList.toggle('dark', dark_chat); + jQuery(container).find('.chat-lines').addClass('ffz-scrollbar'); + + // Tooltips + jQuery(container).find('.tooltip').tipsy({live: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); + jQuery(container).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')}); + + // Load the room data. + var room_id = el.getAttribute('data-room'); + if ( room_id && ! this.rooms[room_id] ) + this.load_room(room_id, this._reprocess_rechat.bind(this, container)); + + // Do stuff. + var lines = container.querySelectorAll('.rechat-chat-line'); + for(var i=0; i < lines.length; i++) { + var line = lines[i]; + if ( line.classList.contains('ffz-processed') ) + continue; + + this.process_rechat_line(line); + } + + // Start observing. + this._rechat_observer.observe(container, { + childList: true, + subtree: true + }); + + this._rechat_listening = true; +} + + +// -------------------- +// ReChat Lines +// -------------------- + +FFZ.prototype._reprocess_rechat = function(container) { + var lines = container.querySelectorAll('.rechat-chat-line'); + for(var i=0; i < lines.length; i++) + this.process_rechat_line(lines[i], true); +} + + +FFZ.prototype.process_rechat_line = function(line, reprocess) { + if ( ! reprocess && line.classList.contains('ffz-processed') ) + return; + + line.classList.add('ffz-processed'); + + var user_id = line.getAttribute('data-sender'), + room_id = line.getAttribute('data-room'), + + Layout = App.__container__.lookup('controller:layout'), + Settings = App.__container__.lookup('controller:settings'), + is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('model.darkMode')), + + badges_el = line.querySelector('.badges'), + from_el = line.querySelector('.from'), + message_el = line.querySelector('.message'), + + badges = {}, + had_badges = !!badges_el, + + raw_color = from_el && FFZ.Color.RGB.fromCSS(from_el.style.color), + colors = raw_color && this._handle_color(raw_color), + + alias = this.aliases[user_id]; + + + if ( ! badges_el ) { + badges_el = document.createElement('span'); + badges_el.className = 'badges float-left'; + line.insertBefore(badges_el, from_el || line.firstElementChild); + } + + if ( ! reprocess || ! had_badges ) { + // Read existing known badges. + var existing = badges_el.querySelectorAll('.badge'); + for(var i=0; i < existing.length; i++) { + var badge = existing[i]; + if ( badge.classList.contains('broadcaster') ) + badges[0] = {klass: 'broadcaster', title: 'Broadcaster'}; + else if ( badge.classList.contains('staff') ) + badges[0] = {klass: 'staff', title: 'Staff'}; + else if ( badge.classList.contains('admin') ) + badges[0] = {klass: 'admin', title: 'Admin'}; + else if ( badge.classList.contains('global-moderator') ) + badges[0] = {klass: 'global-moderator', title: 'Global Moderator'}; + else if ( badge.classList.contains('moderator') ) + badges[0] = {klass: 'moderator', title: 'Moderator'}; + else if ( badge.classList.contains('subscriber') ) + badges[10] = {klass: 'subscriber', title: 'Subscriber'}; + else if ( badge.classList.contains('turbo') ) + badges[15] = {klass: 'turbo', title: 'Turbo'}; + } + + if ( user_id && user_id === room_id ) + badges[0] = {klass: 'broadcaster', title: 'Broadcaster'}; + + if ( user_id ) + badges = this._render_badges(user_id, room_id, badges); + + var output = ''; + for(var key in badges) { + var badge = badges[key], + css = badge.iamge ? 'background-image:url("' + badge.image + '");' : ''; + + if ( badge.color ) + css += 'background-color:' + badge.color + ';'; + + if ( badge.extra_css ) + css += badge.extra_css; + + output += '
'; + } + + badges_el.innerHTML = output; + } + + if ( ! reprocess && from_el ) { + from_el.style.fontWeight = ""; + if ( colors ) { + from_el.classList.add('has_color'); + from_el.style.color = is_dark ? colors[1] : colors[0]; + } + + if ( alias ) { + from_el.classList.add('ffz-alias'); + from_el.title = from_el.textContent; + from_el.textContent = alias; + } + } + + if ( ! message_el ) + return; + + if ( ! reprocess && message_el.style.color ) { + message_el.classList.add('has-color'); + message_el.style.color = is_dark ? colors[1] : colors[0]; + } + + var raw_tokens = line.getAttribute('data-tokens'), + tokens = raw_tokens ? JSON.parse(raw_tokens) : []; + + if ( ! raw_tokens ) { + for(var i=0; i < message_el.childNodes.length; i++) { + var node = message_el.childNodes[i]; + + if ( node.nodeType === node.TEXT_NODE ) + tokens.push(node.textContent); + + else if ( node.nodeType === node.ELEMENT_NODE ) { + if ( node.tagName === 'IMG' ) + tokens.push({ + altText: node.alt, + emoticonSrc: node.src + }); + + else if ( node.tagName === 'A' ) + tokens.push({ + isLink: true, + href: node.textContent + }); + + else if ( node.tagName === 'SPAN' ) + tokens.push({ + mentionedUser: node.textContent, + own: node.classList.contains('mentioning') + }); + + else + this.log("Unknown Tag Type: " + node.tagName); + } else + this.log("Unknown Node Type Tokenizing Message: " + node.nodeType); + } + } + + line.setAttribute('data-tokens', JSON.stringify(tokens)); + + // Further tokenization~! + if ( this.settings.replace_bad_emotes ) + tokens = this.tokenize_replace_emotes(tokens); + + tokens = this._remove_banned(tokens); + tokens = this.tokenize_emotes(user_id, room_id, tokens, false); + + if ( this.settings.parse_emoji ) + tokens = this.tokenize_emoji(tokens); + + tokens = this.tokenize_mentions(tokens); + + // Check for a mention + if ( ! line.classList.contains('ffz-mentioend') ) + for(var i=0; i < tokens.length; i++) + if ( tokens[i].mentionedUser ) { + line.classList.add('ffz-mentioned'); + break; + } + + // Now, put the content back into the element. + message_el.innerHTML = this.render_tokens(tokens); +} \ No newline at end of file diff --git a/src/main.js b/src/main.js index ed9f7ae0..666649d3 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: 5, revision: 65, + major: 3, minor: 5, revision: 77, toString: function() { return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); } @@ -90,12 +90,22 @@ FFZ.prototype._pastebin = function(data, callback) { // ------------------- FFZ.prototype.get_user = function() { - if ( window.PP && PP.login ) { - return PP; - } else if ( window.App ) { - var nc = App.__container__.lookup("controller:login"); - return nc ? nc.get("userData") : undefined; + if ( this.__user ) + return this.__user; + + var user; + if ( window.App ) { + var nc = App.__container__.lookup('controller:login'); + user = nc ? nc.get('userData') : undefined; } + + if ( ! user && window.PP && PP.login ) + user = PP; + + if ( user ) + this.__user = user; + + return user; } @@ -133,6 +143,7 @@ require('./ember/following'); require('./debug'); +require('./ext/rechat'); require('./ext/betterttv'); require('./ext/emote_menu'); @@ -140,6 +151,7 @@ require('./featurefriday'); require('./ui/styles'); require('./ui/dark'); +require('./ui/tooltips'); require('./ui/notifications'); require('./ui/viewer_count'); require('./ui/sub_count'); @@ -256,6 +268,7 @@ FFZ.prototype.init_normal = function(delay, no_socket) { this.setup_following_count(false); this.setup_menu(); + this.fix_tooltips(); this.find_bttv(10); var end = (window.performance && performance.now) ? performance.now() : Date.now(), @@ -297,6 +310,7 @@ FFZ.prototype.init_dashboard = function(delay) { // Set up the FFZ message passer. this.setup_message_event(); + this.fix_tooltips(); this.find_bttv(10); var end = (window.performance && performance.now) ? performance.now() : Date.now(), @@ -354,8 +368,10 @@ FFZ.prototype.init_ember = function(delay) { this.setup_following_count(true); this.setup_races(); + this.fix_tooltips(); this.connect_extra_chat(); + this.setup_rechat(); this.find_bttv(10); this.find_emote_menu(10); diff --git a/src/styles/chat-background.css b/src/styles/chat-background.css index 1b6246bc..8f162569 100644 --- a/src/styles/chat-background.css +++ b/src/styles/chat-background.css @@ -1,7 +1,10 @@ /* Regular Alternating Background */ .conversation-chat-lines > div:nth-child(2n+0):before, .chat-history .chat-line:nth-child(2n+0):before, -.ember-chat .chat-lines > div:nth-child(2n+0) .chat-line:before { +.ember-chat .chat-lines > div:nth-child(2n+0) .chat-line:before, + +/* ReChat */ +.ember-chat.chat-messages > .rechat-chat-line:nth-child(2n+0):before { background-color: rgba(0,0,0, 0.1); } @@ -17,7 +20,12 @@ .dark .chat-history .chat-line:nth-child(2n+0):before, .force-dark .chat-history .chat-line:nth-child(2n+0):before, .dark .chat-lines > div:nth-child(2n+0) .chat-line:before, -.force-dark .chat-lines > div:nth-child(2n+0) .chat-line:before { +.force-dark .chat-lines > div:nth-child(2n+0) .chat-line:before, + +/* ReChat */ +.theatre .chat-lines > .rechat-chat-line:nth-child(2n+0):before, +.dark .chat-lines > .rechat-chat-line:nth-child(2n+0):before, +.force-dark .chat-lines > .rechat-chat-line:nth-child(2n+0):before { background-color: rgba(255,255,255, 0.05); } diff --git a/src/styles/chat-hc-background.css b/src/styles/chat-hc-background.css index 71ff193a..87096e93 100644 --- a/src/styles/chat-hc-background.css +++ b/src/styles/chat-hc-background.css @@ -1,7 +1,7 @@ /* High-Contrast Background */ .chat-container, .ember-chat-container { - background-color: #fff; + background-color: #fff !important; } @@ -12,5 +12,5 @@ .chat-container.force-dark, .ember-chat-container.dark, .ember-chat-container.force-dark { - background-color: #000; + background-color: #000 !important; } \ No newline at end of file diff --git a/src/styles/chat-hc-text.css b/src/styles/chat-hc-text.css index 687bd48c..867b0e6e 100644 --- a/src/styles/chat-hc-text.css +++ b/src/styles/chat-hc-text.css @@ -1,7 +1,7 @@ /* High-Contrast Text */ .chat-container, .ember-chat-container { - color: #000; + color: #000 !important; } /* Dark: High-Contrast Text */ @@ -10,6 +10,10 @@ .chat-container.dark, .chat-container.force-dark, .ember-chat-container.dark, -.ember-chat-container.force-dark { - color: #fff; +.ember-chat-container.force-dark, + +.ffz-dark .ember-chat-container.dark .chat-line, +.ffz-dark .chat-container.dark .chat-line + { + color: #fff !important; } \ No newline at end of file diff --git a/src/tokenize.js b/src/tokenize.js index 1f3d1d51..bd877874 100644 --- a/src/tokenize.js +++ b/src/tokenize.js @@ -1,76 +1,11 @@ var FFZ = window.FrankerFaceZ, utils = require("./utils"), constants = require("./constants"), - TWITCH_BASE = "http://static-cdn.jtvnw.net/emoticons/v1/", helpers, + conv_helpers, EXPLANATION_TRAIL = '
FFZ is hiding this link because this url shortener is known to be used by Twitch spam bots posting malicious links. Please use caution when visiting shortened links.', - SRCSETS = {}; - build_srcset = function(id) { - if ( SRCSETS[id] ) - return SRCSETS[id]; - var out = SRCSETS[id] = TWITCH_BASE + id + "/1.0 1x, " + TWITCH_BASE + id + "/2.0 2x, " + TWITCH_BASE + id + "/3.0 4x"; - return out; - }, - - - data_to_tooltip = function(data) { - var set = data.set, - set_type = data.set_type, - owner = data.owner; - - if ( set_type === undefined ) - set_type = "Channel"; - - if ( ! set ) - return data.code; - - else if ( set === "--global--" ) { - set = "Twitch Global"; - set_type = null; - - } else if ( set == "--twitch-turbo--" || set == "turbo" || set == "--turbo-faces--" ) { - set = "Twitch Turbo"; - set_type = null; - } - - return "Emoticon: " + data.code + "
" + (set_type ? set_type + ": " : "") + set + (owner ? "
By: " + owner.display_name : ""); - }, - - build_tooltip = function(id) { - var emote_data = this._twitch_emotes[id], - set = emote_data ? emote_data.set : null; - - if ( ! emote_data ) - return "???"; - - if ( typeof emote_data == "string" ) - return emote_data; - - if ( emote_data.tooltip ) - return emote_data.tooltip; - - return emote_data.tooltip = data_to_tooltip(emote_data); - }, - - load_emote_data = function(id, code, success, data) { - if ( ! success ) - return code; - - if ( code ) - data.code = code; - - this._twitch_emotes[id] = data; - var tooltip = build_tooltip.bind(this)(id); - - var images = document.querySelectorAll('img[data-emote="' + id + '"]'); - for(var x=0; x < images.length; x++) - images[x].title = tooltip; - - return tooltip; - }, - reg_escape = function(str) { return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); @@ -105,7 +40,7 @@ var FFZ = window.FrankerFaceZ, return IMGUR_PATH.test(path); return any_domain ? IMAGE_EXT.test(path) : IMAGE_DOMAINS.indexOf(domain) !== -1; - } + }, image_iframe = function(href, extra_class) { return ''; @@ -248,12 +183,12 @@ FFZ._emote_mirror_swap = function(img) { img.setAttribute('data-alt-attempts', attempts + 1); var id = img.getAttribute('data-emote'); - if ( img.src.substr(0, TWITCH_BASE.length) === TWITCH_BASE ) { + if ( img.src.substr(0, constants.TWITCH_BASE.length) === constants.TWITCH_BASE ) { img.src = constants.EMOTE_MIRROR_BASE + id + ".png"; img.srcset = ""; } else { - img.src = TWITCH_BASE + id + "/1.0"; - img.srcset = build_srcset(id); + img.src = constants.TWITCH_BASE + id + "/1.0"; + img.srcset = utils.build_srcset(id); } } @@ -317,6 +252,10 @@ FFZ.prototype.setup_tokenization = function() { if ( ! helpers ) return this.log("Unable to get chat helper functions."); + conv_helpers = window.require && window.require("ember-twitch-conversations/helpers/conversation-line-helpers"); + if ( ! conv_helpers ) + this.log("Unable to get conversation helper functions."); + this.log("Hooking Ember chat line helpers."); var f = this; @@ -386,6 +325,8 @@ FFZ.prototype.load_twitch_emote_data = function(tries) { this._twitch_set_to_channel[33] = "--turbo-faces--"; this._twitch_set_to_channel[42] = "--turbo-faces--"; + this._reset_tooltips(true); + }).fail(function(data) { if ( data.status === 404 ) return; @@ -410,6 +351,9 @@ FFZ.prototype.tokenize_conversation_line = function(message, prevent_notificatio emotes = message.get('tags.emotes'), tokens = [msg]; + if ( conv_helpers && conv_helpers.checkActionMessage ) + tokens = conv_helpers.checkActionMessage(tokens); + // Standard Tokenization if ( helpers && helpers.linkifyMessage ) tokens = helpers.linkifyMessage(tokens); @@ -597,8 +541,11 @@ FFZ.prototype.tokenize_line = function(user, room, message, no_emotes, no_emoji) FFZ.prototype.render_tokens = function(tokens, render_links) { var f = this; return _.map(tokens, function(token) { + if ( token.hidden ) + return ""; + if ( token.emoticonSrc ) { - var tooltip, src = token.emoticonSrc, srcset, extra; + var tooltip, src = token.emoticonSrc, srcset, cls, extra; if ( token.ffzEmote ) { var emote_set = f.emote_sets && f.emote_sets[token.ffzEmoteSet], emote = emote_set && emote_set.emoticons && emote_set.emoticons[token.ffzEmote]; @@ -610,26 +557,32 @@ FFZ.prototype.render_tokens = function(tokens, render_links) { } else if ( token.ffzEmoji ) { var eid = token.ffzEmoji, emoji = f.emoji_data && f.emoji_data[eid], - setting = f.settings.parse_emoji; + setting = f.settings.parse_emoji, + image = ''; if ( setting === 0 || (setting === 1 && ! emoji.tw) || (setting === 2 && ! emoji.noto) ) return token.altText; - tooltip = emoji ? "Emoji: " + token.altText + "\nName: " + emoji.name + (emoji.short_name ? "\nShort Name: :" + emoji.short_name + ":" : "") : token.altText; - extra = ' data-ffz-emoji="' + eid + '" height="18px"'; src = setting === 2 ? token.noto_src : token.tw_src; + if ( emoji && f.settings.emote_image_hover ) + image = ''; + + tooltip = emoji ? image + "Emoji: " + token.altText + "
Name: " + emoji.name + (emoji.short_name ? "
Short Name: :" + emoji.short_name + ":" : "") : token.altText; + extra = ' data-ffz-emoji="' + eid + '" height="18px"'; + cls = ' emoji'; + } else { var id = token.replacedId || FFZ.src_to_id(token.emoticonSrc), data = id && f._twitch_emotes && f._twitch_emotes[id]; if ( data ) - tooltip = data.tooltip ? data.tooltip : token.altText; + tooltip = data.tooltip ? data.tooltip : utils.build_tooltip.bind(f)(id, false, token.altText); else { try { var set_id = f._twitch_emote_to_set[id]; if ( set_id ) { - tooltip = load_emote_data.bind(f)(id, token.altText, true, { + tooltip = utils.load_emote_data.bind(f)(id, token.altText, true, { code: token.altText, id: id, set: f._twitch_set_to_channel[set_id], @@ -637,19 +590,18 @@ FFZ.prototype.render_tokens = function(tokens, render_links) { }); } else { tooltip = f._twitch_emotes[id] = token.altText; - f.ws_send("twitch_emote", id, load_emote_data.bind(f, id, token.altText)); + f.ws_send("twitch_emote", id, utils.load_emote_data.bind(f, id, token.altText)); } } catch(err) { f.error("Error Generating Emote Tooltip: " + err); } } - var mirror_url = utils.quote_attr(constants.EMOTE_MIRROR_BASE + id + '.png'); - + //var mirror_url = utils.quote_attr(constants.EMOTE_MIRROR_BASE + id + '.png'); extra = ' data-emote="' + id + '"'; // onerror="FrankerFaceZ._emote_mirror_swap(this)"'; // Disable error checking for now. if ( ! constants.EMOTE_REPLACEMENTS[id] ) - srcset = build_srcset(id); + srcset = utils.build_srcset(id); } return ''; @@ -797,7 +749,7 @@ FFZ.prototype.tokenize_title_emotes = function(tokens) { data = data.emoticon_sets[0]; for(var i=0; i < data.length; i++) { var em = data[i]; - emotes.push({regex: em.code, url: TWITCH_BASE + em.id + "/1.0"}); + emotes.push({regex: em.code, url: utils.TWITCH_BASE + em.id + "/1.0"}); } if ( f._cindex ) @@ -893,7 +845,7 @@ FFZ.prototype.tokenize_emotes = function(user, room, tokens, do_report) { bits.push(eo); if ( do_report && room ) - f.add_usage(room, emote.id); + f.add_usage(room, emote); } else bits.push(bit); diff --git a/src/ui/dark.js b/src/ui/dark.js index 3c7f5260..3a515933 100644 --- a/src/ui/dark.js +++ b/src/ui/dark.js @@ -144,6 +144,9 @@ FFZ.settings_info.dark_twitch = { model && model.set('darkMode', true); } else model && model.set('darkMode', this.settings.twitch_chat_dark); + + // Try coloring ReChat + jQuery('.rechat-chat-line').parents('.chat-container').toggleClass('dark', val || this.settings.twitch_chat_dark); } }; diff --git a/src/ui/following-count.js b/src/ui/following-count.js index c4ec99be..43da8b50 100644 --- a/src/ui/following-count.js +++ b/src/ui/following-count.js @@ -52,7 +52,7 @@ FFZ.prototype.setup_following_count = function(has_ember) { // If we don't have Ember, no point in trying this stuff. if ( ! has_ember ) - return this._update_following_count(); + return this._following_get_me(); this.log("Connecting to Live Streams model."); var Stream = window.App && App.__container__.resolve('model:stream'); @@ -80,6 +80,27 @@ FFZ.prototype.setup_following_count = function(has_ember) { } +FFZ.prototype._following_get_me = function(tries) { + // get_user doesn't properly return an oauth token any longer, so we need to get me manually. + if ( ! window.Twitch ) + // Wait around till the API shows up. + return setTimeout(this._following_get_me.bind(this, tries), Math.floor(2000*Math.random()) + 500); + + var f = this; + Twitch.api.get("/api/me").done(function(data) { + f.log("Fetched User Data -- " + (data.name || data.login)); + f.__user = data; + f._update_following_count(); + + }).fail(function() { + tries = (tries||0) + 1; + if ( tries < 5 ) + return setTimeout(f._following_get_me.bind(f, tries), Math.floor(2000*Math.random()) + 500); + f.log("Failed to get proper user object."); + }); +} + + FFZ.prototype._schedule_following_count = function() { if ( ! this.settings.following_count ) { if ( this._following_count_timer ) { @@ -111,8 +132,13 @@ FFZ.prototype._update_following_count = function() { if ( Live ) Live.load(); - else - Twitch.api && Twitch.api.get("streams/followed", {limit:5, offset:0}, {version:3}) + else { + var a = {}, + u = this.get_user(); + + a.Authorization = "OAuth " + u.chat_oauth_token; + + Twitch.api && Twitch.api.get("streams/followed", {limit:20, offset:0}, {version:3, headers: a}) .done(function(data) { f._draw_following_count(data._total); f._draw_following_channels(data.streams, data._total); @@ -120,6 +146,7 @@ FFZ.prototype._update_following_count = function() { f._draw_following_count(); f._draw_following_channels(); }) + } } diff --git a/src/ui/menu.js b/src/ui/menu.js index ff29cf0d..9a38f083 100644 --- a/src/ui/menu.js +++ b/src/ui/menu.js @@ -2,8 +2,6 @@ var FFZ = window.FrankerFaceZ, constants = require('../constants'), utils = require('../utils'), - TWITCH_BASE = "http://static-cdn.jtvnw.net/emoticons/v1/", - fix_menu_position = function(container) { var swapped = document.body.classList.contains('ffz-sidebar-swap') && ! document.body.classList.contains('ffz-portrait'); @@ -63,7 +61,8 @@ FFZ.prototype.setup_menu = function() { this.log("Hooking the Ember Chat Settings view."); - var Settings = window.App && App.__container__.resolve('view:settings'); + var Settings = window.App && App.__container__.resolve('view:settings'), + Layout = App.__container__.lookup('controller:layout'); if ( ! Settings ) return; @@ -155,6 +154,12 @@ FFZ.prototype.setup_menu = function() { menu.appendChild(header); menu.appendChild(content); + + // Maximum Height + var e = el.querySelector('.chat-settings'); + if ( Layout && e ) + e.style.maxHeight = (Layout.get('windowHeight') - 90) + 'px'; + }, ffzTeardown: function() { @@ -162,6 +167,15 @@ FFZ.prototype.setup_menu = function() { } }); + // Maximum height~! + if ( Layout ) + Layout.addObserver('windowHeight', function() { + var el = document.querySelector('.ember-chat .chat-settings'); + if ( el ) + el.style.maxHeight = (Layout.get('windowHeight') - 90) + 'px'; + }); + + // For some reason, this doesn't work unless we create an instance of the // chat settings view and then destroy it immediately. try { @@ -225,7 +239,7 @@ FFZ.prototype.build_ui_popup = function(view) { container.classList.toggle('dark', dark); // Stuff - jQuery(inner).find('.html-tooltip').tipsy({live: true, html: true, gravity: jQuery.fn.tipsy.autoNS}); + jQuery(inner).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')}); // Menu Container @@ -316,7 +330,7 @@ FFZ.prototype.build_ui_popup = function(view) { link.title = page.name; link.innerHTML = page.icon; - jQuery(link).tipsy(); + jQuery(link).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); link.addEventListener("click", this._ui_change_page.bind(this, view, inner, menu, sub_container, key)); @@ -438,11 +452,11 @@ FFZ.menu_pages.channel = { var s = document.createElement('span'), can_use = is_subscribed || !emote.subscriber_only, - img_set = 'image-set(url("' + TWITCH_BASE + emote.id + '/1.0") 1x, url("' + TWITCH_BASE + emote.id + '/2.0") 2x, url("' + TWITCH_BASE + emote.id + '/3.0") 4x)'; + img_set = 'image-set(url("' + constants.TWITCH_BASE + emote.id + '/1.0") 1x, url("' + constants.TWITCH_BASE + emote.id + '/2.0") 2x), url("' + constants.TWITCH_BASE + emote.id + '/3.0") 4x)'; - s.className = 'emoticon tooltip' + (!can_use ? " locked" : ""); + s.className = 'emoticon html-tooltip' + (!can_use ? " locked" : ""); - s.style.backgroundImage = 'url("' + TWITCH_BASE + emote.id + '/1.0")'; + s.style.backgroundImage = 'url("' + constants.TWITCH_BASE + emote.id + '/1.0")'; s.style.backgroundImage = '-webkit-' + img_set; s.style.backgroundImage = '-moz-' + img_set; s.style.backgroundImage = '-ms-' + img_set; @@ -450,7 +464,7 @@ FFZ.menu_pages.channel = { s.style.width = emote.width + "px"; s.style.height = emote.height + "px"; - s.title = emote.regex; + s.title = (this.settings.emote_image_hover ? '' : '') + emote.regex; s.addEventListener('click', function(can_use, id, code, e) { if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons ) diff --git a/src/ui/my_emotes.js b/src/ui/my_emotes.js index 9d12f761..36954713 100644 --- a/src/ui/my_emotes.js +++ b/src/ui/my_emotes.js @@ -2,7 +2,6 @@ var FFZ = window.FrankerFaceZ, constants = require("../constants"), utils = require("../utils"), - TWITCH_BASE = "http://static-cdn.jtvnw.net/emoticons/v1/", BANNED_SETS = {"00000turbo":true}; @@ -166,11 +165,14 @@ FFZ.menu_pages.myemotes = { if ( (settings === 1 && ! emoji.tw) || (settings === 2 && ! emoji.noto) ) continue; - em.className = 'emoticon html-tooltip'; - em.title = 'Emoji: ' + emoji.raw + '\nName: ' + emoji.name + (emoji.short_name ? '\nShort Name: :' + emoji.short_name + ':' : ''); + var src = settings === 2 ? emoji.noto_src : emoji.tw_src, + image = this.settings.emote_image_hover ? '' : ''; + + em.className = 'emoticon emoji html-tooltip'; + em.title = image + 'Emoji: ' + emoji.raw + '
Name: ' + emoji.name + (emoji.short_name ? '
Short Name: :' + emoji.short_name + ':' : ''); em.addEventListener('click', this._add_emote.bind(this, view, emoji.raw)); - em.style.backgroundImage = 'url("' + (settings === 2 ? emoji.noto_src : emoji.tw_src) + '")'; + em.style.backgroundImage = 'url("' + src + '")'; em.style.backgroundSize = "18px"; menu.appendChild(em); @@ -237,21 +239,21 @@ FFZ.menu_pages.myemotes = { code = constants.KNOWN_CODES[emote.code] || emote.code, em = document.createElement('span'), - img_set = 'image-set(url("' + TWITCH_BASE + emote.id + '/1.0") 1x, url("' + TWITCH_BASE + emote.id + '/2.0") 2x, url("' + TWITCH_BASE + emote.id + '/3.0") 4x)'; + img_set = 'image-set(url("' + constants.TWITCH_BASE + emote.id + '/1.0") 1x, url("' + constants.TWITCH_BASE + emote.id + '/2.0") 2x, url("' + constants.TWITCH_BASE + emote.id + '/3.0") 4x)'; em.className = 'emoticon html-tooltip'; if ( this.settings.replace_bad_emotes && constants.EMOTE_REPLACEMENTS[emote.id] ) { em.style.backgroundImage = 'url("' + constants.EMOTE_REPLACEMENT_BASE + constants.EMOTE_REPLACEMENTS[emote.id] + '")'; } else { - em.style.backgroundImage = 'url("' + TWITCH_BASE + emote.id + '/1.0")'; + em.style.backgroundImage = 'url("' + constants.TWITCH_BASE + emote.id + '/1.0")'; em.style.backgroundImage = '-webkit-' + img_set; em.style.backgroundImage = '-moz-' + img_set; em.style.backgroundImage = '-ms-' + img_set; em.style.backgroudnImage = img_set; } - em.title = code; + em.title = (this.settings.emote_image_hover ? '' : '') + code; em.addEventListener("click", function(id, c, e) { e.preventDefault(); if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons ) diff --git a/src/ui/sub_count.js b/src/ui/sub_count.js index e8c85976..e2be80a5 100644 --- a/src/ui/sub_count.js +++ b/src/ui/sub_count.js @@ -84,7 +84,7 @@ FFZ.prototype._update_subscribers = function() { }); cont.appendChild(stat); - jQuery(stat).tipsy(f.is_dashboard ? {"gravity":"s"} : undefined); + jQuery(stat).tipsy({gravity: f.is_dashboard ? "s" : utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); } el.innerHTML = sub_count; diff --git a/src/ui/tooltips.js b/src/ui/tooltips.js new file mode 100644 index 00000000..5e2c27b0 --- /dev/null +++ b/src/ui/tooltips.js @@ -0,0 +1,38 @@ +var FFZ = window.FrankerFaceZ, + utils = require('../utils'), + constants = require('../constants'); + + +// --------------------- +// Initialization +// --------------------- + +FFZ.prototype.fix_tooltips = function() { + // First, override the tooltip mixin. + var TipsyTooltip = window.App && App.__container__.resolve('component:tipsy-tooltip'); + if ( TipsyTooltip ) { + this.log("Modifying Tipsy-Tooltip component to use gravity."); + TipsyTooltip.reopen({ + didInsertElement: function() { + var gravity = this.get("gravity"); + if ( ! gravity || typeof gravity === "string" ) + gravity = utils.tooltip_placement(constants.TOOLTIP_DISTANCE, gravity || 's'); + + this.$().tipsy({ + gravity: gravity + }); + } + }) + } + + // Iterate all existing tipsy stuff~! + this.log('Fixing already existing tooltips.'); + if ( ! window.jQuery || ! jQuery.cache ) + return; + + for(var obj_id in jQuery.cache) { + var obj = jQuery.cache[obj_id]; + if ( obj && obj.data && obj.data.tipsy && obj.data.tipsy.options && typeof obj.data.tipsy.options.gravity !== "function" ) + obj.data.tipsy.options.gravity = utils.tooltip_placement(constants.TOOLTIP_DISTANCE, obj.data.tipsy.options.gravity || 's'); + } +} \ No newline at end of file diff --git a/src/ui/viewer_count.js b/src/ui/viewer_count.js index 98d75edb..4227b078 100644 --- a/src/ui/viewer_count.js +++ b/src/ui/viewer_count.js @@ -66,6 +66,6 @@ FFZ.ws_commands.viewers = function(data) { view_count.innerHTML = content; parent.appendChild(view_count); - jQuery(view_count).tipsy(this.is_dashboard ? {"gravity":"s"} : undefined); + jQuery(view_count).tipsy({gravity: this.is_dashboard ? "s" : utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')}); } } \ No newline at end of file diff --git a/src/utils.js b/src/utils.js index b1cce141..364e8d05 100644 --- a/src/utils.js +++ b/src/utils.js @@ -182,10 +182,98 @@ var sanitize_el = document.createElement('span'), out = es[variant] = r.join("-"); return out; + }, + + // Twitch Emote Tooltips + + SRCSETS = {}, + build_srcset = function(id) { + if ( SRCSETS[id] ) + return SRCSETS[id]; + var out = SRCSETS[id] = constants.TWITCH_BASE + id + "/1.0 1x, " + constants.TWITCH_BASE + id + "/2.0 2x, " + constants.TWITCH_BASE + id + "/3.0 4x"; + return out; + }, + + + data_to_tooltip = function(data) { + var emote_set = data.set, + set_type = data.set_type, + + f = FFZ.get(), + image = ''; + + if ( data.id && f.settings.emote_image_hover ) + image = ''; + + if ( set_type === undefined ) + set_type = "Channel"; + + if ( ! emote_set ) + return image + data.code; + + else if ( emote_set === "--global--" ) { + emote_set = "Twitch Global"; + set_type = null; + + } else if ( emote_set == "--twitch-turbo--" || emote_set == "turbo" || emote_set == "--turbo-faces--" ) { + emote_set = "Twitch Turbo"; + set_type = null; + } + + return image + "Emoticon: " + data.code + "
" + (set_type ? set_type + ": " : "") + emote_set; + }, + + build_tooltip = function(id, force_update, code) { + var emote_data = this._twitch_emotes[id]; + + if ( ! emote_data && code ) { + var set_id = this._twitch_emote_to_set[id]; + if ( set_id ) { + emote_data = this._twitch_emotes[id] = { + code: code, + id: id, + set: this._twitch_set_to_channel[set_id], + set_id: set_id + } + } + } + + if ( ! emote_data ) + return "???"; + + if ( typeof emote_data == "string" ) + return emote_data; + + if ( ! force_update && emote_data.tooltip ) + return emote_data.tooltip; + + return emote_data.tooltip = data_to_tooltip(emote_data); + }, + + load_emote_data = function(id, code, success, data) { + if ( ! success ) + return code; + + if ( code ) + data.code = code; + + this._twitch_emotes[id] = data; + var tooltip = build_tooltip.bind(this)(id); + + var images = document.querySelectorAll('img[data-emote="' + id + '"]'); + for(var x=0; x < images.length; x++) + images[x].title = tooltip; + + return tooltip; }; module.exports = { + build_srcset: build_srcset, + build_tooltip: build_tooltip, + load_emote_data: load_emote_data, + + update_css: function(element, id, css) { var all = element.innerHTML, start = "/*BEGIN " + id + "*/", @@ -207,6 +295,25 @@ module.exports = { }, + tooltip_placement: function(margin, prefer) { + return function() { + var dir = {ns: prefer[0], ew: (prefer.length > 1 ? prefer[1] : false)}, + $this = $(this), + half_width = $this.width() / 2, + half_height = $this.height() / 2, + boundTop = $(document).scrollTop() + half_height + (margin*2), + boundLeft = $(document).scrollLeft() + half_width + margin; + + if ($this.offset().top < boundTop) dir.ns = 'n'; + if ($this.offset().left < boundLeft) dir.ew = 'w'; + if ($(window).width() + $(document).scrollLeft() - ($this.offset().left + half_width) < margin) dir.ew = 'e'; + if ($(window).height() + $(document).scrollTop() - ($this.offset().top + half_height) < (2*margin)) dir.ns = 's'; + + return dir.ns + (dir.ew ? dir.ew : ''); + } + }, + + splitIRCMessage: splitIRCMessage, parseIRCTags: parseIRCTags, diff --git a/style.css b/style.css index 0a3af431..651bf347 100644 --- a/style.css +++ b/style.css @@ -21,20 +21,20 @@ body > div.tipsy .tipsy-arrow { opacity: 0.8; } .ffz-hide-recent-past-broadcast .recent-past-broadcast, .ffz-hide-view-count .stat.twitch-channel-views, -.ffz-minimal-chat-input .emoticon-selector-toggle, -.ffz-menu-replace .emoticon-selector-toggle { +.ffz-minimal-chat-input .chat-interface .emoticon-selector-toggle, +.ffz-menu-replace .chat-interface .emoticon-selector-toggle { display: none !important; } -body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + .ffz-ui-toggle svg, -body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + script + .ffz-ui-toggle svg +body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + .ffz-ui-toggle svg, +body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + script + .ffz-ui-toggle svg { height: 14px; width: 18px; } -body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + .ffz-ui-toggle, -body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + script + .ffz-ui-toggle { +body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + .ffz-ui-toggle, +body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + script + .ffz-ui-toggle { height: 14px; width: 18px; top: 28px; @@ -263,6 +263,11 @@ body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-togg margin-bottom: 30px; } +.ffz-theater-stats .app-main.theatre #channel .player-column:focus .archive_info + .stats-and-actions, +.ffz-theater-stats .app-main.theatre #channel .player-column:hover .archive_info + .stats-and-actions { + display: none; +} + .ffz-theater-stats .app-main.theatre .player-column:focus #hostmode > div.clearfix, .ffz-theater-stats .app-main.theatre .player-column:hover #hostmode > div.clearfix, .ffz-theater-stats .app-main.theatre .player-column:focus .stats-and-actions, @@ -898,8 +903,17 @@ span.ffz-handle:after { left: 8px } .ffz-ui-popup.dark .ffz-ui-menu-page { background-color: #1e1e1e; } +/* Positioning Fixes */ + +body:not(.ffz-bttv) .ember-chat .chat-settings { bottom: 40px; } +body:not(.ffz-bttv) .notification-controls .notify-menu { bottom: 25px; } +body:not(.ffz-bttv) .dropmenu.share { margin-bottom: 0; } + + /* Menu Scrollbar */ +.ffz-scrollbar::-webkit-scrollbar, +.ember-chat .chat-settings::-webkit-scrollbar, .conversations-list .conversations-list-inner::-webkit-scrollbar, .conversation-window .conversation-content::-webkit-scrollbar, .chat-history::-webkit-scrollbar, @@ -910,6 +924,8 @@ span.ffz-handle:after { left: 8px } width: 6px; } +.ffz-scrollbar::-webkit-scrollbar-thumb, +.ember-chat .chat-settings::-webkit-scrollbar-thumb, .conversations-list .conversations-list-inner::-webkit-scrollbar-thumb, .conversation-window .conversation-content::-webkit-scrollbar-thumb, .chat-history::-webkit-scrollbar-thumb, @@ -922,10 +938,14 @@ span.ffz-handle:after { left: 8px } box-shadow: 0 0 1px 1px rgba(255,255,255,0.25); } +.ffz-dark .ffz-scrollbar::-webkit-scrollbar-thumb, .ffz-dark .table::-webkit-scrollbar-thumb, .ffz-dark .conversation-window .conversation-content::-webkit-scrollbar-thumb, .ffz-dark .conversations-list .conversations-list-inner::-webkit-scrollbar-thumb, +.ffz-dark .conversation-input-bar .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, +.theatre .ffz-scrollbar::-webkit-scrollbar-thumb, +.theatre .ember-chat .chat-settings::-webkit-scrollbar-thumb, .theatre .conversation-window .conversation-content::-webkit-scrollbar-thumb, .theatre .conversations-list .conversations-list-inner::-webkit-scrollbar-thumb, @@ -934,11 +954,15 @@ span.ffz-handle:after { left: 8px } .theatre .ffz-ui-menu-page::-webkit-scrollbar-thumb, .theatre .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb +.dark .ffz-scrollbar::-webkit-scrollbar-thumb, +.dark .ember-chat .chat-settings::-webkit-scrollbar-thumb, .dark .chat-history::-webkit-scrollbar-thumb, .dark .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, .dark .ffz-ui-menu-page::-webkit-scrollbar-thumb, .dark .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb, +.force-dark .ffz-scrollbar::-webkit-scrollbar-thumb, +.force-dark .ember-chat .chat-settings::-webkit-scrollbar-thumb, .force-dark .chat-history::-webkit-scrollbar-thumb, .force-dark .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb, .force-dark .ffz-ui-menu-page::-webkit-scrollbar-thumb, @@ -954,7 +978,6 @@ img.channel_background[src="null"] { display: none; } .ffz-moderation-card { border: 2px solid #cbcbcb; max-width: 340px; - /*box-shadow: #808080 0 0 5px;*/ } .ffz-moderation-card .extra-interface { @@ -967,6 +990,7 @@ img.channel_background[src="null"] { display: none; } .ffz-moderation-card.ffz-has-info h3.name { margin-top: 0; + white-space: nowrap; } .ffz-moderation-card .info { @@ -1073,7 +1097,7 @@ img.channel_background[src="null"] { display: none; } } .mod-icons .custom { - text-indent: 0; + text-indent: 0 !important; text-align: center; text-decoration: none; font-size: 18px; @@ -1106,7 +1130,7 @@ img.channel_background[src="null"] { display: none; } text-decoration: none; } -.more-messages-indicator { +body:not(.ffz-bttv) .more-messages-indicator { /* This looks better when it's full width. */ margin: 0 -20px; } @@ -2047,6 +2071,8 @@ li[data-name="following"] a { /* Conversations */ +.conversation-chat-line.action .colon, +.conversation-input-bar .emoticon-selector .tabs, .conversation-preview-line .badges, body.ffz-conv-title-clickable .conversation-header span.conversation-header-name, body:not(.ffz-conv-title-clickable) .conversation-header a.conversation-header-name { display:none }