1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-02 16:08:31 +00:00

3.5.169. Oops. Haven't commited in a while :< Did... stuff? And things.

This commit is contained in:
SirStendec 2016-05-06 02:23:12 -04:00
parent 4086a2e9fd
commit 8056463bbe
28 changed files with 908 additions and 508 deletions

View file

@ -72,6 +72,8 @@
}
/* stats */
.ffz-dark .ct-tags--extracted { border-bottom: none }
.ffz-dark .stats-and-actions,
.ffz-dark #main_col .content #stats_and_actions {
border-bottom-color: rgba(255,255,255,0.2);
@ -115,19 +117,23 @@ body.ffz-dark,
}
.ffz-dark div.title > span.real,
.ffz-dark div.title > span.over{
color:rgb(222,222,222)!important;
.ffz-dark div.title > span.over,
.ffz-dark #broadcast-meta .info .title {
color: #DEDEDE !important;
background-color: rgba(16,16,16,0.3) !important;
}
.ffz-dark div.title > span.over:hover,
.ffz-dark div.title > span.real:hover {
background-color:rgb(16,16,16)!important;
color:rgb(255,255,255)!important;
.ffz-dark div.title > span.real:hover,
.ffz-dark #broadcast-meta .info .title:hover {
color: #fff !important;
background-color: #101010 !important;
}
/* Right Column */
.ffz-dark .ct-banner--off .ct-banner__toggle,
.ffz-dark #right_col {
background-color: rgb(25,25,31);
color: #fff;
@ -175,6 +181,9 @@ body.ffz-dark,
box-shadow: rgba(255,255,255,0.2) 0 0 0 1px inset;
}
.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 .st-autocomplete-sidebar .label,
@ -216,6 +225,7 @@ body.ffz-dark,
}
.ffz-dark .change-banner .banner-preview,
.ffz-dark .ct-banner--off .ct-banner__inputbox,
.ffz-dark form.js-new_panel_form input,
.ffz-dark form.js-new_panel_form textarea,
.ffz-dark .conversation-input-bar textarea,
@ -269,10 +279,20 @@ body.ffz-dark,
.ffz-dark .manager .videos-grid .video:hover .meta .actions li a,
.ffz-dark .ember-chat .chat-room-list .room:not(:hover) p.room-title,
.ffz-dark .dropmenu_action:not(:hover) span,
.ffz-dark a:not(.filter-item):not(.ui-state-focus):not(.button):not(.switch):not(.follow):not(.fb_button):not(.what) {
.ffz-dark a:not(.profile-card__content):not(.filter-item):not(.ui-state-focus):not(.button):not(.switch):not(.follow):not(.fb_button):not(.what) {
color: #a68ed2;
}
.ffz-dark .balloon--cols .balloon__list~.balloon__list {
box-shadow: -1px 0 0 rgba(255,255,255,0.2);
}
.ffz-dark .warp__item a.js-language-select,
.ffz-dark .warp__item > a { color: #d5d4d9 !important }
.ffz-dark .warp__item--toggled a.js-language-select,
.ffz-dark .warm__item--toggled > a { color: #eae9ec !important }
.ffz-dark .exit-theatre > a { color: #000 !important; }
.ffz-dark .follow-button a,
@ -297,7 +317,7 @@ body.ffz-dark,
background-color: #25252a;
}
.ffz-dark .button:not(.primary) {
.ffz-dark .button:not(.button--status):not(.primary) {
color: #a68ed2;
}
@ -1117,6 +1137,29 @@ body.ffz-dark,
}
/* Creative Tags */
.ffz-dark .ct-tags__tag {
background-color: #191919;
color: #999 !important;
}
.ffz-dark .ct-tag--light .ct-tag__link:hover { color: #ccc !important }
.ffz-dark .ct-tags__tag:hover {
background-color: #000;
color: #ccc !important;
}
.ffz-dark .ct-tags__tag.ct-tags__tag--current {
background-color: #7d5bbc;
color: #fff !important;
}
.ffz-dark .ct-banner--off .ct-banner__header { color: #999 }
.ffz-dark .ct-banner--off .ct-banner__link { color: #ccc }
/* Activity Feeds */
.button.alert { color: #fff !important }
@ -1128,12 +1171,12 @@ body.ffz-dark,
.ffz-dark .activity-meta:before { background-color: #474747 }
.ffz-dark .activity-react__like:hover {
.ffz-dark .activity-react__item:hover {
border-color: #d5d5d5;
background-color: #242424;
}
.ffz-dark .activity-react__like svg.endorse-icon #head__base { fill: #fff }
.ffz-dark .activity-react__item svg.endorse-icon #head__base { fill: #fff }
.ffz-dark .activity-create__actions {
background-color: #191919;
@ -1141,7 +1184,7 @@ body.ffz-dark,
}
.ffz-dark .activity-create,
.ffz-dark .activity-react__like {
.ffz-dark .activity-react__item {
border-color: #474747;
color: #fff !important;
background-color: #191919;

View file

@ -15,6 +15,8 @@ module.exports = FrankerFaceZ.constants = {
DEBUG: DEBUG,
SERVER: SERVER,
IS_OSX: navigator.platform ? navigator.platform.indexOf('Mac') !== -1 : /OS X/.test(navigator.userAgent),
// Twitch Client ID for API Stuff
CLIENT_ID: "a3bc9znoz6vi8ozsoca0inlcr4fcvkl",
@ -22,11 +24,11 @@ module.exports = FrankerFaceZ.constants = {
WS_SERVER_POOLS: {
1: [
["wss://catbag.frankerfacez.com/", 0.5],
["wss://catbag.frankerfacez.com/", 0.25],
["wss://andknuckles.frankerfacez.com/", 1],
["wss://tuturu.frankerfacez.com/", 1]],
2: [
["ws://localhost:8001/", 1]]
["wss://localhost:8001/", 1]]
},
CHAT_COLORS: ["#FF0000", "#0000FF", "#008000", "#B22222", "#FF7F50", "#9ACD32", "#FF4500", "#2E8B57", "#DAA520", "#D2691E", "#5F9EA0", "#1E90FF", "#FF69B4", "#8A2BE2", "#00FF7F"],

View file

@ -40,16 +40,17 @@ FFZ.prototype.setup_channel = function() {
// Update Existing
var views = utils.ember_views();
for(var key in views) {
if ( ! views.hasOwnProperty(key) )
continue;
var view = views[key];
if ( !(view instanceof Channel) )
continue;
this.log("Manually updating Channel Index view.", view);
if ( view instanceof Channel ) {
this.log("Manually updating existing Channel Index view.", view);
try {
if ( ! view.ffzInit )
this._modify_cindex(view);
view.ffzInit();
} catch(err) {
this.error("setup: view:channel/index: " + err);
}
}
};
@ -145,7 +146,7 @@ FFZ.prototype.setup_channel = function() {
if ( f._cindex )
f._cindex.ffzFixTitle();
}.observes("content.status", "content.id"),
}.observes("content.status", "content.id", "hostModeTarget.status", "hostModeTarget.id"),
ffzHostTarget: function() {
var target = this.get('content.hostModeTarget'),
@ -245,24 +246,43 @@ FFZ.prototype._modify_cindex = function(view) {
if ( Layout )
Layout.set('isTheatreMode', true);
}
this.$().on("click", ".ffz-creative-tag-link", function(e) {
if ( e.button !== 0 || e.altKey || e.ctrlKey || e.shiftKey || e.metaKey )
return;
utils.ember_lookup("router:main").transitionTo('creative.hashtag.index', this.getAttribute('data-tag'));
e.preventDefault();
return false;
});
},
ffzFixTitle: function() {
if ( f.has_bttv || ! f.settings.stream_title )
return;
var status = this.get("controller.content.status") || this.get("controller.status"),
channel = this.get("controller.content.id") || this.get("controller.id");
var status = this.get("controller.content.status"),
channel = this.get("controller.content.id"),
game = this.get("controller.content.game"),
status = f.render_tokens(f.tokenize_line(channel, channel, status, true));
tokens = f.tokenize_line(channel, channel, status, true);
this.$(".title span").each(function(i, el) {
var scripts = el.querySelectorAll("script");
if ( ! scripts.length )
el.innerHTML = status;
else
el.innerHTML = scripts[0].outerHTML + status + scripts[1].outerHTML;
});
if ( game === 'Creative' )
tokens = f.tokenize_ctags(tokens);
this.$("#broadcast-meta .title").html(f.render_tokens(tokens));
status = this.get('controller.hostModeTarget.status');
channel = this.get('controller.hostModeTarget.id');
game = this.get('controller.hostModeTarget.game');
if ( channel ) {
tokens = f.tokenize_line(channel, channel, status, true);
if ( game === 'Creative' )
tokens = f.tokenize_ctags(tokens);
this.$(".target-meta .target-title").html(f.render_tokens(tokens));
}
},

View file

@ -871,7 +871,7 @@ FFZ.prototype._modify_chat_input = function(component) {
case KEYCODES.TAB:
// If we do Ctrl-Tab or Alt-Tab. Just don't
// even think of doing suggestions.
if ( e.ctrlKey || e.altKey )
if ( e.ctrlKey || e.altKey || e.metaKey )
break;
e.preventDefault();

View file

@ -366,6 +366,16 @@ FFZ.prototype.setup_chatview = function() {
}.observes("currentChannelRoom", "connectedPrivateGroupRooms"),
ffzSubOwnChannelRoom: function() {
var user = f.get_user(),
room = this.get("currentChannelRoom"),
room_id = room && room.get("id");
if ( user && user.login && user.login === room_id )
room && room.ffzSubscribe && room.ffzSubscribe();
}.observes("currentChannelRoom"),
ffzUpdateInvites: function() {
if ( ! f._chatv || f.has_bttv )
return;
@ -520,8 +530,8 @@ FFZ.prototype._modify_cview = function(view) {
el && el.setAttribute('data-room', room_id || "");
this.$('.textarea-contain').append(f.build_ui_link(this));
this.$('.chat-messages').find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
this.$('.chat-messages').find('.ffz-tooltip').tipsy({live: true, html: true, title: f.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
//this.$('.chat-messages').find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
//this.$('.chat-messages').find('.ffz-tooltip').tipsy({live: true, html: true, title: f.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
if ( ! f.has_bttv ) {
if ( f.settings.group_tabs )

View file

@ -101,8 +101,8 @@ FFZ.prototype.setup_conversations = function() {
this.log("Unable to resolve: component:conversation-line");
// 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')});
jQuery('.conversations-list').find('.ffz-tooltip').tipsy({live: true, html: true, title: this.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
//jQuery('.conversations-list').find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
//jQuery('.conversations-list').find('.ffz-tooltip').tipsy({live: true, html: true, title: this.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
}
@ -175,8 +175,8 @@ FFZ.prototype._modify_conversation_window = function(component) {
}
jQuery('.badge', el).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
jQuery(el).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
jQuery(el).find('.ffz-tooltip').tipsy({live: true, html: true, title: f.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
//jQuery(el).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
//jQuery(el).find('.ffz-tooltip').tipsy({live: true, html: true, title: f.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
}
});
}

View file

@ -55,7 +55,23 @@ FFZ.settings_info.sidebar_hide_recommended_channels = {
};
FFZ.settings_info.directory_creative_all_tags = {
FFZ.settings_info.sidebar_hide_recommended_friends = {
type: "boolean",
value: true,
category: "Appearance",
no_mobile: true,
name: "Sidebar Recommended Friends",
help: "Display the Recommended Friends section on the sidebar.",
on_update: function(val) {
document.body.classList.toggle('ffz-hide-recommended-friends', !val);
}
};
/*FFZ.settings_info.directory_creative_all_tags = {
type: "boolean",
value: false,
@ -68,7 +84,7 @@ FFZ.settings_info.directory_creative_all_tags = {
on_update: function(val) {
document.body.classList.toggle('ffz-creative-tags', val);
}
};
};*/
FFZ.settings_info.directory_creative_showcase = {
@ -123,6 +139,82 @@ FFZ.settings_info.directory_group_hosts = {
};
FFZ.settings_info.banned_games = {
type: "button",
value: [],
category: "Directory",
no_mobile: true,
name: "Banned Games",
help: "A list of games that will not be displayed in the Directory.",
on_update: function() {
var banned = this.settings.banned_games,
els = document.querySelectorAll('.ffz-directory-preview');
for(var i=0; i < els.length; i++) {
var el = els[i],
game = el.getAttribute('data-game');
el.classList.toggle('ffz-game-banned', banned.indexOf(game && game.toLowerCase()) !== -1);
}
},
method: function() {
var f = this,
old_val = f.settings.banned_games.join(", ");
utils.prompt(
"Banned Games",
"Please enter a comma-separated list of games that you would like to be banned from viewing in the Directory.</p><p>This is case insensitive, however you must type the full name.</p><p><b>Example:</b> <code>League of Legends, Dota 2, Smite</code>",
old_val,
function(new_val) {
if ( new_val === null || new_val === undefined )
return;
f.settings.set("banned_games", _.unique(new_val.trim().toLowerCase().split(/\s*,\s*/)));
}, 600);
}
}
FFZ.settings_info.spoiler_games = {
type: "button",
value: [],
category: "Directory",
no_mobile: true,
name: "Spoiler Games",
help: "Stream thumbnails will be hidden for games that you add to this list.",
on_update: function() {
var spoiled = this.settings.spoiler_games,
els = document.querySelectorAll('.ffz-directory-preview');
for(var i=0; i < els.length; i++) {
var el = els[i],
game = el.getAttribute('data-game');
el.classList.toggle('ffz-game-spoilered', spoiled.indexOf(game && game.toLowerCase()) !== -1);
}
},
method: function() {
var f = this,
old_val = f.settings.spoiler_games.join(", ");
utils.prompt(
"Spoiler Games",
"Please enter a comma-separated list of games that you would like to have the thumbnails hidden for in the Directory.</p><p>This is case insensitive, however you must type the full name.</p><p><b>Example:</b> <code>Undertale</code>",
old_val,
function(new_val) {
if ( new_val === null || new_val === undefined )
return;
f.settings.set("spoiler_games", _.unique(new_val.trim().toLowerCase().split(/\s*,\s*/)));
}, 600);
}
}
FFZ.settings_info.directory_host_menus = {
type: "select",
options: {
@ -168,6 +260,7 @@ FFZ.prototype.setup_directory = function() {
document.body.classList.toggle('ffz-creative-tags', this.settings.directory_creative_all_tags);
document.body.classList.toggle('ffz-creative-showcase', this.settings.directory_creative_showcase);
document.body.classList.toggle('ffz-hide-recommended-channels', !this.settings.sidebar_hide_recommended_channels);
document.body.classList.toggle('ffz-hide-recommended-friends', !this.settings.sidebar_hide_recommended_friends);
var GamesFollowing = utils.ember_lookup('controller:games-following'),
f = this;
@ -197,7 +290,7 @@ FFZ.prototype.setup_directory = function() {
var ChannelView = utils.ember_resolve('component:stream-preview');
if ( ChannelView ) {
this._modify_directory_live(ChannelView);
this._modify_directory_live(ChannelView, false);
try {
ChannelView.create().destroy();
} catch(err) { }
@ -205,7 +298,7 @@ FFZ.prototype.setup_directory = function() {
var CreativeChannel = utils.ember_resolve('component:creative-preview');
if ( CreativeChannel ) {
this._modify_directory_live(CreativeChannel);
this._modify_directory_live(CreativeChannel, false);
try {
CreativeChannel.create().destroy();
} catch(err) { }
@ -222,19 +315,30 @@ FFZ.prototype.setup_directory = function() {
} catch(err) { }
var VideoPreview = utils.ember_resolve('component:video-preview');
if ( VideoPreview ) {
VideoPreview = this._modify_video_preview(VideoPreview);
try { VideoPreview.create().destroy();
} catch(err) { }
}
// Initialize existing views.
var views = utils.ember_views();
for(var key in views) {
var view = views[key];
if ( (ChannelView && view instanceof ChannelView) || (CreativeChannel && view instanceof CreativeChannel) ) {
if ( ! view.ffzInit )
this._modify_directory_live(view);
this._modify_directory_live(view, false);
} else if ( CSGOChannel && view instanceof CSGOChannel ) {
if ( ! view.ffzInit )
this._modify_directory_live(view, true);
} else if ( view instanceof HostView || view.get('tt_content') === 'live_host' ) {
if ( ! view.ffzInit )
this._modify_directory_host(view);
} else if ( VideoPreview && view instanceof VideoPreview ) {
if ( ! view.ffzInit )
this._modify_video_preview(view);
} else
continue;
@ -386,9 +490,15 @@ FFZ.prototype._modify_directory_live = function(dir, is_csgo) {
meta = el && el.querySelector('.meta'),
thumb = el && el.querySelector('.thumb'),
cap = thumb && thumb.querySelector('.cap'),
channel_id = this.get(pref + 'channel.name');
channel_id = this.get(pref + 'channel.name'),
game = this.get(pref + 'game');
el.classList.add('ffz-directory-preview');
el.setAttribute('data-channel', channel_id);
el.setAttribute('data-game', game);
el.classList.toggle('ffz-game-banned', f.settings.banned_games.indexOf(game && game.toLowerCase()) !== -1);
el.classList.toggle('ffz-game-spoilered', f.settings.spoiler_games.indexOf(game && game.toLowerCase()) !== -1);
// CSGO doesn't provide the actual uptime information...
if ( !is_csgo && f.settings.stream_uptime && f.settings.stream_uptime < 3 && cap ) {
@ -482,6 +592,33 @@ FFZ.prototype._modify_directory_live = function(dir, is_csgo) {
}
FFZ.prototype._modify_video_preview = function(vp) {
var f = this;
vp.reopen({
didInsertElement: function() {
this._super();
try {
this.ffzInit();
} catch(err) {
f.error("component:video-preview ffzInit: " + err);
}
},
ffzInit: function() {
var el = this.get('element'),
game = this.get('video.game');
el.classList.add('ffz-directory-preview');
el.setAttribute('data-channel', this.get('video.channel.id'));
el.setAttribute('data-game', game);
el.classList.toggle('ffz-game-banned', f.settings.banned_games.indexOf(game && game.toLowerCase()) !== -1);
el.classList.toggle('ffz-game-spoilered', f.settings.spoiler_games.indexOf(game && game.toLowerCase()) !== -1);
}
});
}
FFZ.prototype._modify_directory_host = function(dir) {
var f = this, mutator;
@ -613,11 +750,17 @@ FFZ.prototype._modify_directory_host = function(dir) {
title = meta && meta.querySelector('.title a'),
target = this.get('stream.target.channel'),
game = this.get('stream.target.meta_game'),
hosts = this.get('stream.ffz_hosts'); //,
//boxart = thumb && thumb.querySelector('.boxart');
el.classList.add('ffz-directory-preview');
el.setAttribute('data-channel', target.name);
el.setAttribute('data-game', game);
el.classList.toggle('ffz-game-banned', f.settings.banned_games.indexOf(game && game.toLowerCase()) !== -1);
el.classList.toggle('ffz-game-spoilered', f.settings.spoiler_games.indexOf(game && game.toLowerCase()) !== -1);
this._ffz_image_timer = setInterval(this.ffzRotateImage.bind(this), 30000);
this.ffzRotateImage();

View file

@ -21,10 +21,11 @@ var FFZ = window.FrankerFaceZ,
FFZ.prototype.setup_feed_cards = function() {
var FeedCard = utils.ember_resolve('component:feed-card');
var FeedCard = utils.ember_resolve('component:channel-feed/card');
if ( ! FeedCard )
return;
return this.error("Unable to locate component:channel-feed/card");
this.log("Modifying the feed-card component.");
this._modify_feed_card(FeedCard);
try { FeedCard.create().destroy();
@ -35,7 +36,7 @@ FFZ.prototype.setup_feed_cards = function() {
FFZ.prototype.rerender_feed_cards = function(for_set) {
var FeedCard = utils.ember_resolve('component:feed-card'),
var FeedCard = utils.ember_resolve('component:channel-feed/card'),
views = utils.ember_views();
if ( ! FeedCard )
@ -49,7 +50,7 @@ FFZ.prototype.rerender_feed_cards = function(for_set) {
this._modify_feed_card(view);
view.ffzInit(for_set);
} catch(err) {
this.error("setup component:feed-card ffzInit: " + err)
this.error("setup component:channel-feed/card ffzInit: " + err)
}
}
}
@ -64,7 +65,7 @@ FFZ.prototype._modify_feed_card = function(component) {
try {
this.ffzInit();
} catch(err) {
f.error("component:feed-card ffzInit: " + err);
f.error("component:channel-feed/card ffzInit: " + err);
}
},
@ -73,7 +74,7 @@ FFZ.prototype._modify_feed_card = function(component) {
message = this.get('post.body'),
emotes = parse_emotes(this.get('post.emotes')),
user_id = this.get('post.user.login'),
room_id = this.get('channelId'),
room_id = this.get('channelId') || user_id,
pbody = el && el.querySelector('.activity-body');
if ( ! message || ! el || ! pbody )
@ -91,8 +92,8 @@ FFZ.prototype._modify_feed_card = function(component) {
pbody.innerHTML = '<p>' + output + '</p>';
jQuery('.ffz-tooltip', pbody).tipsy({html: true, title: f.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
jQuery('.html-tooltip', pbody).tipsy({html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
//jQuery('.ffz-tooltip', pbody).tipsy({html: true, title: f.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
//jQuery('.html-tooltip', pbody).tipsy({html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
}
});
}

View file

@ -1,6 +1,8 @@
var FFZ = window.FrankerFaceZ,
utils = require('../utils'),
constants = require('../constants');
constants = require('../constants'),
createElement = utils.createElement;
// --------------------
@ -13,7 +15,7 @@ FFZ.settings_info.enhance_profile_following = {
category: "Directory",
name: "Enhanced Following Control",
help: "Display additional controls on your own profile's Following tab to make management easier."
help: "Display additional controls on your own profile's Following tab to make management easier, as well as telling you how long everyone has been following everyone else in the profile."
}
@ -29,6 +31,7 @@ FFZ.prototype.setup_profile_following = function() {
// Build our is-following cache.
this._following_cache = {};
this._follower_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.
@ -36,12 +39,24 @@ FFZ.prototype.setup_profile_following = function() {
if ( Following )
this._hook_following(Following);
var Followers = utils.ember_resolve('model:user-followers');
if ( Followers )
this._hook_followers(Followers);
// Also try hooking that other model.
var Notification = utils.ember_resolve('model:notification');
if ( Notification )
this._hook_following(Notification, true);
// Find the followed item view
var FollowedItem = utils.ember_resolve('component:display-followed-item');
if ( ! FollowedItem )
return;
this._modify_display_followed_item(FollowedItem);
// Now, we need to edit the profile Following view itself.
var ProfileView = utils.ember_resolve('view:channel/following');
if ( ! ProfileView )
@ -57,155 +72,171 @@ FFZ.prototype.setup_profile_following = function() {
}
},
ffzInit: function() {
// Only process our own profile following page.
if ( ! f.settings.enhance_profile_following )
return;
var el = this.get('element'),
user = f.get_user(),
user_id = this.get('context.model.id');
el.classList.add('ffz-enhanced-following');
el.classList.toggle('ffz-my-following', user && user.login === user_id);
el.setAttribute('data-user', user_id);
}
});
// TODO: Add nice Manage Following button to the directory.
// Now, rebuild any views.
try { FollowedItem.create().destroy();
} catch(err) { }
var views = utils.ember_views();
if ( views ) {
for(var key in views) {
var view = views[key];
if ( view instanceof FollowedItem ) {
this.log("Manually updating existing component:display-followed-item.", view);
try {
if ( ! view.ffzInit )
this._modify_display_followed_item(view);
view.ffzInit();
} catch(err) {
this.error("setup: component:display-followed-item ffzInit: " + err);
}
}
}
}
// Refresh all existing following data.
var count = 0,
Channel = utils.ember_resolve('model:channel');
if ( Channel && Channel._cache )
for(var key in Channel._cache) {
var chan = Channel._cache[key];
if ( chan instanceof Channel ) {
var following = chan.get('following'),
followers = chan.get('followers'),
refresher = function(x) {
if ( x.get('isLoading') )
setTimeout(refresher.bind(this,x), 25);
x.clear();
x.load();
};
// Make sure this channel's Following collection is modified.
this._hook_following(following);
this._hook_followers(followers);
var counted = false;
if ( following.get('isLoaded') || following.get('isLoading') ) {
refresher(following);
count++;
counted = true;
}
if ( followers.get('isLoaded') || followers.get('isLoading') ) {
refresher(followers);
if ( ! counted )
count++;
}
}
}
f.log("Refreshing previously loaded user following data for " + count + " channels.");
}
FFZ.prototype._modify_display_followed_item = function(component) {
var f = this;
component.reopen({
didInsertElement: function() {
this._super();
try {
this.ffzInit();
} catch(err) {
f.error("component:display-followed-item ffzInit: " + err);
}
},
willClearRender: function() {
try {
this.ffzTeardown();
} catch(err) {
f.error("ProvileView ffzTeardown: " + err);
f.error("component:display-followed-item 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.model.id') )
var el = this.get('element'),
channel_id = this.get('parentView.parentView.model.id'),
is_following = document.body.getAttribute('data-current-path').indexOf('.following') !== -1,
user = f.get_user(),
mine = user && user.login && user.login === channel_id,
big_cache = is_following ? f._following_cache : f._follower_cache;
user_cache = big_cache[channel_id] = big_cache[channel_id] || {},
user_id = this.get('followed.id'),
data = user_cache[user_id];
if ( ! f.settings.enhance_profile_following )
return;
var el = this.get('element'),
users = el && el.querySelectorAll('.user.item');
el.classList.add('ffz-processed');
el.classList.add('ffz-enhanced-following');
// TODO: REMOVE
window._d = this;
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();
}
// Make sure the Following is modified.
f._hook_following(following);
// 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('user') )
t.ffzProcessUser(added);
else 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]);
}
}
}
});
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, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 's')});
var now = Date.now() - (f._ws_server_offset || 0),
age = data[0] ? Math.floor((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: <nobr>' + data[0].toLocaleString() + '</nobr>');
} else
t_el.style.display = 'none';
age = data[0] ? Math.floor((now - data[0].getTime()) / 1000) : 0,
t_el = createElement('div', 'overlay_info length'),
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 + '<span> Follow</span>';
if ( t_el ) {
update_time = function() {
var now = Date.now() - (f._ws_server_offset || 0),
age = data && data[0] ? Math.floor((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: <nobr>' + data[0].toLocaleString() + '</nobr>');
t_el.title = 'Following Since: <nobr>' + data[0].toLocaleString() + '</nobr>';
t_el.style.display = '';
} else {
} else
t_el.style.display = 'none';
}
}
};
update_time();
jQuery(t_el).tipsy({html:true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 's')});
el.appendChild(t_el);
if ( ! mine || ! is_following )
return;
var actions = createElement('div', 'actions'),
follow = createElement('button', 'button follow'),
notif = createElement('button', 'button notifications'),
update_follow = function() {
data = user_cache[user_id];
el.classList.toggle('followed', data);
follow.innerHTML = constants.HEART + constants.UNHEART + '<span> Follow</span>';
},
update_notif = function() {
data = f._following_cache[user_id];
data = user_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();
@ -220,11 +251,12 @@ FFZ.prototype.setup_profile_following = function() {
utils.api.del("users/:login/follows/channels/" + user_id) :
utils.api.put("users/:login/follows/channels/" + user_id, {notifications: false}))
.done(function() {
data = f._following_cache[user_id] = was_following ? null : [new Date(Date.now() - (f._ws_server_offset||0)), false];
data = user_cache[user_id] = was_following ? null : [new Date(Date.now() - (f._ws_server_offset||0)), false];
})
.always(function() {
update_follow();
update_notif();
update_time();
follow.disabled = false;
notif.disabled = false;
})
@ -250,32 +282,14 @@ FFZ.prototype.setup_profile_following = function() {
actions.appendChild(follow);
actions.appendChild(notif);
user.appendChild(actions);
return true;
el.appendChild(actions);
},
ffzTeardown: function() {
}
});
// TODO: Add nice Manage Following button to the directory.
// Now, rebuild any views.
try {
ProfileView.create().destroy();
} catch(err) { }
var views = utils.ember_views();
if ( views )
for(var key in views) {
var view = views[key];
if ( view instanceof ProfileView ) {
this.log("Manually updating existing Following View.", view);
try {
view.ffzInit();
} catch(err) {
this.error("setup: view:channel/following: " + err);
}
}
}
}
@ -287,12 +301,10 @@ FFZ.prototype._hook_following = function(Following) {
Following.reopen({
ffz_hooked: true,
apiLoad: function(e) {
var user = f.get_user(),
channel_id = this.get('id'),
var channel_id = this.get('id'),
t = this;
if ( ! user || user.login !== channel_id )
return this._super(e);
f._following_cache[channel_id] = f._following_cache[channel_id] || {};
return new RSVP.Promise(function(success, fail) {
t._super(e).then(function(data) {
@ -307,7 +319,47 @@ FFZ.prototype._hook_following = function(Following) {
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];
f._following_cache[channel_id][follow.channel.name] = [follow.created_at ? utils.parse_date(follow.created_at) : null, follow.notifications || false];
}
}
success(data);
}, function(err) {
fail(err);
})
});
}
});
}
FFZ.prototype._hook_followers = function(Followers) {
var f = this;
if ( Followers.ffz_hooked )
return;
Followers.reopen({
ffz_hooked: true,
apiLoad: function(e) {
var channel_id = this.get('id'),
t = this;
f._follower_cache[channel_id] = f._follower_cache[channel_id] || {};
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.user || ! follow.user.name ) {
continue;
}
if ( follow.user.display_name )
FFZ.capitalization[follow.user.name] = [follow.user.display_name, now];
f._follower_cache[channel_id][follow.user.name] = [follow.created_at ? utils.parse_date(follow.created_at) : null, follow.notifications || false];
}
}

View file

@ -145,7 +145,6 @@ FFZ.prototype.setup_layout = function() {
return;
document.body.classList.toggle("ffz-sidebar-swap", this.settings.swap_sidebars);
document.body.classList.toggle("ffz-portrait", this.settings.portrait_mode);
this.log("Creating layout style element.");
var s = this._layout_style = document.createElement('style');
@ -328,4 +327,5 @@ FFZ.prototype.setup_layout = function() {
// Force re-calculation of everything.
Ember.propertyDidChange(Layout, 'windowWidth');
Ember.propertyDidChange(Layout, 'windowHeight');
Layout.ffzUpdatePortraitCSS();
}

View file

@ -1024,6 +1024,7 @@ FFZ.prototype._modify_vod_line = function(component) {
FFZ.capitalization = {};
FFZ._cap_fetching = 0;
FFZ._cap_waiting = {};
FFZ.get_capitalization = function(name, callback) {
if ( ! name )
@ -1039,13 +1040,25 @@ FFZ.get_capitalization = function(name, callback) {
return old_data[0];
}
if ( FFZ._cap_fetching < 25 ) {
if ( FFZ._cap_waiting[name] )
FFZ._cap_waiting[name].push(callback);
else if ( FFZ._cap_fetching < 25 ) {
FFZ._cap_fetching++;
FFZ._cap_waiting[name] = [callback];
FFZ.get().ws_send("get_display_name", name, function(success, data) {
var cap_name = success ? data : name;
var cap_name = success ? data : name,
waiting = FFZ._cap_waiting[name];
FFZ.capitalization[name] = [cap_name, Date.now()];
FFZ._cap_fetching--;
typeof callback === "function" && callback(cap_name);
FFZ._cap_waiting[name] = false;
for(var i=0; i < waiting.length; i++)
try {
typeof waiting[i] === "function" && waiting[i](cap_name);
} catch(err) { }
});
}

View file

@ -704,6 +704,13 @@ FFZ.prototype.setup_mod_card = function() {
}
// Follow Button
var follow_button = el.querySelector(".interface > .follow-button");
if ( follow_button )
jQuery(follow_button).tipsy({title: function() { return follow_button.classList.contains('is-following') ? "Unfollow" : "Follow"}});
// Whisper and Message Buttons
var msg_btn = el.querySelector(".interface > button.message-button");
if ( msg_btn ) {
msg_btn.innerHTML = 'W';
@ -1082,8 +1089,8 @@ FFZ.prototype._build_mod_card_history = function(msg, modcard, show_from) {
jQuery('.deleted-word', l_el).click(function(e) { jQuery(this).trigger('mouseout'); this.outerHTML = this.getAttribute('data-text'); });
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, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')});
jQuery('.ffz-tooltip', l_el).tipsy({live: true, html: true, title: f.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')});
//jQuery('.html-tooltip', l_el).tipsy({html:true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')});
//jQuery('.ffz-tooltip', l_el).tipsy({live: true, html: true, title: f.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')});
if ( modcard ) {
modcard.get('cardInfo.user.id') !== msg.from && jQuery('span.from', l_el).click(function(e) {

View file

@ -164,9 +164,9 @@ FFZ.prototype._modify_player = function(player) {
var stats = this.$('.player .js-playback-stats');
stats.draggable({cancel: 'li', containment: 'parent'});
// Give the player time to do stuff before we change this
/*// Give the player time to do stuff before we change this
// text. It's a bit weird otherwise.
setTimeout(function(){stats.children('.js-stats-toggle').html(constants.CLOSE);},500);
setTimeout(function(){stats.children('.js-stats-toggle').html(constants.CLOSE);},500);*/
// Only set up the stats hooks if we need stats.

View file

@ -4,6 +4,15 @@ var FFZ = window.FrankerFaceZ,
utils = require('../utils'),
helpers,
STATUS_BADGES = [
["r9k", "r9k", "This room is in R9K-mode."],
["sub", "subsOnly", "This room is in subscribers-only mode."],
["slow", "slow", function(room) { return "This room is in slow mode. You may send messages every " + utils.number_commas(room && room.get('slow') || 120) + " seconds." }],
["ban", "ffz_banned", "You have been banned from talking in this room."],
["delay", function() { return this.settings.chat_delay !== 0 }, function() { return "You have enabled artificial chat delay. Messages are displayed after " + (this.settings.chat_delay/1000) + " seconds." }],
["batch", function() { return this.settings.chat_batching !== 0 }, function() { return "You have enabled chat message batching. Messages are displayed in " + (this.settings.chat_batching/1000) + " second increments." }]
],
// StrimBagZ Support
is_android = navigator.userAgent.indexOf('Android') !== -1,
@ -210,152 +219,47 @@ FFZ.prototype._modify_rview = function(view) {
ffzUpdateStatus: function() {
var room = this.get('controller.model'),
el = this.get('element'),
cont = el && el.querySelector('.chat-buttons-container');
if ( ! cont )
return;
var r9k_badge = cont.querySelector('#ffz-stat-r9k'),
sub_badge = cont.querySelector('#ffz-stat-sub'),
emote_badge = cont.querySelector('#ffz-stat-emote'),
slow_badge = cont.querySelector('#ffz-stat-slow'),
banned_badge = cont.querySelector('#ffz-stat-banned'),
delay_badge = cont.querySelector('#ffz-stat-delay'),
batch_badge = cont.querySelector('#ffz-stat-batch'),
btn = cont.querySelector('button');
var btn = cont.querySelector('button');
if ( f.has_bttv || ! f.settings.room_status ) {
if ( r9k_badge )
r9k_badge.parentElement.removeChild(r9k_badge);
if ( sub_badge )
sub_badge.parentElement.removeChild(sub_badge);
if ( emote_badge )
emote_badge.parentElement.removeChild(emote_badge);
if ( slow_badge )
slow_badge.parentElement.removeChild(slow_badge);
if ( delay_badge )
delay_badge.parentElement.removeChild(delay_badge);
if ( batch_badge )
batch_badge.parentElement.removeChild(batch_badge);
jQuery(".ffz.room-state", cont).remove();
if ( btn )
btn.classList.remove('ffz-waiting');
return;
}
if ( ! r9k_badge ) {
r9k_badge = document.createElement('span');
r9k_badge.className = 'ffz room-state stat float-right';
r9k_badge.id = 'ffz-stat-r9k';
r9k_badge.innerHTML = 'R<span>9K</span>';
r9k_badge.title = "This room is in R9K-mode.";
cont.appendChild(r9k_badge);
jQuery(r9k_badge).tipsy({gravity:"s", offset:15});
}
if ( ! sub_badge ) {
sub_badge = document.createElement('span');
sub_badge.className = 'ffz room-state stat float-right';
sub_badge.id = 'ffz-stat-sub';
sub_badge.innerHTML = 'S<span>UB</span>';
sub_badge.title = "This room is in subscribers-only mode.";
cont.appendChild(sub_badge);
jQuery(sub_badge).tipsy({gravity:"s", offset:15});
}
if ( ! emote_badge ) {
emote_badge = document.createElement('span');
emote_badge.className = 'ffz room-state stat float-right';
emote_badge.id = 'ffz-stat-emote';
emote_badge.innerHTML = 'E<span>MOTE</span>';
emote_badge.title = "This room is in Twitch emote-only mode. Emotes added by extensions are not permitted in this mode.";
cont.appendChild(emote_badge);
jQuery(emote_badge).tipsy({gravity: "s", offset: 15});
}
if ( ! slow_badge ) {
slow_badge = document.createElement('span');
slow_badge.className = 'ffz room-state stat float-right';
slow_badge.id = 'ffz-stat-slow';
slow_badge.innerHTML = 'S<span>LOW</span>';
cont.appendChild(slow_badge);
jQuery(slow_badge).tipsy({gravity:"s", offset:15});
}
if ( ! banned_badge ) {
banned_badge = document.createElement('span');
banned_badge.className = 'ffz room-state stat float-right';
banned_badge.id = 'ffz-stat-banned';
banned_badge.innerHTML = 'B<span>AN</span>';
banned_badge.title = "You have been banned from talking in this room.";
cont.appendChild(banned_badge);
jQuery(banned_badge).tipsy({gravity:"s", offset:15});
}
if ( ! delay_badge ) {
delay_badge = document.createElement('span');
delay_badge.className = 'ffz room-state stat float-right';
delay_badge.id = 'ffz-stat-delay';
delay_badge.innerHTML = 'D<span>ELAY</span>';
cont.appendChild(delay_badge);
jQuery(delay_badge).tipsy({gravity:"s", offset:15});
}
if ( ! batch_badge ) {
batch_badge = document.createElement('span');
batch_badge.className = 'ffz room-state stat float-right';
batch_badge.id = 'ffz-stat-batch';
batch_badge.innerHTML = 'B<span>ATCH</span>';
cont.appendChild(batch_badge);
jQuery(batch_badge).tipsy({gravity:"s", offset:15});
}
var vis_count = 0,
r9k_vis = room && room.get('r9k'),
sub_vis = room && room.get('subsOnly'),
emote_vis = room && room.get('emoteOnly') && room.get('emoteOnly') !== '0',
ban_vis = room && room.get('ffz_banned'),
slow_vis = room && room.get('slowMode'),
delay_vis = f.settings.chat_delay !== 0,
batch_vis = f.settings.chat_batching !== 0;
if ( r9k_vis ) vis_count += 1;
if ( sub_vis ) vis_count += 1;
if ( emote_vis ) vis_count += 1;
if ( ban_vis ) vis_count += 1;
if ( slow_vis ) vis_count += 1;
if ( delay_vis ) vis_count += 1;
if ( batch_vis ) vis_count += 1;
r9k_badge.classList.toggle('truncated', vis_count > 3);
sub_badge.classList.toggle('truncated', vis_count > 3);
emote_badge.classList.toggle('truncated', vis_count > 3);
banned_badge.classList.toggle('truncated', vis_count > 3);
slow_badge.classList.toggle('truncated', vis_count > 3);
delay_badge.classList.toggle('truncated', vis_count > 3);
batch_badge.classList.toggle('truncated', vis_count > 3);
r9k_badge.classList.toggle('hidden', ! r9k_vis);
sub_badge.classList.toggle('hidden', ! sub_vis);
emote_badge.classList.toggle('hidden', ! emote_vis);
banned_badge.classList.toggle('hidden', ! ban_vis);
slow_badge.classList.toggle('hidden', ! slow_vis);
slow_badge.title = "This room is in slow mode. You may send messages every " + utils.number_commas(room && room.get('slow')||120) + " seconds.";
delay_badge.title = "You have enabled artificial chat delay. Messages are displayed after " + (f.settings.chat_delay/1000) + " seconds.";
delay_badge.classList.toggle('hidden', ! delay_vis);
batch_badge.title = "You have enabled chat message batching. Messages are displayed in " + (f.settings.chat_batching/1000) + " second increments.";
batch_badge.classList.toggle('hidden', ! batch_vis);
if ( btn ) {
} else if ( btn ) {
btn.classList.toggle('ffz-waiting', (room && room.get('slowWait') || 0));
btn.classList.toggle('ffz-banned', (room && room.get('ffz_banned')));
}
var badge, id, info, vis_count = 0;
for(var i=0; i < STATUS_BADGES.length; i++) {
info = STATUS_BADGES[i];
id = 'ffz-stat-' + info[0];
badge = cont.querySelector('#' + id);
visible = typeof info[1] === "function" ? info[1].call(f, room) : room && room.get(info[1]);
if ( ! badge ) {
badge = utils.createElement('span', 'ffz room-state stat float-right', info[0].charAt(0).toUpperCase() + '<span>' + info[0].substr(1).toUpperCase() + '</span>');
badge.id = id;
jQuery(badge).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'se')});
cont.appendChild(badge);
}
badge.title = typeof info[2] === "function" ? info[2].call(f, room) : info[2];
badge.classList.toggle('hidden', ! visible);
if ( visible )
vis_count++;
}
jQuery(".ffz.room-state", cont).toggleClass("truncated", vis_count > 3);
}.observes('controller.model'),
ffzEnableFreeze: function() {
@ -677,7 +581,8 @@ FFZ.prototype.add_room = function(id, room) {
}
// Let the server know where we are.
this.ws_send("sub", "room." + id);
room && room.ffzSubscribe && room.ffzSubscribe();
//this.ws_send("sub", "room." + id);
// See if we need history?
if ( ! this.has_bttv && this.settings.chat_history && room && (room.get('messages.length') || 0) < 10 ) {
@ -983,7 +888,7 @@ FFZ.prototype._modify_room = function(room) {
room_id = this.get('id');
if ( (Chat && Chat.get('currentChannelRoom') === this) || (user && user.login === room_id) || (f._chatv && f._chatv._ffz_host === room_id) || (f.settings.pinned_rooms && f.settings.pinned_rooms.indexOf(room_id) !== -1) )
return;
return this.ffzUnsubscribe(true);
this.destroy();
},
@ -993,6 +898,24 @@ FFZ.prototype._modify_room = function(room) {
f._roomv.ffzUpdateStatus();
}.observes('r9k', 'subsOnly', 'emoteOnly', 'slow', 'ffz_banned'),
ffzShouldSubscribe: function() {
var Chat = utils.ember_lookup('controller:chat'),
room_id = this.get('id');
return (Chat && Chat.get('currentChannelRoom') === this) || (f.settings.pinned_rooms && f.settings.pinned_rooms.indexOf(room_id) !== -1);
},
ffzSubscribe: function() {
if ( this.ffzShouldSubscribe() )
f.ws_send("sub", "room." + this.get('id'));
},
ffzUnsubscribe: function(not_always) {
if ( ! not_always || ! this.ffzShouldSubscribe() )
f.ws_send("unsub", "room." + this.get('id'));
},
// User Level
ffzUserLevel: function() {
if ( this.get('isStaff') )
@ -1300,6 +1223,12 @@ FFZ.prototype._modify_room = function(room) {
if ( msg.color )
f._handle_color(msg.color);
// Message Filtering
var i = f._chat_filters.length;
while(i--)
if ( f._chat_filters[i](msg) === false )
return;
// Report this message to the dashboard.
if ( window !== window.parent && parent.postMessage && msg.from && msg.from !== "jtv" && msg.from !== "twitchnotify" )
parent.postMessage({from_ffz: true, command: 'chat_message', data: {from: msg.from, room: msg.room}}, location.protocol + "//www.twitch.tv/");
@ -1308,6 +1237,10 @@ FFZ.prototype._modify_room = function(room) {
return this._super(msg);
},
ffzChatFilters: function(msg) {
var i = f._chat_filters.length;
},
setHostMode: function(e) {
this.set('ffz_host_target', e && e.hostTarget || null);
var user = f.get_user();

View file

@ -154,7 +154,7 @@ FFZ.prototype._modify_vod_chat_display = function(component) {
if ( f.settings.chat_hover_pause )
this.ffzEnableFreeze();
this.$('.chat-messages').find('.html-tooltip').tipsy({
/*this.$('.chat-messages').find('.html-tooltip').tipsy({
live: true, html: true,
gravity: utils.tooltip_placement(2 * constants.TOOLTIP_DISTANCE, function() {
return this.classList.contains('right') ? 'e' : 'n'
@ -165,7 +165,7 @@ FFZ.prototype._modify_vod_chat_display = function(component) {
title: f.render_tooltip(),
gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, function() {
return this.classList.contains('right') ? 'e' : 'n'
})});
})});*/
},
ffzTeardown: function() {

View file

@ -50,6 +50,8 @@ var API = FFZ.API = function(instance, name, icon, version) {
this.global_sets = [];
this.default_sets = [];
this.users = {};
this.chat_filters = [];
this.on_room_callbacks = [];
this.name = name || ("Extension#" + this.id);
@ -384,6 +386,76 @@ API.prototype.unregister_room_set = function(room_id, id) {
}
// -----------------------
// User Modifications
// -----------------------
API.prototype.user_add_set = function(user_name, set_id) {
var user = this.users[user_name] = this.users[user_name] || {},
ffz_user = this.ffz.users[user_name] = this.ffz.users[user_name] || {},
emote_sets = user.sets = user.sets || [],
ffz_sets = ffz_user.sets = ffz_user.sets || [],
exact_id = this.id + '-' + set_id;
if ( emote_sets.indexOf(exact_id) === -1 )
emote_sets.push(exact_id);
if ( ffz_sets.indexOf(exact_id) === -1 )
ffz_sets.push(exact_id);
// Update tab completion.
var user = this.ffz.get_user();
if ( this.ffz._inputv && user && user.login === user_name )
Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons');
}
API.prototype.user_remove_set = function(user_name, set_id) {
var user = this.users[user_name],
ffz_user = this.ffz.users[user_name],
emote_sets = user && user.sets,
ffz_sets = ffz_user && ffz_user.sets,
exact_id = this.id + '-' + set_id;
var ind = emote_sets ? emote_sets.indexOf(exact_id) : -1;
if ( ind !== -1 )
emote_sets.splice(ind, 1);
ind = ffz_sets ? ffz_sets.indexOf(exact_id) : -1;
if ( ind !== -1 )
ffz_sets.splice(ind, 1);
// Update tab completion.
var user = this.ffz.get_user();
if ( this.ffz._inputv && user && user.login === user_name )
Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons');
}
// -----------------------
// Chat Callback
// -----------------------
API.prototype.register_chat_filter = function(filter) {
this.chat_filters.push(filter);
this.ffz._chat_filters.push(filter);
}
API.prototype.unregister_chat_filter = function(filter) {
var ind = this.chat_filters.indexOf(filter);
if ( ind !== -1 )
this.chat_filters.splice(ind, 1);
ind = this.ffz._chat_filters.indexOf(filter);
if ( ind !== -1 )
this.ffz._chat_filters.splice(ind, 1);
}
// -----------------------
// Channel Callbacks
// -----------------------

View file

@ -102,8 +102,8 @@ FFZ.prototype.find_rechat = function() {
// 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')});
jQuery(container).find('.ffz-tooltip').tipsy({live: true, html: true, title: this.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
//jQuery(container).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
//jQuery(container).find('.ffz-tooltip').tipsy({live: true, html: true, title: this.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
// Load the room data.
var room_id = el.getAttribute('data-room');

View file

@ -11,6 +11,7 @@ var FFZ = window.FrankerFaceZ = function() {
// Logging
this._log_data = [];
this._apis = {};
this._chat_filters = [];
// Error Logging
var t = this;
@ -35,7 +36,7 @@ FFZ.msg_commands = {};
// Version
var VER = FFZ.version_info = {
major: 3, minor: 5, revision: 159,
major: 3, minor: 5, revision: 169,
toString: function() {
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
}
@ -91,7 +92,7 @@ FFZ.prototype.paste_logs = function() {
FFZ.prototype._pastebin = function(data, callback) {
jQuery.ajax({url: "http://putco.de/", type: "PUT", data: data, context: this})
jQuery.ajax({url: "https://putco.de/", type: "PUT", data: data, context: this})
.success(function(e) {
callback.call(this, e.trim() + ".log");
}).fail(function(e) {

View file

@ -413,8 +413,8 @@ var is_android = navigator.userAgent.indexOf('Android') !== -1,
el.appendChild(label);
el.appendChild(help);
menu.appendChild(el);
jQuery('.html-tooltip', el).tipsy({html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
jQuery('.ffz-tooltip', el).tipsy({live: true, html: true, title: this.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
//jQuery('.html-tooltip', el).tipsy({html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
//jQuery('.ffz-tooltip', el).tipsy({live: true, html: true, title: this.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
}
container.appendChild(menu);

View file

@ -153,10 +153,12 @@ FFZ.prototype.ws_create = function() {
// Send the current rooms.
for(var room_id in f.rooms) {
if ( ! f.rooms.hasOwnProperty(room_id) || ! f.rooms[room_id] )
var room = f.rooms[room_id];
if ( ! f.rooms.hasOwnProperty(room_id) || ! room )
continue;
f.ws_send("sub", "room." + room_id);
room.room && room.room.ffzSubscribe && room.room.ffzSubscribe();
//f.ws_send("sub", "room." + room_id);
if ( f.rooms[room_id].needs_history ) {
f.rooms[room_id].needs_history = false;

View file

@ -719,6 +719,11 @@ FFZ.prototype.render_token = function(render_links, warn_links, token) {
return '<img class="emoticon ffz-tooltip' + (cls||'') + '"' + (extra||'') + ' src="' + utils.quote_attr(src) + '"' + (srcset ? ' srcset="' + utils.quote_attr(srcset) + '"' : '') + ' alt="' + utils.quote_attr(token.altText) + '">';
}
else if ( token.type === "tag" ) {
var link = Twitch.uri.game("Creative") + "/" + token.tag;
return '<a href="' + utils.quote_attr(link) + '" data-tag="' + utils.quote_attr(token.tag) + '" class="ffz-creative-tag-link">' + utils.sanitize(token.text) + '</a>';
}
else if ( token.type === "link" ) {
var text = token.title || (token.isLong && '<long link>') || (token.isDeleted && '<deleted link>') || (warn_links && '<whispered link>') || token.text;
@ -757,8 +762,8 @@ FFZ.prototype.render_token = function(render_links, warn_links, token) {
href = '#';
}
//return `<a class="ffz-tooltip ${cls}" data-text="${utils.quote_attr(token.text)}" data-url="${utils.quote_attr(actual_href)}" href="${utils.quote_attr(href||'#')}" target="_blank">${utils.sanitize(text)}</a>`;
return '<a class="ffz-tooltip' + (cls ? ' ' + cls : '') + '" data-text="' + utils.quote_attr(token.text) + '" data-url="' + utils.quote_attr(actual_href) + '" href="' + utils.quote_attr(href||'#') + '" target="_blank">' + utils.sanitize(text) + '</a>';
//return `<a class="ffz-tooltip ${cls}" data-text="${utils.quote_attr(token.text)}" data-url="${utils.quote_attr(actual_href)}" href="${utils.quote_attr(href||'#')}" target="_blank" rel="noopener">${utils.sanitize(text)}</a>`;
return '<a class="ffz-tooltip' + (cls ? ' ' + cls : '') + '" data-text="' + utils.quote_attr(token.text) + '" data-url="' + utils.quote_attr(actual_href) + '" href="' + utils.quote_attr(href||'#') + '" target="_blank" rel="noopener">' + utils.sanitize(text) + '</a>';
}
else if ( token.type === "deleted" )
@ -785,6 +790,58 @@ FFZ.prototype.render_tokens = function(tokens, render_links, warn_links) {
}
// ---------------------
// Creative Tags
// ---------------------
FFZ.prototype.tokenize_ctags = function(tokens) {
"use strict";
if ( typeof tokens === "string" )
tokens = [tokens];
var banned_tags = window.SiteOptions && SiteOptions.creative_banned_tags && SiteOptions.creative_banned_tags.split(',') || [],
new_tokens = [];
for(var i=0, l = tokens.length; i < l; i++) {
var token = tokens[i];
if ( ! token )
continue;
if ( typeof token !== "string" )
if ( token.type === "text" )
token = token.text;
else {
new_tokens.push(token);
continue;
}
var segments = token.split(' '),
text = [], segment, tag;
for(var x=0,y=segments.length; x < y; x++) {
segment = segments[x];
tag = segment.substr(1).toLowerCase();
if ( segment.charAt(0) === '#' && banned_tags.indexOf(tag) === -1 ) {
if ( text.length ) {
new_tokens.push({type: "text", text: text.join(' ') + ' '});
text = [];
}
new_tokens.push({type: "tag", text: segment, tag: tag});
text.push('');
} else
text.push(segment);
}
if ( text.length > 1 || (text.length === 1 && text[0] !== '') )
new_tokens.push({type: "text", text: text.join(' ')});
}
return new_tokens;
}
// ---------------------
// Emoticon Processing
// ---------------------

View file

@ -79,6 +79,41 @@ var include_html = function(heading_text, filename) {
render_news = include_html("news", constants.SERVER + "script/news.html");
var make_line = function(key, container) {
var desc = NICE_DESCRIPTION.hasOwnProperty(key) ? NICE_DESCRIPTION[key] : key;
if ( ! desc )
return;
line = createElement('li', null, desc + '<span></span>');
line.setAttribute('data-property', key);
container.appendChild(line);
return line;
};
var update_mem_stats = function(container) {
if ( ! document.querySelector('.ffz-ui-sub-menu-page[data-page="debugging"]') )
return;
setTimeout(update_mem_stats.bind(this, container), 1000);
var mem = window.performance && performance.memory;
if ( ! mem )
return;
var sorted_keys = ['jsHeapSizeLimit', 'totalJSHeapSize', 'usedJSHeapSize'];
for(var i=0; i < sorted_keys.length; i++) {
var key = sorted_keys[i],
data = mem[key],
line = container.querySelector('li[data-property="' + key + '"]');
if ( ! line )
line = make_line(key, container);
if ( line )
line.querySelector('span').textContent = utils.format_size(data) + ' (' + data + ')';
}
};
var update_player_stats = function(player, container) {
if ( ! document.querySelector('.ffz-ui-sub-menu-page[data-page="debugging"]') || ! player.getVideoInfo )
return;
@ -100,16 +135,10 @@ var update_player_stats = function(player, container) {
data = player_data[key],
line = container.querySelector('li[data-property="' + key + '"]');
if ( ! line ) {
var desc = NICE_DESCRIPTION.hasOwnProperty(key) ? NICE_DESCRIPTION[key] : key;
if ( ! desc )
continue;
line = createElement('li', null, desc + '<span></span>');
line.setAttribute('data-property', key);
container.appendChild(line);
}
if ( ! line )
line = make_line(key, container);
if ( line )
line.querySelector('span').textContent = data;
}
};
@ -270,6 +299,10 @@ FFZ.menu_pages.about = {
['Deploy Flavor', SiteOptions.deploy_flavor]
],
has_memory = window.performance && performance.memory,
mem_head = createElement('div'),
mem_list = createElement('ul'),
player_head = createElement('div'),
player_list = createElement('ul'),
@ -279,6 +312,7 @@ FFZ.menu_pages.about = {
vers = createElement('ul'),
version_list = [
['Ember', Ember.VERSION],
['Ember Data', window.DS && DS.VERSION || '<i>unknown</i>'],
['GIT Version', EmberENV.GIT_VERSION],
null,
['FrankerFaceZ', FFZ.version_info.toString()]
@ -302,9 +336,8 @@ FFZ.menu_pages.about = {
heading.className = 'chat-menu-content center';
heading.innerHTML = '<h1>FrankerFaceZ</h1><div class="ffz-about-subheading">woofs for nerds</div>';
info_head.className = twitch_head.className = player_head.className = ver_head.className = log_head.className = 'list-header';
info.className = twitch.className = player_list.className = vers.className = 'chat-menu-content menu-side-padding version-list';
info_head.className = mem_head.className = twitch_head.className = player_head.className = ver_head.className = log_head.className = 'list-header';
info.className = mem_list.className = twitch.className = player_list.className = vers.className = 'chat-menu-content menu-side-padding version-list';
info_head.innerHTML = 'Client Status';
@ -351,13 +384,6 @@ FFZ.menu_pages.about = {
twitch.appendChild(line);
}
if ( player_data ) {
player_head.innerHTML = "Player Statistics";
update_player_stats(player, player_list);
}
ver_head.innerHTML = 'Versions';
if ( this.has_bttv )
@ -395,7 +421,18 @@ FFZ.menu_pages.about = {
container.appendChild(twitch_head);
container.appendChild(twitch);
if ( has_memory ) {
mem_head.innerHTML = 'Memory Statistics';
setTimeout(update_mem_stats.bind(this,mem_list),0);
container.appendChild(mem_head);
container.appendChild(mem_list);
}
if ( player_data ) {
player_head.innerHTML = "Player Statistics";
setTimeout(update_player_stats.bind(this,player,player_list),0);
container.appendChild(player_head);
container.appendChild(player_list);
}

View file

@ -2,12 +2,29 @@ var FFZ = window.FrankerFaceZ,
utils = require('../utils'),
constants = require('../constants'),
FOLLOWING_CONTAINERS = [
['#small_nav ul.game_filters li[data-name="following"] a', true],
['nav a.warp__tipsy[data-href="following"]', true],
['#large_nav #nav_personal li[data-name="following"] a', false],
['#header_actions #header_following', false]
],
FOLLOW_GRAVITY = function(f, el) {
return (f.settings.following_count && el.parentElement.getAttribute('data-name') === 'following' ? 'n' : '') + (f.settings.swap_sidebars ? 'e' : 'w');
return (f.settings.following_count && (
el.getAttribute('data-href') === 'following' ||
el.parentElement.getAttribute('data-name') === 'following'
) ? 'n' : '') +
(f.settings.swap_sidebars ? 'e' : 'w');
},
WIDE_TIP = function(f, el) {
return ( ! f.settings.following_count || (el.id !== 'header_following' && el.parentElement.getAttribute('data-name') !== 'following') ) ? '' : 'ffz-wide-tip';
return (f.settings.following_count && (
el.id === 'header_following' ||
el.getAttribute('data-href') === 'following' ||
el.parentElement.getAttribute('data-name') === 'following'
)) ? 'ffz-wide-tip' : '';
};
@ -49,6 +66,7 @@ FFZ.prototype.setup_following_count = function(has_ember) {
// Tooltips~!
this._install_following_tooltips();
setTimeout(this._install_following_tooltips.bind(this), 2000);
// If we don't have Ember, no point in trying this stuff.
if ( ! has_ember )
@ -76,15 +94,20 @@ FFZ.prototype.setup_following_count = function(has_ember) {
if ( HostLive )
HostLive.load();*/
var init = function() {
var total = Live.get('total'),
streams = Live.get('content');
if ( typeof total === "number" ) {
this._draw_following_count(total);
f._draw_following_count(total);
if ( streams && streams.length )
this._draw_following_channels(streams, total);
f._draw_following_channels(streams, total);
}
}
init()
setTimeout(init, 2000);
}
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.
@ -161,7 +184,7 @@ FFZ.prototype._update_following_count = function() {
FFZ.prototype._build_following_tooltip = function(el) {
if ( el.id !== 'header_following' && el.parentElement.getAttribute('data-name') !== 'following' )
if ( el.id !== 'header_following' && el.getAttribute('data-href') !== 'following' && el.parentElement.getAttribute('data-name') !== 'following' )
return el.getAttribute('original-title');
if ( ! this.settings.following_count )
@ -262,43 +285,24 @@ FFZ.prototype._build_following_tooltip = function(el) {
FFZ.prototype._install_following_tooltips = function() {
var f = this,
gravity = function() { return FOLLOW_GRAVITY(f, this) },
data = {
html: true,
className: function() { return WIDE_TIP(f, this); },
title: function() { return f._build_following_tooltip(this); }
};
// Small
var small_following = jQuery('#small_nav ul.game_filters li[data-name="following"] a');
if ( small_following && small_following.length ) {
var td = small_following.data('tipsy');
for(var i=0; i < FOLLOWING_CONTAINERS.length; i++) {
var following = jQuery(FOLLOWING_CONTAINERS[i][0]);
if ( following && following.length ) {
var td = following.data('tipsy');
if ( td && td.options ) {
td.options = _.extend(td.options, data);
td.options.gravity = function() { return FOLLOW_GRAVITY(f, this); };
if ( FOLLOWING_CONTAINERS[i][1] )
td.options.gravity = gravity;
} else
small_following.tipsy(_.extend({gravity: function() { return FOLLOW_GRAVITY(f, this); }}, data));
following.tipsy(FOLLOWING_CONTAINERS[i][1] ? _.extend({gravity: gravity}, data) : data);
}
// Large
var large_following = jQuery('#large_nav #nav_personal li[data-name="following"] a');
if ( large_following && large_following.length ) {
var td = large_following.data('tipsy');
if ( td && td.options )
td.options = _.extend(td.options, data);
else
large_following.tipsy(data);
}
// Heading
var head_following = jQuery('#header_actions #header_following');
if ( head_following && head_following.length ) {
var td = head_following.data('tipsy');
if ( td && td.options )
td.options = _.extend(td.options, data);
else
head_following.tipsy(data);
}
}
@ -310,55 +314,22 @@ FFZ.prototype._draw_following_channels = function(streams, total) {
FFZ.prototype._draw_following_count = function(count) {
// Small
var small_following = document.querySelector('#small_nav ul.game_filters li[data-name="following"] a');
if ( small_following ) {
var badge = small_following.querySelector('.ffz-follow-count');
count = count ? utils.format_unread(count) : '';
for(var i=0; i < FOLLOWING_CONTAINERS.length; i++) {
var container = document.querySelector(FOLLOWING_CONTAINERS[i][0]),
badge = container && container.querySelector('.ffz-follow-count');
if ( ! container )
continue;
if ( this.has_bttv || ! this.settings.following_count ) {
if ( badge )
badge.parentElement.removeChild(badge);
} else {
if ( ! badge ) {
badge = document.createElement('span');
badge.className = 'ffz-follow-count';
small_following.appendChild(badge);
}
badge.innerHTML = count ? utils.format_unread(count) : '';
}
container.removeChild(badge);
continue;
} else if ( ! badge ) {
badge = utils.createElement('span', 'ffz-follow-count');
container.appendChild(badge);
}
// Large
var large_following = document.querySelector('#large_nav #nav_personal li[data-name="following"] a');
if ( large_following ) {
var badge = large_following.querySelector('.ffz-follow-count');
if ( this.has_bttv || ! this.settings.following_count ) {
if ( badge )
badge.parentElement.removeChild(badge);
} else {
if ( ! badge ) {
badge = document.createElement('span');
badge.className = 'ffz-follow-count';
large_following.appendChild(badge);
}
badge.innerHTML = count ? utils.format_unread(count) : '';
}
}
// Heading
var head_following = document.querySelector('#header_actions #header_following');
if ( head_following ) {
var badge = head_following.querySelector('.ffz-follow-count');
if ( this.has_bttv || ! this.settings.following_count ) {
if ( badge )
badge.parentElement.removeChild(badge);
} else {
if ( ! badge ) {
badge = document.createElement('span');
badge.className = 'ffz-follow-count';
head_following.appendChild(badge);
}
badge.innerHTML = count ? utils.format_unread(count) : '';
}
badge.innerHTML = count;
}
}

View file

@ -2,6 +2,8 @@ var FFZ = window.FrankerFaceZ,
constants = require('../constants'),
utils = require('../utils'),
IS_OSX = constants.IS_OSX,
reported_sets = [],
fix_menu_position = function(container) {
@ -218,8 +220,8 @@ FFZ.prototype.build_ui_popup = function(view) {
container.classList.toggle('dark', dark);
// Stuff
jQuery(inner).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')});
jQuery(inner).find('.ffz-tooltip').tipsy({live: true, html: true, title: this.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
//jQuery(inner).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')});
//jQuery(inner).find('.ffz-tooltip').tipsy({live: true, html: true, title: this.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
// Menu Container
var sub_container = document.createElement('div');
@ -761,7 +763,7 @@ FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, image, sub
if ( api && api.emote_url_generator )
url = api.emote_url_generator(set.source_id, id);
} else
url = "https://www.frankerfacez.com/emoticons/" + id;
url = "https://www.frankerfacez.com/emoticon/" + id;
if ( url )
window.open(url);
} else
@ -781,7 +783,7 @@ FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, image, sub
FFZ.prototype._add_emote = function(view, emote, favorites_set, favorites_key, event) {
if ( event && event.ctrlKey ) {
if ( event && ((!IS_OSX && event.ctrlKey) || (IS_OSX && event.metaKey)) ) {
var el = event.target;
if ( ! el.classList.contains('locked') && el.classList.contains('ffz-can-favorite') && favorites_set && favorites_key ) {
var favs = this.settings.favorite_emotes[favorites_set] = this.settings.favorite_emotes[favorites_set] || [],

View file

@ -129,7 +129,7 @@ FFZ.menu_pages.myemotes = {
var el = document.createElement("div");
el.className = "emoticon-grid ffz-no-emotes center";
el.innerHTML = "You have no favorite emoticons.<br> <img src=\"//cdn.frankerfacez.com/emoticon/26608/2\"><br>To make an emote a favorite, find it on the <nobr>All Emoticons</nobr> tab and <nobr>Ctrl-Click</nobr> it.";
el.innerHTML = "You have no favorite emoticons.<br> <img src=\"//cdn.frankerfacez.com/emoticon/26608/2\"><br>To make an emote a favorite, find it on the <nobr>All Emoticons</nobr> tab and <nobr>" + (constants.IS_OSX ? '⌘' : 'Ctrl') + "-Click</nobr> it.";
container.appendChild(el);
}
},

View file

@ -8,6 +8,11 @@ var FFZ = window.FrankerFaceZ,
// ---------------------
FFZ.prototype.fix_tooltips = function() {
// Add handlers to FFZ's tooltip classes.
jQuery(".html-tooltip").tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
jQuery(".ffz-tooltip").tipsy({live: true, html: true, title: this.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
// First, override the tooltip mixin.
var TipsyTooltip = utils.ember_resolve('component:tipsy-tooltip');
if ( TipsyTooltip ) {

View file

@ -467,6 +467,19 @@ module.exports = FFZ.utils = {
return "" + count;
},
format_size: function(bits) {
if(Math.abs(bits) < 1024)
return bits + ' b';
var units = ['Kb','Mb','Gb','Tb','Pb','Eb','Zb','Yb'],
u = -1;
do {
bits /= 1024;
++u;
} while(Math.abs(bits) >= 1024 && u < units.length - 1);
return bits.toFixed(1) + ' ' + units[u];
},
escape_regex: escape_regex,
createElement: function(tag, className, content) {

View file

@ -19,6 +19,7 @@ body > div.tipsy .tipsy-arrow { opacity: 0.8; }
cursor: pointer;
}
.ffz-hide-recommended-friends .recommended-friends,
.ffz-hide-recommended-channels .js-recommended-channels,
.ffz-hide-recent-past-broadcast .recent-past-broadcast,
.ffz-hide-view-count .stat.twitch-channel-views,
@ -1235,6 +1236,24 @@ img.channel_background[src="null"] { display: none; }
padding: 0 5px;
}
.ember-chat .ffz-moderation-card .mod-controls button {
width: auto;
margin-right: 10px;
}
.ffz-moderation-card .follow-button,
.ffz-moderation-card .friend-button { max-height: 30px }
.ffz-moderation-card .right button:last-of-type,
.ffz-moderation-card .mod-controls button:last-of-type { margin-right: 0 }
.ffz-moderation-card .follow-button a {
text-indent: -9999px;
padding-right: 0 !important;
}
.ffz-moderation-card .button.glyph-only { padding: 0 !important }
.ffz-moderation-card button:not(.glyph-only):hover,
.ffz-moderation-card button:not(.glyph-only):focus {
color: #fff;
@ -1242,7 +1261,7 @@ img.channel_background[src="null"] { display: none; }
}
.ffz-moderation-card button.message {
height: 30px; width: 28px;
height: 30px;
}
.ffz-moderation-card.ffz-is-mod .interface .mod-controls:last-of-type,
@ -1994,8 +2013,8 @@ body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-inter
}
.ffz-sidebar-swap #left_close {
right: auto;
left: -25px;
right: 5px;
left: auto;
}
.ffz-sidebar-swap #main_col {
@ -2226,11 +2245,13 @@ li[data-name="following"] a {
background-color: rgba(25,25,25,0.5);
}
#left_col.open .warp__item .ffz-follow-count,
#large_nav .ffz-follow-count,
.ffz-dark #header_following .ffz-follow-count {
background-color: rgba(127,127,127,0.5);
}
#left_col.open .warp__item .ffz-follow-count,
#large_nav .ffz-follow-count {
position: absolute;
right: 10px;
@ -2240,6 +2261,12 @@ li[data-name="following"] a {
padding: 2px 5px;
}
#left_col.open .warp__item .ffz-follow-count {
top: 6px;
right: 20px;
}
#left_col.closed .warp__item .ffz-follow-count,
#small_nav .ffz-follow-count {
position: absolute;
bottom: 2px;
@ -2644,41 +2671,13 @@ body:not(.ffz-top-conversations) .conversations-list-bottom-bar {
/* Creative Directory */
.ffz-creative-tags .creativetag-list.filter-list,
.ffz-creative-tags .creativetag-list ul,
.ffz-creative-tags .creativetag-list-contain {
width: inherit;
height: inherit;
overflow: inherit;
}
.ffz-top-conversations .ct-banner { margin-top: -50px }
.ffz-top-conversations .ct-banner__feature { top: 40px; margin-bottom: 0 }
body:not(.ffz-creative-showcase) .creative-hero,
.ffz-creative-tags .creativetag-list-contain .filter-nav { display: none; }
body:not(.ffz-tags-on-channel) #broadcast-meta .ct-tags,
body:not(.ffz-creative-showcase) .ct-gallery { display: none; }
.ffz-creative-tags .creativetag-list ul {
display: flex;
flex-wrap: wrap;
position: inherit;
margin-bottom: -5px;
}
.ffz-creative-tags .creativetag-list li {
flex-grow: 1;
height: inherit;
float: none;
margin: 0 0 5px;
}
.ffz-creative-tags .creativetag-list a {
display: block;
text-align: center;
padding: 5px 10px;
}
.ffz-creative-tags .creativetag-list a.active {
color: #fff !important;
background-color: #6441a5 !important;
}
body:not(.ffz-tags-on-channel) .tw-title--tall { height: 60px }
/* Content-Box~! Down with Twitch randomly changing the box-sizing for everything! */
@ -2732,8 +2731,21 @@ body:not(.ffz-creative-showcase) .creative-hero,
line-height: 40px;
}
/* Banned and Spoiler Games */
.ffz-game-spoilered .thumb .cap img,
.ffz-game-banned { display: none }
.ffz-game-spoilered .thumb .cap {
position: absolute !important; top: 0; left: 0; bottom: 0; right: 0;
background: url("https://static-cdn.jtvnw.net/ttv-static/404_preview-320x180.jpg") no-repeat !important;
background-size: cover !important;
}
/* Dashboard Channel Feed */
.activity-card .emoticon-selector .tabs { display: none }
.ffz-feed-button span { line-height: 30px; }
#ffz-feed-tabs .tabs { margin-bottom: 10px }
#ffz-feed-tabs textarea { resize: vertical }
@ -2748,3 +2760,7 @@ body.ffz-bttv #ffz-feed-tabs .tabs li:not(.selected):not(:hover) a { color: #644
body.ffz-bttv-dark #ffz-feed-tabs .tabs li:not(.selected):not(:hover) a { color: #999; }
body.ffz-bttv #ffz-feed-tabs .tabs { margin-bottom: 0 }
/* New Sidebar */
.warp__anchor { height: 5.5rem }