From 2f7dc1d8d3a82ff612ad26952c651439db260b6e Mon Sep 17 00:00:00 2001 From: SirStendec Date: Sun, 5 Jun 2016 22:12:54 -0400 Subject: [PATCH] 3.5.203. Improved styling for balloon elements in dark theme. Support the new badge system. Add support for hiding badges. Add support for hiding badges when BetterTTV is present. Remove silly duplicate code from channel.js. Fix the Chat button showing a silly message when you're perma-banned. --- dark.css | 14 +- src/badges.js | 283 +++++++++++++++++++++------ src/ember/channel.js | 5 - src/ember/conversations.js | 30 +-- src/ember/line.js | 25 ++- src/ember/room.js | 5 +- src/main.js | 2 +- src/styles/badges-blank.css | 2 +- src/styles/badges-circular-small.css | 2 +- src/styles/badges-circular.css | 2 +- src/styles/badges-rounded.css | 2 +- src/tokenize.js | 3 + src/utils.js | 29 +++ style.css | 76 +++++++ 14 files changed, 396 insertions(+), 84 deletions(-) diff --git a/dark.css b/dark.css index eb1d67ed..e2081742 100644 --- a/dark.css +++ b/dark.css @@ -200,10 +200,19 @@ body.ffz-dark:not([data-page="teams#show"]), box-shadow: rgba(255,255,255,0.2) 0 0 0 1px inset; } +.ffz-dark #flyout .content, +.ffz-dark .ffz-ui-popup.emoticon-selector .emoticon-selector-box { border: none } + +.ffz-dark .balloon--up:after { box-shadow: 1px 1px 0 rgba(255,255,255,0.2) } +.ffz-dark .balloon--down:after { box-shadow: -1px -1px 0 rgba(255,255,255,0.2) } +.ffz-dark .balloon--left:after { box-shadow: 1px -1px 0 rgba(255,255,255,0.2) } +.ffz-dark .balloon--right:after { box-shadow: -1px 1px 0 rgba(255,255,255,0.2) } + + .ffz-dark .player-menu__header { color: #c3c3c3 } .ffz-dark .player-menu__section { border-bottom-color: rgba(255,255,255,0.2) } -.ffz-dark .balloon:after { box-shadow: none } +/*.ffz-dark .balloon:after { box-shadow: none }*/ .ffz-dark .st-autocomplete-sidebar .label, .ffz-dark .st-autocomplete-small .label, @@ -287,6 +296,9 @@ body.ffz-dark:not([data-page="teams#show"]), color: #8c8c9c; } +.ffz-dark .balloon .balloon__link { color: #a68ed2 !important } +.ffz-dark .balloon .balloon__link:hover { color: #fff !important } + .ffz-dark .st-autocomplete-sidebar .all p:not(.active), .ffz-dark .st-autocomplete-small .all p:not(.active), .ffz-dark .st-autocomplete .all p:not(.active), diff --git a/src/badges.js b/src/badges.js index 6490abfe..dcdc2fa1 100644 --- a/src/badges.js +++ b/src/badges.js @@ -2,16 +2,36 @@ var FFZ = window.FrankerFaceZ, constants = require('./constants'), utils = require('./utils'), - SPECIAL_BADGES = [ - ['staff', 'staff', 'Staff'], - ['admin', 'admin', 'Admin'], - ['global_mod', 'global-moderator', 'Global Moderator'] - ], + SPECIAL_BADGES = ['staff', 'admin', 'global_mod'], + OTHER_KNOWN = ['turbo', 'warcraft'], - badge_css = function(badge) { - var out = ".badges .ffz-badge-" + badge.id + " { background-color: " + badge.color + '; background-image: url("' + badge.image + '"); ' + (badge.css || "") + '}'; + BTTV_TYPE_REPLACEMENTS = { + 'global-moderator': 'global_mod' + }, + + BADGE_POSITIONS = { + 'broadcaster': 0, + 'staff': 0, + 'admin': 0, + 'global_mod': 0, + 'mod': 1, + 'moderator': 1, + 'subscriber': 10, + }, + + BADGE_NAMES = { + 'global_mod': 'Global Moderator' + }, + + BADGE_KLASSES = { + 'global_mod': 'global-moderator' + }, + + badge_css = function(badge, klass) { + klass = klass || ('ffz-badge-' + badge.id); + var out = ".badges ." + klass + " { background-color: " + badge.color + '; background-image: url("' + badge.image + '"); ' + (badge.css || "") + '}'; if ( badge.alpha_image ) - out += ".badges .badge.alpha.ffz-badge-" + badge.id + ",.ffz-transparent-badges .badges .ffz-badge-" + badge.id + ' { background-image: url("' + badge.alpha_image + '"); }'; + out += ".badges .badge.alpha." + klass + ",.ffz-transparent-badges .badges ." + klass + ' { background-image: url("' + badge.alpha_image + '"); }'; return out; }; @@ -27,7 +47,80 @@ FFZ.settings_info.show_badges = { category: "Chat Appearance", name: "Additional Badges", help: "Show additional badges for bots, FrankerFaceZ donors, and other special users." - }; +}; + + +FFZ.settings_info.hidden_badges = { + type: "button", + value: [], + + category: "Chat Appearance", + name: "Hidden Badges", + help: "Any badges added to this list will not be displayed in chat.", + + on_update: function(val) { + if ( this.has_bttv ) + return; + + var controller = utils.ember_lookup('controller:chat'), + messages = controller && controller.get('currentRoom.messages'); + + if ( ! messages ) + return; + + for(var i=0; i < messages.length; i++) + messages[i]._line && messages[i]._line.ffzUpdateBadges(); + }, + + method: function() { + var f = this, + service = utils.ember_lookup('service:badges'), + badgeCollection = service && service.badgeCollection, + old_val = f.settings.hidden_badges.join(", "), + values = []; + + if ( badgeCollection ) { + if ( badgeCollection.global ) + for(var badge in badgeCollection.global) + if ( badgeCollection.global.hasOwnProperty(badge) && badge !== 'broadcasterName' ) + values.push('' + badge + ''); + + if ( badgeCollection.channel ) + for(var badge in badgeCollection.channel) + if ( badgeCollection.channel.hasOwnProperty(badge) && badge !== 'broadcasterName' ) + values.push('' + badge + ''); + } + + for(var badge_id in f.badges) { + if ( f.badges.hasOwnProperty(badge_id) && f.badges[badge_id].name ) + values.push('ffz-' + f.badges[badge_id].name + ''); + } + + if ( this.has_bttv && window.BetterTTV ) { + try { + for(var badge_id in BetterTTV.chat.store.__badgeTypes) + values.push('bttv-' + badge_id + ''); + + values.push('bot'); + + } catch(err) { + this.error("Unable to load known BetterTTV badges.", err); + } + } + + utils.prompt( + "Hidden Badges", + "Please enter a comma-separated list of badges that you would like to be hidden in chat.

Possible Values: " + _.unique(values).join(", "), + old_val, + function(new_val) { + if ( new_val === null || new_val === undefined ) + return; + + f.settings.set("hidden_badges", _.unique(new_val.trim().toLowerCase().split(/\s*,\s*/))); + }, 600 + ) + } +}; FFZ.settings_info.sub_notice_badges = { @@ -39,10 +132,10 @@ FFZ.settings_info.sub_notice_badges = { help: "Display a subscriber badge on chat messages about new subscribers.", on_update: function(val) { - this.toggle_style('badges-sub-notice', ! val); - this.toggle_style('badges-sub-notice-on', val); - } - }; + this.toggle_style('badges-sub-notice', ! val); + this.toggle_style('badges-sub-notice-on', val); + } +}; FFZ.settings_info.legacy_badges = { @@ -71,11 +164,11 @@ FFZ.settings_info.legacy_badges = { }, on_update: function(val) { - this.toggle_style('badges-legacy', val === 3); - this.toggle_style('badges-legacy-mod', val !== 0); - this.toggle_style('badges-legacy-turbo', val > 1); - } - }; + this.toggle_style('badges-legacy', val === 3); + this.toggle_style('badges-legacy-mod', val !== 0); + this.toggle_style('badges-legacy-turbo', val > 1); + } +}; FFZ.settings_info.transparent_badges = { @@ -108,17 +201,17 @@ FFZ.settings_info.transparent_badges = { }, on_update: function(val) { - if ( this.has_bttv ) - return; + if ( this.has_bttv ) + return; - 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-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); + document.body.classList.toggle('ffz-transparent-badges', val === 5); + } +}; // -------------------- @@ -187,7 +280,9 @@ FFZ.ws_commands.set_badge = function(data) { // -------------------- FFZ.prototype.get_badges = function(user, room_id, badges, msg) { - var data = this.users[user]; + var data = this.users[user], + hidden_badges = this.settings.hidden_badges; + if ( ! data || ! data.badges || ! this.settings.show_badges ) return badges; @@ -199,6 +294,9 @@ FFZ.prototype.get_badges = function(user, room_id, badges, msg) { full_badge = this.badges[badge.id] || {}, old_badge = badges[slot]; + if ( hidden_badges.indexOf('ffz-' + full_badge.name) !== -1 ) + continue; + if ( full_badge.visible !== undefined ) { var visible = full_badge.visible; if ( typeof visible === "function" ) @@ -223,6 +321,7 @@ FFZ.prototype.get_badges = function(user, room_id, badges, msg) { klass: 'ffz-badge-' + badge.id, title: badge.title || full_badge.title, image: badge.image, + full_image: full_badge.image, color: badge.color, extra_css: badge.extra_css }; @@ -234,30 +333,77 @@ FFZ.prototype.get_badges = function(user, room_id, badges, msg) { FFZ.prototype.get_line_badges = function(msg) { var badges = {}, + hidden_badges = this.settings.hidden_badges, + + last_id = -1, + had_last = false, room = msg.get && msg.get('room') || msg.room, from = msg.get && msg.get('from') || msg.from, tags = msg.get && msg.get('tags') || msg.tags || {}, - labels = msg.labels || []; + badge_tag = tags.badges || {}, - if ( room && from === room ) - badges[0] = {klass: 'broadcaster', title: 'Broadcaster'}; - else { - for(var i=0, l = SPECIAL_BADGES.length; i < l; i++) { - var mb = SPECIAL_BADGES[i]; - if ( tags['user-type'] === mb[0] || labels.indexOf(mb[0]) !== -1 ) { - badges[0] = {klass: mb[1], title: mb[2]} - break; - } - } + service = utils.ember_lookup('service:badges'), + badgeCollection = service && service.badgeCollection, - if ( tags.mod || labels.indexOf('mod') !== -1 ) - badges[1] = {klass: 'moderator', title: 'Moderator'}; - } + globals = badgeCollection && badgeCollection.global || {}, + channel = badgeCollection && badgeCollection.channel || {}; - if ( tags.subscriber || labels.indexOf('subscriber') !== -1 ) - badges[10] = {klass: 'subscriber', title: 'Subscriber'} - if ( tags.turbo || labels.indexOf('turbo') !== -1 ) - badges[15] = {klass: 'turbo', title: 'Turbo'}; + // VoD Chat lines don't have the badges pre-parsed for some reason. + if ( typeof badge_tag === 'string' ) { + var val = badge_tag.split(','); + badge_tag = {}; + for(var i=0; i < val.length; i++) { + var parts = val[i].split('/'); + if ( parts.length === 2 ) + badge_tag[parts[0]] = parts[1]; + } + } + + for(var badge in badge_tag) { + var version = badge_tag[badge]; + if ( ! badge_tag.hasOwnProperty(badge) || ! version ) + continue; + + var versions = channel[badge] || globals[badge], + binfo = versions && versions.versions && versions.versions[version]; + + if ( from === 'sirstendec' && badge === 'turbo' && globals.warcraft ) { + badge = 'warcraft'; + version = 'protoss'; + binfo = { + click_action: 'visit_url', + click_url: 'https://www.youtube.com/watch?v=dpBM2FIHprM', + description: 'My life for Aiur!', + title: 'Protoss', + image_url_1x: 'https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/1.png', + image_url_2x: 'https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/2.png', + image_url_3x: 'https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/4.png' + } + } + + if ( hidden_badges.indexOf(badge) !== -1 ) + continue; + + if ( BADGE_POSITIONS.hasOwnProperty(badge) ) + last_id = BADGE_POSITIONS[badge]; + else { + last_id = had_last ? last_id + 1 : 15; + had_last = true; + } + + var is_known = BADGE_POSITIONS.hasOwnProperty(badge) || OTHER_KNOWN.indexOf(badge) !== -1; + + badges[last_id] = { + klass: (BADGE_KLASSES[badge] || badge) + (is_known ? '' : ' unknown-badge') + ' version-' + version, + title: binfo && binfo.title || BADGE_NAMES[badge] || badge.capitalize(), + click_url: binfo && binfo.click_action === 'visit_url' && binfo.click_url + }; + + if ( ! is_known && binfo ) { + badges[last_id].image = binfo.image_url_1x; + badges[last_id].srcSet = 'url("' + binfo.image_url_1x + '") 1x, url("' + binfo.image_url_2x + '") 2x, url("' + binfo.image_url_3x + '") 4x'; + } + } // FFZ Badges return this.get_badges(from, room, badges, msg); @@ -272,8 +418,8 @@ FFZ.prototype.get_other_badges = function(user_id, room_id, user_type, has_sub, else for(var i=0, l = SPECIAL_BADGES.length; i < l; i++) { var mb = SPECIAL_BADGES[i]; - if ( user_type === mb[0] ) { - badges[0] = {klass: mb[1], title: mb[2]}; + if ( user_type === mb ) { + badges[0] = {klass: BADGE_KLASSES[mb] || mb, title: BADGE_TITLES[mb] || mb.capitalize()}; break; } } @@ -295,15 +441,22 @@ FFZ.prototype.render_badges = function(badges) { var out = []; for(var key in badges) { var badge = badges[key], + klass = badge.klass, css = badge.image ? 'background-image:url("' + utils.quote_attr(badge.image) + '");' : ''; + if ( badge.srcSet ) + css += 'background-image:-webkit-image-set(' + badge.srcSet + ');background-image:image-set(' + badge.srcSet + ');' + if ( badge.color ) css += 'background-color:' + badge.color + ';' if ( badge.extra_css ) css += badge.extra_css; - out.push('

'); + if ( badge.click_url ) + klass += ' click_url'; + + out.push('
'); } return out.join(""); @@ -322,23 +475,38 @@ FFZ.prototype.bttv_badges = function(data) { user = this.users[user_id], badges_out = [], insert_at = -1, + + hidden_badges = this.settings.hidden_badges, alpha = BetterTTV.settings.get('alphaTags'); - if ( ! user || ! user.badges ) - return; if ( ! data.badges ) data.badges = []; // Determine where in the list to insert these badges. + // Also, strip out banned badges while we're at it. for(var i=0; i < data.badges.length; i++) { - var badge = data.badges[i]; - if ( badge.type == "subscriber" || badge.type == "turbo" ) { + var badge = data.badges[i], + space_ind = badge.type.indexOf(' '), + hidden_key = BTTV_TYPE_REPLACEMENTS[badge.type] || (space_ind === -1 ? badge.type : badge.type.substr(0, space_ind)); + + if ( hidden_badges.indexOf(hidden_key) !== -1 ) { + data.badges.splice(i, 1); + continue; + } + + if ( badge.type === "subscriber" || badge.type === "turbo" || badge.type.substr(0, 8) === 'warcraft' ) { insert_at = i; break; } } + // If there's no user, we're done now. + if ( ! user || ! user.badges ) + return; + + + // We have a user. Start replacing badges. for (var slot in user.badges) { if ( ! user.badges.hasOwnProperty(slot) ) continue; @@ -348,9 +516,12 @@ FFZ.prototype.bttv_badges = function(data) { desc = badge.title || full_badge.title, style = ""; + if ( hidden_badges.indexOf('ffz-' + full_badge.name) !== -1 ) + continue; + if ( full_badge.visible !== undefined ) { var visible = full_badge.visible; - if ( typeof visible == "function" ) + if ( typeof visible === "function" ) visible = visible.call(this, null, user_id); if ( ! visible ) @@ -400,6 +571,8 @@ FFZ.prototype.bttv_badges = function(data) { while(badges_out.length) data.badges.insertAt(insert_at, badges_out.shift()[1]); } + + } diff --git a/src/ember/channel.js b/src/ember/channel.js index e5ad0e10..56b0168d 100644 --- a/src/ember/channel.js +++ b/src/ember/channel.js @@ -18,11 +18,6 @@ FFZ.prototype.setup_channel = function() { document.body.classList.toggle("ffz-hide-view-count", !this.settings.channel_views); document.body.classList.toggle('ffz-theater-stats', this.settings.theater_stats); - this.log("Creating channel style element."); - var s = this._channel_style = document.createElement('style'); - s.id = "ffz-channel-css"; - document.head.appendChild(s); - this.log("Hooking the Ember Channel Index view."); var Channel = utils.ember_resolve('view:channel/index'), f = this; diff --git a/src/ember/conversations.js b/src/ember/conversations.js index 81daef62..8d879f7c 100644 --- a/src/ember/conversations.js +++ b/src/ember/conversations.js @@ -138,22 +138,22 @@ FFZ.prototype._modify_conversation_window = function(component) { component.reopen({ headerBadges: Ember.computed("thread.participants", "currentUsername", function() { - var e = this.get("otherUser"), - badges = f.get_other_badges(e.get('username'), null, e.get('userType'), false, e.get('hasTurbo')), - out = []; - - // It wants slightly different output from us. - for(var slot in badges) { - var badge = badges[slot]; - out.push({ - classes: 'badge ' + badge.klass, - title: badge.title - }); - } - - return out; + return []; }), + ffzHeaderBadges: Ember.computed("thread.participants", "currentUsername", function() { + var e = this.get("otherUser"); + return f.get_other_badges(e.get('username'), null, e.get('userType'), false, e.get('hasTurbo')); + }), + + ffzReplaceBadges: function() { + var el = this.get('element'), + badge_el = el && el.querySelector('.badges'), + badges = this.get('ffzHeaderBadges'); + + badge_el.innerHTML = f.render_badges(badges); + }.observes('ffzHeaderBadges'), + didInsertElement: function() { var el = this.get('element'), header = el && el.querySelector('.conversation-header'), @@ -164,6 +164,8 @@ FFZ.prototype._modify_conversation_window = function(component) { is_dark = (Layout && Layout.get('isTheatreMode')) || f.settings.dark_twitch; + this.ffzReplaceBadges(); + if ( header_name && raw_color ) { header_name.style.color = (is_dark ? colors[1] : colors[0]); header_name.classList.add('has-color'); diff --git a/src/ember/line.js b/src/ember/line.js index 436b2f96..10217bb2 100644 --- a/src/ember/line.js +++ b/src/ember/line.js @@ -662,6 +662,10 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) { this.$(".deleted,.message").replaceWith(this.buildMessageHTML()); }), + ffzUpdateBadges: function() { + this.$(".badges").html(f.render_badges(f.get_line_badges(this.get('msgObject')))); + }, + ffzUserLevel: function() { if ( this.get('isStaff') ) return 5; @@ -755,7 +759,7 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) { output += this.buildModIconsHTML(); // Badges - output += '' + f.render_badges(f.get_line_badges(this.get('msgObject'), is_whisper)) + ''; + output += '' + f.render_badges(f.get_line_badges(this.get('msgObject'))) + ''; // Alias Support var alias = f.aliases[user], @@ -915,7 +919,10 @@ FFZ.prototype._modify_chat_subline = function(component) { this.sendAction("timeoutUser", {user:from}); } else if ( cl.contains('badge') ) { - if ( cl.contains('turbo') ) + if ( cl.contains('click_url') ) + window.open(e.target.getAttribute('data-url'), "_blank"); + + else if ( cl.contains('turbo') ) window.open("/products/turbo?ref=chat_badge", "_blank"); else if ( cl.contains('subscriber') ) @@ -1015,7 +1022,19 @@ FFZ.prototype._modify_vod_line = function(component) { }, click: function(e) { - if ( e.target.classList.contains('delete') ) { + var cl = e.target.classList; + + if ( cl.contains('badge') ) { + if ( cl.contains('click_url') ) + window.open(e.target.getAttribute('data-url'), "_blank"); + + else if ( cl.contains('turbo') ) + window.open("/products/turbo?ref=chat_badge", "_blank"); + + else if ( cl.contains('subscriber') ) + this.sendAction("clickSubscriber"); + + } else if ( cl.contains('delete') ) { e.preventDefault(); this.sendAction("timeoutUser", this.get("msgObject.id")); } diff --git a/src/ember/room.js b/src/ember/room.js index 9388cf6b..db74e14b 100644 --- a/src/ember/room.js +++ b/src/ember/room.js @@ -995,7 +995,7 @@ FFZ.prototype._modify_room = function(room) { // If we were banned, set the state and update the UI. if ( is_me ) { t.set('ffz_banned', true); - if ( typeof duration === "number" && duration ) + if ( typeof duration === "number" && duration && isFinite(duration) && !isNaN(duration) ) t.updateWait(duration) else if ( duration ) { t.set('slowWait', 0); @@ -1308,6 +1308,9 @@ FFZ.prototype._modify_room = function(room) { if ( msg.from === 'twitchnotify' && msg.message.indexOf('subscribed to') === -1 && msg.message.indexOf('subscribed') !== -1 ) { if ( ! msg.tags ) msg.tags = {}; + if ( ! msg.tags.badges ) + msg.tags.badges = {}; + msg.tags.badges.subscriber = '1'; msg.tags.subscriber = true; if ( msg.labels && msg.labels.indexOf("subscriber") === -1 ) msg.labels.push("subscriber"); diff --git a/src/main.js b/src/main.js index aec9ce18..9a3e5e62 100644 --- a/src/main.js +++ b/src/main.js @@ -37,7 +37,7 @@ FFZ.msg_commands = {}; // Version var VER = FFZ.version_info = { - major: 3, minor: 5, revision: 196, + major: 3, minor: 5, revision: 203, toString: function() { return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || ""); } diff --git a/src/styles/badges-blank.css b/src/styles/badges-blank.css index 1709f1a8..3fec7ca8 100644 --- a/src/styles/badges-blank.css +++ b/src/styles/badges-blank.css @@ -1,3 +1,3 @@ -.badges .badge:not(.subscriber) { +.badges .badge:not(.subscriber):not(.unknown-badge) { 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 index ec67a3f5..d9eef701 100644 --- a/src/styles/badges-circular-small.css +++ b/src/styles/badges-circular-small.css @@ -1,4 +1,4 @@ -.badges .badge:not(.subscriber) { +.badges .badge:not(.subscriber):not(.unknown-badge) { height: 10px; min-width: 10px; margin: 5px 3px 5px 0; diff --git a/src/styles/badges-circular.css b/src/styles/badges-circular.css index 0cbc892c..166df5f7 100644 --- a/src/styles/badges-circular.css +++ b/src/styles/badges-circular.css @@ -1,4 +1,4 @@ -.badges .badge:not(.subscriber) { +.badges .badge:not(.subscriber):not(.unknown-badge) { border-radius: 9px; background-size: 16px; background-repeat: no-repeat; diff --git a/src/styles/badges-rounded.css b/src/styles/badges-rounded.css index 17c4826c..ba93158f 100644 --- a/src/styles/badges-rounded.css +++ b/src/styles/badges-rounded.css @@ -1,4 +1,4 @@ /* Rounded Badges */ -.badges .badge:not(.subscriber) { +.badges .badge:not(.subscriber):not(.unknown-badge) { border-radius: 2px; } \ No newline at end of file diff --git a/src/tokenize.js b/src/tokenize.js index 0be13ccd..14db7224 100644 --- a/src/tokenize.js +++ b/src/tokenize.js @@ -1139,6 +1139,9 @@ FFZ.prototype.parse_history = function(history, purged, room_id, delete_links, t if ( msg.tags && typeof msg.tags.emotes === "string" ) msg.tags.emotes = utils.uncompressEmotes(msg.tags.emotes); + if ( msg.tags && typeof msg.tags.badges === "string" ) + msg.tags.badges = utils.uncompressBadges(msg.tags.badges); + if ( ! msg.cachedTokens || ! msg.cachedTokens.length ) this.tokenize_chat_line(msg, true, delete_links); diff --git a/src/utils.js b/src/utils.js index f1ab59c4..02098620 100644 --- a/src/utils.js +++ b/src/utils.js @@ -76,6 +76,34 @@ var sanitize_el = document.createElement('span'), return new Date(unix); }, + BADGE_REV = { + 'b': 'broadcaster', + 's': 'staff', + 'a': 'admin', + 'g': 'global_mod', + 'm': 'moderator', + 'u': 'subscriber', + 't': 'turbo' + }, + + uncompressBadges = function(value) { + if ( value === true ) + return {}; + + var output = {}, + badges = value.split(","), + l = badges.length; + + for(var i=0; i < l; i++) { + var parts = badges[i].split('/'); + if ( parts.length !== 2 ) + return {}; + + output[BADGE_REV[parts[0]] || parts[0].substr(1)] = parts[1]; + } + + return output; + }, uncompressEmotes = function(value) { var output = {}, @@ -373,6 +401,7 @@ module.exports = FFZ.utils = { } }, + uncompressBadges: uncompressBadges, uncompressEmotes: uncompressEmotes, emoji_to_codepoint: emoji_to_codepoint, diff --git a/style.css b/style.css index e1b7538d..39434302 100644 --- a/style.css +++ b/style.css @@ -2910,3 +2910,79 @@ body.ffz-bttv #ffz-feed-tabs .tabs { margin-bottom: 0 } /* Chat Pane Overhaul */ .ember-chat.ffz-chat-pane .chat-messages { bottom: 0 } + +/* Hide Outlines */ + +.conversation-header, +.conversations-list-icon, +.toggle-notification-menu { + outline: none !important +} + + +/* Badges */ + +/*.badges .badge { + height: 18px; + min-width: 18px; + display: inline-block; + vertical-align: middle; + float: left; + margin: 1px 3px 1px 0 +} + +.badges .broadcaster { + background: #e71818 url(/images/xarth/badge_broadcaster.svg); + background-size: 100% +} + +.badges .turbo { + cursor: pointer; + background: #6441a5 url(/images/xarth/badge_turbo.svg); + background-size: 100% +} + +.badges .subscriber { + cursor: pointer +} + +.badges .staff { + background: #200f33 url(/images/xarth/badge_staff.svg); + background-size: 100% +} + +.badges .global-moderator { + background: #0c6f20 url(/images/xarth/badge_globalmod.svg); + background-size: 100% +} + +.badges .moderator { + background: #34ae0a url(/images/xarth/badge_mod.svg); + background-size: 100% +} + +.badges .admin { + background: #faaf19 url(/images/xarth/badge_admin.svg); + background-size: 100% +}*/ + +/* Odd Badges */ +.badge.click_url { cursor: pointer } + +.badge.warcraft.version-alliance { + background: url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/1.png") #004094; + background-image: -webkit-image-set(url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/1.png") 1x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/2.png") 2x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/4.png") 4x); + background-image: image-set(url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/1.png") 1x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/2.png") 2x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/4.png") 4x); +} + +.badge.warcraft.version-horde { + background: url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/1.png") #ab0016; + background-image: -webkit-image-set(url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/1.png") 1x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/2.png") 2x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/4.png") 4x); + background-image: image-set(url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/1.png") 1x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/2.png") 2x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/4.png") 4x); +} + +.badge.warcraft.version-protoss { + background: url("https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/1.png") #5bc7ff; + background-image: -webkit-image-set(url("https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/1.png") 1x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/2.png") 2x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/4.png") 4x); + background-image: image-set(url("https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/1.png") 1x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/2.png") 2x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/4.png") 4x); +} \ No newline at end of file