mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-19 04:20:54 +00:00
Commiting code in 2016 LOL (See changelog.html I'm a bad person)
This commit is contained in:
parent
8cfef363f1
commit
86b66bb8f5
34 changed files with 2175 additions and 1732 deletions
89
dark.css
89
dark.css
|
@ -361,11 +361,11 @@ body.ffz-dark:not([data-page="teams#show"]),
|
||||||
color: #a68ed2;
|
color: #a68ed2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ffz-dark .button.button--icon-only svg path {
|
.ffz-dark .button.button--icon-only svg {
|
||||||
fill: #a68ed2;
|
fill: #a68ed2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ffz-dark .button.button--icon-only:hover svg path {
|
.ffz-dark .button.button--icon-only:hover svg {
|
||||||
fill: #fff;
|
fill: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,11 +483,6 @@ body.ffz-dark:not([data-page="teams#show"]),
|
||||||
fill: rgba(255,255,255,0.5);
|
fill: rgba(255,255,255,0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ffz-dark .following-col .col-header,
|
|
||||||
.ffz-dark .following-col .header {
|
|
||||||
border-color: #32323e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ffz-dark .following-col .following-list .load-more span,
|
.ffz-dark .following-col .following-list .load-more span,
|
||||||
.ffz-dark .viewall a {
|
.ffz-dark .viewall a {
|
||||||
background-color: rgb(25,25,31);
|
background-color: rgb(25,25,31);
|
||||||
|
@ -1176,10 +1171,73 @@ body.ffz-dark:not([data-page="teams#show"]),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Creative UI */
|
||||||
|
|
||||||
|
.ffz-dark .ct-spotlight__right {
|
||||||
|
background-color: #121212;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-dark .ct-spotlight__controls-container {
|
||||||
|
background-color: #161616;
|
||||||
|
box-shadow: -1px 0 0 #303030 inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-dark .ct-bar {
|
||||||
|
background-color: #121212;
|
||||||
|
box-shadow:
|
||||||
|
0 2px 6px -2px rgba(255,255,255,0.1),
|
||||||
|
0 1px 0 rgba(255,255,255,0.05),
|
||||||
|
0 -1px 0 rgba(255,255,255,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-dark .ct-banner__name,
|
||||||
|
.ffz-dark .ct-banner__status,
|
||||||
|
.ffz-dark .ct-type-2,
|
||||||
|
.ffz-dark .ct-type-4 {
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-dark .ct-type-grey-light {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.ffz-dark .ct-crumb:after {
|
||||||
|
box-shadow: 12px -6px 24px -8px rgba(255,255,255,0.1);
|
||||||
|
border-color: #303030;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-dark .ct-spotlight__avatar {
|
||||||
|
box-shadow: 0 0 0 1px #303030, 0 2px 3px #303030;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-dark .ct-spotlight__right--col .ct-spotlight__card-container {
|
||||||
|
box-shadow: 0 -1px 0 #303030 inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-dark hr,
|
||||||
|
.ffz-dark .ct-spotlight__section,
|
||||||
|
.ffz-dark .balloon__stroke,
|
||||||
|
.ffz-dark .ct-spotlight__avatar,
|
||||||
|
.ffz-dark .ct-bar__item {
|
||||||
|
border-color: #303030;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-dark .ct-crumb--1:after,
|
||||||
|
.ffz-dark .ct-crumb--1 .ct-crumb__label {
|
||||||
|
background-color: #121212;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-dark .ct-crumb--2:after,
|
||||||
|
.ffz-dark .ct-crumb--2 .ct-crumb__label {
|
||||||
|
background-color: #161616;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Creative Tags */
|
/* Creative Tags */
|
||||||
|
|
||||||
.ffz-dark .ct-tags__tag {
|
.ffz-dark .ct-tags__tag {
|
||||||
background-color: #191919;
|
background-color: #121212;
|
||||||
color: #999 !important;
|
color: #999 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1228,6 +1286,7 @@ body.ffz-dark:not([data-page="teams#show"]),
|
||||||
}
|
}
|
||||||
|
|
||||||
.ffz-dark .activity-meta-divider:before,
|
.ffz-dark .activity-meta-divider:before,
|
||||||
|
.ffz-dark .list-load-more,
|
||||||
.ffz-dark .activity-card {
|
.ffz-dark .activity-card {
|
||||||
border-color: #474747;
|
border-color: #474747;
|
||||||
}
|
}
|
||||||
|
@ -1244,6 +1303,20 @@ body.ffz-dark:not([data-page="teams#show"]),
|
||||||
.ffz-dark .activity-meta__name { color: #ccc }
|
.ffz-dark .activity-meta__name { color: #ccc }
|
||||||
|
|
||||||
|
|
||||||
|
.ffz-dark .activity-card__comments {
|
||||||
|
background-color: #121212;
|
||||||
|
box-shadow:inset 0 1px 0 #474747;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-dark .activity-add-comment__textarea:before {
|
||||||
|
background: #1d1d1d;
|
||||||
|
border-left-color: #474747;
|
||||||
|
border-bottom-color: #474747;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inherit-color { color: inherit !important }
|
||||||
|
|
||||||
|
|
||||||
/* Search Panel */
|
/* Search Panel */
|
||||||
|
|
||||||
.ffz-dark[data-current-path="user.channel.index.index"] .searchPanel { background-color: rgba(16,16,16,0.9) }
|
.ffz-dark[data-current-path="user.channel.index.index"] .searchPanel { background-color: rgba(16,16,16,0.9) }
|
||||||
|
|
14
gulpfile.js
14
gulpfile.js
|
@ -221,20 +221,6 @@ gulp.task('server', function() {
|
||||||
fs.exists(file, function(exists) {
|
fs.exists(file, function(exists) {
|
||||||
if ( ! exists ) {
|
if ( ! exists ) {
|
||||||
util.log("[" + util.colors.cyan("HTTP") + "] " + util.colors.bold.blue("CDN") + " GET " + util.colors.magenta(uri));
|
util.log("[" + util.colors.cyan("HTTP") + "] " + util.colors.bold.blue("CDN") + " GET " + util.colors.magenta(uri));
|
||||||
/*https.request({
|
|
||||||
hostname: 'cdn.frankerfacez.com',
|
|
||||||
port: 443,
|
|
||||||
path: uri,
|
|
||||||
method: 'GET'
|
|
||||||
}, function(cli_res) {
|
|
||||||
res.writeHead(cli_res.statusCode, cli_res.headers);
|
|
||||||
cli_res.on('data', function(chunk) { res.write(chunk); });
|
|
||||||
cli_res.on('end', function() { res.end() });
|
|
||||||
}).on('error', function(e) {
|
|
||||||
res.writeHead(502, {"Access-Control-Allow-Origin": "*"});
|
|
||||||
res.write('502 Bad Gateway');
|
|
||||||
res.end();
|
|
||||||
});*/
|
|
||||||
return request.get("http://cdn.frankerfacez.com/" + uri).on('error', function(err) { res.end() }).pipe(res);
|
return request.get("http://cdn.frankerfacez.com/" + uri).on('error', function(err) { res.end() }).pipe(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
107
src/badges.js
107
src/badges.js
|
@ -3,7 +3,11 @@ var FFZ = window.FrankerFaceZ,
|
||||||
utils = require('./utils'),
|
utils = require('./utils'),
|
||||||
|
|
||||||
SPECIAL_BADGES = ['staff', 'admin', 'global_mod'],
|
SPECIAL_BADGES = ['staff', 'admin', 'global_mod'],
|
||||||
OTHER_KNOWN = ['turbo', 'warcraft'],
|
OTHER_KNOWN = ['turbo', 'warcraft', 'bits'],
|
||||||
|
|
||||||
|
NO_INVERT_BADGES = ['subscriber', 'ffz-badge-1'],
|
||||||
|
INVERT_INVERT_BADGES = ['bits'],
|
||||||
|
TRANSPARENT_BADGES = ['subscriber'],
|
||||||
|
|
||||||
BTTV_TYPE_REPLACEMENTS = {
|
BTTV_TYPE_REPLACEMENTS = {
|
||||||
'global-moderator': 'global_mod'
|
'global-moderator': 'global_mod'
|
||||||
|
@ -25,14 +29,6 @@ var FFZ = window.FrankerFaceZ,
|
||||||
|
|
||||||
BADGE_KLASSES = {
|
BADGE_KLASSES = {
|
||||||
'global_mod': 'global-moderator'
|
'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." + klass + ",.ffz-transparent-badges .badges ." + klass + ' { background-image: url("' + badge.alpha_image + '"); }';
|
|
||||||
return out;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,8 +88,13 @@ FFZ.settings_info.hidden_badges = {
|
||||||
}
|
}
|
||||||
|
|
||||||
for(var badge_id in f.badges) {
|
for(var badge_id in f.badges) {
|
||||||
if ( f.badges.hasOwnProperty(badge_id) && f.badges[badge_id].name )
|
if ( ! f.badges.hasOwnProperty(badge_id) )
|
||||||
values.push('<code>ffz-' + f.badges[badge_id].name + '</code>');
|
continue;
|
||||||
|
|
||||||
|
var badge = f.badges[badge_id],
|
||||||
|
hide_key = (badge.source_ext ? f._apis[badge.source_ext].name_key : 'ffz') + '-' + (badge.name || badge.id);
|
||||||
|
|
||||||
|
values.push('<code>' + hide_key + '</code>');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( this.has_bttv && window.BetterTTV ) {
|
if ( this.has_bttv && window.BetterTTV ) {
|
||||||
|
@ -129,11 +130,13 @@ FFZ.settings_info.sub_notice_badges = {
|
||||||
|
|
||||||
category: "Chat Appearance",
|
category: "Chat Appearance",
|
||||||
name: "Old-Style Subscriber Notice Badges",
|
name: "Old-Style Subscriber Notice Badges",
|
||||||
|
no_bttv: true,
|
||||||
|
|
||||||
help: "Display a subscriber badge on old-style chat messages about new subscribers.",
|
help: "Display a subscriber badge on old-style chat messages about new subscribers.",
|
||||||
|
|
||||||
on_update: function(val) {
|
on_update: function(val) {
|
||||||
this.toggle_style('badges-sub-notice', ! val);
|
this.toggle_style('badges-sub-notice', ! this.has_bttv && ! val);
|
||||||
this.toggle_style('badges-sub-notice-on', val);
|
this.toggle_style('badges-sub-notice-on', ! this.has_bttv && val);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -269,7 +272,7 @@ FFZ.ws_commands.set_badge = function(data) {
|
||||||
badges = user.badges = user.badges || {};
|
badges = user.badges = user.badges || {};
|
||||||
|
|
||||||
if ( badge === undefined || badge === null )
|
if ( badge === undefined || badge === null )
|
||||||
delete badges[slot];
|
badges[slot] = null;
|
||||||
else
|
else
|
||||||
badges[slot] = badge;
|
badges[slot] = badge;
|
||||||
}
|
}
|
||||||
|
@ -287,14 +290,16 @@ FFZ.prototype.get_badges = function(user, room_id, badges, msg) {
|
||||||
return badges;
|
return badges;
|
||||||
|
|
||||||
for(var slot in data.badges) {
|
for(var slot in data.badges) {
|
||||||
if ( ! data.badges.hasOwnProperty(slot) )
|
var badge = data.badges[slot];
|
||||||
|
if ( ! data.badges.hasOwnProperty(slot) || ! badge )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var badge = data.badges[slot],
|
var full_badge = this.badges[badge.id] || {},
|
||||||
full_badge = this.badges[badge.id] || {},
|
old_badge = badges[slot],
|
||||||
old_badge = badges[slot];
|
|
||||||
|
|
||||||
if ( hidden_badges.indexOf('ffz-' + full_badge.name) !== -1 )
|
hide_key = (full_badge.source_ext ? this._apis[full_badge.source_ext].name_key : 'ffz') + '-' + (full_badge.name || full_badge.id);
|
||||||
|
|
||||||
|
if ( hidden_badges.indexOf(hide_key) !== -1 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ( full_badge.visible !== undefined ) {
|
if ( full_badge.visible !== undefined ) {
|
||||||
|
@ -319,10 +324,13 @@ FFZ.prototype.get_badges = function(user, room_id, badges, msg) {
|
||||||
|
|
||||||
badges[slot] = {
|
badges[slot] = {
|
||||||
klass: 'ffz-badge-' + badge.id,
|
klass: 'ffz-badge-' + badge.id,
|
||||||
title: badge.title || full_badge.title,
|
title: badge.title || full_badge.title || ('Unknown FFZ Badge\nID: ' + badge.id),
|
||||||
image: badge.image,
|
image: badge.image,
|
||||||
full_image: full_badge.image,
|
full_image: full_badge.image,
|
||||||
color: badge.color,
|
color: badge.color,
|
||||||
|
no_invert: badge.no_invert || full_badge.no_invert,
|
||||||
|
invert_invert: badge.invert_invert || full_badge.invert_invert,
|
||||||
|
transparent: badge.transparent || full_badge.transparent || (badge.color || full_badge.color) === "transparent",
|
||||||
extra_css: badge.extra_css
|
extra_css: badge.extra_css
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -390,12 +398,15 @@ FFZ.prototype.get_line_badges = function(msg) {
|
||||||
badges[last_id] = {
|
badges[last_id] = {
|
||||||
klass: (BADGE_KLASSES[badge] || badge) + (is_known ? '' : ' unknown-badge') + ' version-' + version,
|
klass: (BADGE_KLASSES[badge] || badge) + (is_known ? '' : ' unknown-badge') + ' version-' + version,
|
||||||
title: binfo && binfo.title || BADGE_NAMES[badge] || badge.capitalize(),
|
title: binfo && binfo.title || BADGE_NAMES[badge] || badge.capitalize(),
|
||||||
click_url: binfo && binfo.click_action === 'visit_url' && binfo.click_url
|
click_url: binfo && binfo.click_action === 'visit_url' && binfo.click_url,
|
||||||
|
no_invert: NO_INVERT_BADGES.indexOf(badge) !== -1,
|
||||||
|
invert_invert: INVERT_INVERT_BADGES.indexOf(badge) !== -1,
|
||||||
|
transparent: TRANSPARENT_BADGES.indexOf(badge) !== -1
|
||||||
};
|
};
|
||||||
|
|
||||||
if ( ! is_known && binfo ) {
|
if ( ! is_known && binfo ) {
|
||||||
badges[last_id].image = binfo.image_url_1x;
|
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';
|
badges[last_id].srcSet = 'url("' + binfo.image_url_1x + '") 1x, url("' + binfo.image_url_2x + '") 2x, url("' + binfo.image_url_4x + '") 4x';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,13 +424,13 @@ FFZ.prototype.get_other_badges = function(user_id, room_id, user_type, has_sub,
|
||||||
for(var i=0, l = SPECIAL_BADGES.length; i < l; i++) {
|
for(var i=0, l = SPECIAL_BADGES.length; i < l; i++) {
|
||||||
var mb = SPECIAL_BADGES[i];
|
var mb = SPECIAL_BADGES[i];
|
||||||
if ( user_type === mb ) {
|
if ( user_type === mb ) {
|
||||||
badges[0] = {klass: BADGE_KLASSES[mb] || mb, title: BADGE_TITLES[mb] || mb.capitalize()};
|
badges[0] = {klass: BADGE_KLASSES[mb] || mb, title: BADGE_NAMES[mb] || mb.capitalize()};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( has_sub )
|
if ( has_sub )
|
||||||
badges[10] = {klass: 'subscriber', title: 'Subscriber'}
|
badges[10] = {klass: 'subscriber', title: 'Subscriber', no_invert: true, transparent: true}
|
||||||
if ( has_turbo )
|
if ( has_turbo )
|
||||||
badges[15] = {klass: 'turbo', title: 'Turbo'}
|
badges[15] = {klass: 'turbo', title: 'Turbo'}
|
||||||
|
|
||||||
|
@ -450,7 +461,16 @@ FFZ.prototype.render_badges = function(badges) {
|
||||||
if ( badge.click_url )
|
if ( badge.click_url )
|
||||||
klass += ' click_url';
|
klass += ' click_url';
|
||||||
|
|
||||||
out.push('<div class="badge float-left html-tooltip ' + utils.quote_attr(klass) + '"' + (badge.click_url ? ' data-url="' + utils.quote_attr(badge.click_url) + '"' : '') + (css ? ' style="' + utils.quote_attr(css) + '"' : '') + ' title="' + utils.quote_attr(badge.title) + '"></div>');
|
if ( badge.no_invert )
|
||||||
|
klass += ' no-invert';
|
||||||
|
|
||||||
|
if ( badge.invert_invert )
|
||||||
|
klass += ' invert-invert';
|
||||||
|
|
||||||
|
if ( badge.transparent )
|
||||||
|
klass += ' transparent';
|
||||||
|
|
||||||
|
out.push('<div class="badge html-tooltip ' + utils.quote_attr(klass) + '"' + (badge.click_url ? ' data-url="' + utils.quote_attr(badge.click_url) + '"' : '') + (css ? ' style="' + utils.quote_attr(css) + '"' : '') + ' title="' + utils.quote_attr(badge.title) + '"></div>');
|
||||||
}
|
}
|
||||||
|
|
||||||
return out.join("");
|
return out.join("");
|
||||||
|
@ -482,17 +502,27 @@ FFZ.prototype.bttv_badges = function(data) {
|
||||||
for(var i=0; i < data.badges.length; i++) {
|
for(var i=0; i < data.badges.length; i++) {
|
||||||
var badge = data.badges[i],
|
var badge = data.badges[i],
|
||||||
space_ind = badge.type.indexOf(' '),
|
space_ind = badge.type.indexOf(' '),
|
||||||
hidden_key = BTTV_TYPE_REPLACEMENTS[badge.type] || (space_ind === -1 ? badge.type : badge.type.substr(0, space_ind));
|
hidden_key = space_ind !== -1 ? badge.type.substr(0, space_ind) : badge.type;
|
||||||
|
|
||||||
|
if ( hidden_key.indexOf('twitch-') === 0 )
|
||||||
|
hidden_key = hidden_key.substr(7);
|
||||||
|
|
||||||
|
if ( BTTV_TYPE_REPLACEMENTS.hasOwnProperty(hidden_key) )
|
||||||
|
hidden_key = BTTV_TYPE_REPLACEMENTS[hidden_key];
|
||||||
|
else {
|
||||||
|
var ind = hidden_key.indexOf('-');
|
||||||
|
if ( ind !== -1 )
|
||||||
|
hidden_key = hidden_key.substr(0, ind);
|
||||||
|
}
|
||||||
|
|
||||||
if ( hidden_badges.indexOf(hidden_key) !== -1 ) {
|
if ( hidden_badges.indexOf(hidden_key) !== -1 ) {
|
||||||
data.badges.splice(i, 1);
|
data.badges.splice(i, 1);
|
||||||
|
i--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( badge.type === "subscriber" || badge.type === "turbo" || badge.type.substr(0, 8) === 'warcraft' ) {
|
if ( insert_at === -1 && (badge.type === "subscriber" || badge.type === "turbo" || badge.type.substr(0, 7) === 'twitch-') )
|
||||||
insert_at = i;
|
insert_at = i;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's no user, we're done now.
|
// If there's no user, we're done now.
|
||||||
|
@ -502,15 +532,17 @@ FFZ.prototype.bttv_badges = function(data) {
|
||||||
|
|
||||||
// We have a user. Start replacing badges.
|
// We have a user. Start replacing badges.
|
||||||
for (var slot in user.badges) {
|
for (var slot in user.badges) {
|
||||||
if ( ! user.badges.hasOwnProperty(slot) )
|
var badge = user.badges[slot];
|
||||||
|
if ( ! user.badges.hasOwnProperty(slot) || ! badge )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var badge = user.badges[slot],
|
var full_badge = this.badges[badge.id] || {},
|
||||||
full_badge = this.badges[badge.id] || {},
|
|
||||||
desc = badge.title || full_badge.title,
|
desc = badge.title || full_badge.title,
|
||||||
style = "";
|
style = "",
|
||||||
|
|
||||||
if ( hidden_badges.indexOf('ffz-' + full_badge.name) !== -1 )
|
hide_key = (full_badge.source_ext ? this._apis[full_badge.source_ext].name_key : 'ffz') + '-' + (full_badge.name || full_badge.id);
|
||||||
|
|
||||||
|
if ( hidden_badges.indexOf(hide_key) !== -1 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ( full_badge.visible !== undefined ) {
|
if ( full_badge.visible !== undefined ) {
|
||||||
|
@ -565,8 +597,6 @@ FFZ.prototype.bttv_badges = function(data) {
|
||||||
while(badges_out.length)
|
while(badges_out.length)
|
||||||
data.badges.insertAt(insert_at, badges_out.shift()[1]);
|
data.badges.insertAt(insert_at, badges_out.shift()[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -644,10 +674,13 @@ FFZ.prototype._load_badge_json = function(badge_id, data) {
|
||||||
data.replaces = true;
|
data.replaces = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( data.name === 'developer' )
|
||||||
|
data.no_invert = true;
|
||||||
|
|
||||||
if ( data.name === 'bot' )
|
if ( data.name === 'bot' )
|
||||||
data.visible = function(r,user) { return !(this.has_bttv && FFZ.bttv_known_bots.indexOf(user)!==-1); };
|
data.visible = function(r,user) { return !(this.has_bttv && FFZ.bttv_known_bots.indexOf(user)!==-1); };
|
||||||
|
|
||||||
utils.update_css(this._badge_style, badge_id, badge_css(data));
|
utils.update_css(this._badge_style, badge_id, utils.badge_css(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ var SVGPATH = 'm120.95 1.74c4.08-0.09 8.33-0.84 12.21 0.82 3.61 1.8 7 4.16 11.01
|
||||||
SERVER = DEBUG ? "//localhost:8000/" : "https://cdn.frankerfacez.com/",
|
SERVER = DEBUG ? "//localhost:8000/" : "https://cdn.frankerfacez.com/",
|
||||||
|
|
||||||
IS_OSX = navigator.platform ? navigator.platform.indexOf('Mac') !== -1 : /OS X/.test(navigator.userAgent),
|
IS_OSX = navigator.platform ? navigator.platform.indexOf('Mac') !== -1 : /OS X/.test(navigator.userAgent),
|
||||||
|
|
||||||
IS_WIN = navigator.platform ? navigator.platform.indexOf('Win') !== -1 : /Windows/.test(navigator.userAgent),
|
IS_WIN = navigator.platform ? navigator.platform.indexOf('Win') !== -1 : /Windows/.test(navigator.userAgent),
|
||||||
|
|
||||||
SEPARATORS = "[\\s`~<>!-#%-\\x2A,-/:;\\x3F@\\x5B-\\x5D_\\x7B}\\u00A1\\u00A7\\u00AB\\u00B6\\u00B7\\u00BB\\u00BF\\u037E\\u0387\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061E\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u0AF0\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166D\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u2329\\u232A\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E3B\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uAAF0\\uAAF1\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65]",
|
SEPARATORS = "[\\s`~<>!-#%-\\x2A,-/:;\\x3F@\\x5B-\\x5D_\\x7B}\\u00A1\\u00A7\\u00AB\\u00B6\\u00B7\\u00BB\\u00BF\\u037E\\u0387\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061E\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u0AF0\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166D\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u2329\\u232A\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E3B\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uAAF0\\uAAF1\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65]",
|
||||||
|
@ -44,6 +43,8 @@ module.exports = FrankerFaceZ.constants = {
|
||||||
SEPARATORS: SEPARATORS,
|
SEPARATORS: SEPARATORS,
|
||||||
SPLITTER: SPLITTER,
|
SPLITTER: SPLITTER,
|
||||||
|
|
||||||
|
UUID_TEST: /(?:^| +)([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}) *$/i,
|
||||||
|
|
||||||
KNOWN_CODES: {
|
KNOWN_CODES: {
|
||||||
"#-?[\\\\/]": "#-/",
|
"#-?[\\\\/]": "#-/",
|
||||||
":-?(?:7|L)": ":-7",
|
":-?(?:7|L)": ":-7",
|
||||||
|
|
112
src/ember/bits.js
Normal file
112
src/ember/bits.js
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
var FFZ = window.FrankerFaceZ,
|
||||||
|
utils = require('../utils'),
|
||||||
|
constants = require('../constants');
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------
|
||||||
|
// Settings
|
||||||
|
// --------------------
|
||||||
|
|
||||||
|
FFZ.settings_info.bits_animated = {
|
||||||
|
type: "boolean",
|
||||||
|
value: true,
|
||||||
|
|
||||||
|
category: "Chat Appearance",
|
||||||
|
no_bttv: true,
|
||||||
|
|
||||||
|
visible: function() {
|
||||||
|
var globals = utils.ember_lookup('service:globals'),
|
||||||
|
user = this.get_user();
|
||||||
|
|
||||||
|
return (globals && globals.get('isBitsEnabled')) || (user && user.is_staff);
|
||||||
|
},
|
||||||
|
|
||||||
|
name: "Bits Animation",
|
||||||
|
help: "Display bits with animation.",
|
||||||
|
|
||||||
|
on_update: utils.toggle_cls('ffz-animate-bits')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------
|
||||||
|
// Initialization
|
||||||
|
// --------------------
|
||||||
|
|
||||||
|
FFZ.prototype.setup_bits = function() {
|
||||||
|
utils.toggle_cls('ffz-animate-bits')(this.settings.bits_animated);
|
||||||
|
|
||||||
|
var f = this,
|
||||||
|
Service = utils.ember_lookup('service:bits-rendering-config');
|
||||||
|
if ( ! Service )
|
||||||
|
return this.error("Unable to locate the Ember service:bits-rendering-config");
|
||||||
|
|
||||||
|
Service.reopen({
|
||||||
|
ffz_get_tier: function(amount) {
|
||||||
|
var config = this.get('config'),
|
||||||
|
tiers = config.tiers || [],
|
||||||
|
tier = null,
|
||||||
|
index = null;
|
||||||
|
|
||||||
|
for(var i=0, l = tiers.length; i < l; i++) {
|
||||||
|
var t = tiers[i];
|
||||||
|
if ( amount < t.min_bits )
|
||||||
|
break;
|
||||||
|
|
||||||
|
tier = t;
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [index, tier];
|
||||||
|
},
|
||||||
|
|
||||||
|
ffz_get_preview: function(tier) {
|
||||||
|
return this._templateUrlConstructor(tier.image, "dark", (f.settings.bits_animated ? 'animated' : 'static'), 4);
|
||||||
|
},
|
||||||
|
|
||||||
|
_ffz_tier_css: function(ind, tier) {
|
||||||
|
var selector = '.ffz-bit.bit-tier-' + ind,
|
||||||
|
color = f._handle_color(tier.color),
|
||||||
|
|
||||||
|
template = 'url("' + this.get('config.templateUrl').replace('{background}', 'light').replace('{image}', tier.image) + '")',
|
||||||
|
template_srcset = template.replace('{scale}', 1) + ' 1x, ' + template.replace('{scale}', 2) + ' 2x, ' + template.replace('{scale}', 4) + ' 4x',
|
||||||
|
output;
|
||||||
|
|
||||||
|
output = selector + '{' +
|
||||||
|
'color: ' + color[0] + ';' +
|
||||||
|
'background-image: ' + template.replace('{scale}', 1).replace(/{state}/g, 'static') + ';' +
|
||||||
|
'background-image: -webkit-image-set(' + template_srcset.replace(/{state}/g, 'static') + ');' +
|
||||||
|
'}.ffz-animate-bits ' + selector + '{' +
|
||||||
|
'background-image: ' + template.replace('{scale}', 1).replace(/{state}/g, 'animated') + ';' +
|
||||||
|
'background-image: -webkit-image-set(' + template_srcset.replace(/{state}/g, 'animated') + ');' +
|
||||||
|
'}';
|
||||||
|
|
||||||
|
template = template.replace('/light/', '/dark/');
|
||||||
|
template_srcset = template_srcset.replace(/\/light\//g, '/dark/');
|
||||||
|
|
||||||
|
return output + '.tipsy ' + selector + ',.dark ' + selector + ',.force-dark ' + selector + ',.theatre ' + selector + '{' +
|
||||||
|
'color: ' + color[1] + ';' +
|
||||||
|
'background-image: ' + template.replace('{scale}', 1).replace(/{state}/g, 'static') + ';' +
|
||||||
|
'background-image: -webkit-image-set(' + template_srcset.replace(/{state}/g, 'static') + ');' +
|
||||||
|
'}.ffz-animate-bits .tipsy ' + selector + ',.ffz-animate-bits .dark ' + selector + ',.ffz-animate-bits .force-dark ' + selector + ',.ffz-animate-bits .theatre ' + selector + '{' +
|
||||||
|
'background-image: ' + template.replace('{scale}', 1).replace(/{state}/g, 'animated') + ';' +
|
||||||
|
'background-image: -webkit-image-set(' + template_srcset.replace(/{state}/g, 'animated') + ');' +
|
||||||
|
'}';
|
||||||
|
},
|
||||||
|
|
||||||
|
ffz_update_css: function() {
|
||||||
|
var tiers = this.get('config.tiers') || [],
|
||||||
|
output = [];
|
||||||
|
|
||||||
|
for(var i=0, l = tiers.length; i < l; i++)
|
||||||
|
output.push(this._ffz_tier_css(i, tiers[i]));
|
||||||
|
|
||||||
|
utils.update_css(f._chat_style, 'bit-styles', output.join(''));
|
||||||
|
|
||||||
|
}.observes('config')
|
||||||
|
});
|
||||||
|
|
||||||
|
if ( ! Service.get('isLoaded') )
|
||||||
|
Service.loadRenderConfig();
|
||||||
|
else
|
||||||
|
Service.ffz_update_css();
|
||||||
|
}
|
|
@ -19,55 +19,24 @@ FFZ.prototype.setup_channel = function() {
|
||||||
document.body.classList.toggle('ffz-theater-stats', this.settings.theater_stats);
|
document.body.classList.toggle('ffz-theater-stats', this.settings.theater_stats);
|
||||||
|
|
||||||
this.log("Hooking the Ember Channel Index view.");
|
this.log("Hooking the Ember Channel Index view.");
|
||||||
var Channel = utils.ember_resolve('view:channel/index'),
|
if ( ! this.update_views('view:channel/index', this.modify_channel_index) )
|
||||||
f = this;
|
|
||||||
|
|
||||||
if ( ! Channel )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._modify_cindex(Channel);
|
|
||||||
|
|
||||||
// The Stupid View Fix. Is this necessary still?
|
|
||||||
try {
|
|
||||||
Channel.create().destroy();
|
|
||||||
} catch(err) { }
|
|
||||||
|
|
||||||
// Update Existing
|
|
||||||
var views = utils.ember_views();
|
|
||||||
for(var key in views) {
|
|
||||||
var view = views[key];
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
this.log("Hooking the Ember Channel model.");
|
this.log("Hooking the Ember Channel model.");
|
||||||
Channel = utils.ember_resolve('model:channel');
|
var f = this,
|
||||||
|
Channel = utils.ember_resolve('model:deprecated-channel');
|
||||||
|
|
||||||
if ( ! Channel )
|
if ( ! Channel )
|
||||||
return;
|
return this.log("Unable to find the Ember model:deprecated-channel");
|
||||||
|
|
||||||
Channel.reopen({
|
this._modify_cmodel(Channel);
|
||||||
ffz_host_target: undefined,
|
|
||||||
|
|
||||||
setHostMode: function(e) {
|
var Store = utils.ember_lookup('service:store'),
|
||||||
if ( f.settings.hosted_channels ) {
|
type_map = Store && Store.typeMapFor(Channel);
|
||||||
this.set('ffz_host_target', e.target);
|
|
||||||
return this._super(e);
|
|
||||||
} else {
|
|
||||||
this.set('ffz_host_target', undefined);
|
|
||||||
return this._super({target: void 0, delay: 0});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
if ( type_map && type_map.records )
|
||||||
|
for(var i=0; i < type_map.records.length; i++)
|
||||||
|
this._modify_cmodel(type_map.records[i]);
|
||||||
|
|
||||||
this.log("Hooking the Ember Channel controller.");
|
this.log("Hooking the Ember Channel controller.");
|
||||||
|
|
||||||
|
@ -89,7 +58,7 @@ FFZ.prototype.setup_channel = function() {
|
||||||
if ( ! this.get('content.id') )
|
if ( ! this.get('content.id') )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._ffz_update_timer = setTimeout(this.ffzCheckUpdate.bind(this), 60000);
|
this._ffz_update_timer = setTimeout(this.ffzCheckUpdate.bind(this), 55000 + (Math.random() * 10000));
|
||||||
}.observes("content.id"),
|
}.observes("content.id"),
|
||||||
|
|
||||||
ffzCheckUpdate: function() {
|
ffzCheckUpdate: function() {
|
||||||
|
@ -130,7 +99,6 @@ FFZ.prototype.setup_channel = function() {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
ffzUpdateTitle: function() {
|
ffzUpdateTitle: function() {
|
||||||
var name = this.get('content.name'),
|
var name = this.get('content.name'),
|
||||||
display_name = this.get('content.display_name');
|
display_name = this.get('content.display_name');
|
||||||
|
@ -178,29 +146,28 @@ FFZ.prototype.setup_channel = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype._modify_cindex = function(view) {
|
FFZ.prototype._modify_cmodel = function(model) {
|
||||||
var f = this;
|
var f = this;
|
||||||
|
model.reopen({
|
||||||
|
ffz_host_target: undefined,
|
||||||
|
|
||||||
view.reopen({
|
setHostMode: function(e) {
|
||||||
didInsertElement: function() {
|
if ( f.settings.hosted_channels ) {
|
||||||
this._super();
|
this.set('ffz_host_target', e.target);
|
||||||
try {
|
return this._super(e);
|
||||||
this.ffzInit();
|
} else {
|
||||||
} catch(err) {
|
this.set('ffz_host_target', undefined);
|
||||||
f.error("CIndex didInsertElement: " + err);
|
return this._super({target: void 0, delay: 0});
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
willClearRender: function() {
|
|
||||||
try {
|
|
||||||
this.ffzTeardown();
|
|
||||||
} catch(err) {
|
|
||||||
f.error("CIndex willClearRender: " + err);
|
|
||||||
}
|
}
|
||||||
return this._super();
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
ffzInit: function() {
|
|
||||||
|
FFZ.prototype.modify_channel_index = function(view) {
|
||||||
|
var f = this;
|
||||||
|
utils.ember_reopen_view(view, {
|
||||||
|
ffz_init: function() {
|
||||||
var id = this.get('controller.content.id') || this.get('controller.id'),
|
var id = this.get('controller.content.id') || this.get('controller.id'),
|
||||||
el = this.get('element');
|
el = this.get('element');
|
||||||
|
|
||||||
|
@ -216,6 +183,10 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
this.ffzUpdateHostButton();
|
this.ffzUpdateHostButton();
|
||||||
this.ffzUpdatePlayerStats();
|
this.ffzUpdatePlayerStats();
|
||||||
|
|
||||||
|
// Listen to scrolling.
|
||||||
|
this._ffz_scroller = this.ffzOnScroll.bind(this);
|
||||||
|
jQuery(el).parents('.tse-scroll-content').on('scroll', this._ffz_scroller);
|
||||||
|
|
||||||
var views = this.get('element').querySelector('.svg-glyph_views:not(.ffz-svg)')
|
var views = this.get('element').querySelector('.svg-glyph_views:not(.ffz-svg)')
|
||||||
if ( views )
|
if ( views )
|
||||||
views.parentNode.classList.add('twitch-channel-views');
|
views.parentNode.classList.add('twitch-channel-views');
|
||||||
|
@ -242,6 +213,41 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ffz_destroy: function() {
|
||||||
|
var id = this.get('controller.content.id') || this.get('controller.id');
|
||||||
|
if ( id )
|
||||||
|
f.ws_send("unsub", "channel." + id);
|
||||||
|
|
||||||
|
this.get('element').setAttribute('data-channel', '');
|
||||||
|
f._cindex = undefined;
|
||||||
|
if ( this._ffz_update_uptime )
|
||||||
|
clearTimeout(this._ffz_update_uptime);
|
||||||
|
|
||||||
|
if ( this._ffz_update_stats )
|
||||||
|
clearTimeout(this._ffz_update_stats);
|
||||||
|
|
||||||
|
if ( this._ffz_scroller ) {
|
||||||
|
jQuery(this.get('element')).parents('.tse-scroll-content').off('scroll', this._ffz_scroller);
|
||||||
|
this._ffz_scroller = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.classList.remove('ffz-small-player');
|
||||||
|
utils.update_css(f._channel_style, id, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
ffzOnScroll: function(event) {
|
||||||
|
// When we scroll past the bottom of the player, do stuff!
|
||||||
|
var top = event && event.target && event.target.scrollTop,
|
||||||
|
height = this.get('layout.playerSize.1');
|
||||||
|
|
||||||
|
if ( ! top )
|
||||||
|
top = jQuery(this.get('element')).parents('.tse-scroll-content').scrollTop();
|
||||||
|
|
||||||
|
document.body.classList.toggle('ffz-small-player', f.settings.small_player && top >= height);
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
ffzFixTitle: function() {
|
ffzFixTitle: function() {
|
||||||
if ( f.has_bttv || ! f.settings.stream_title )
|
if ( f.has_bttv || ! f.settings.stream_title )
|
||||||
return;
|
return;
|
||||||
|
@ -463,6 +469,15 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
|
|
||||||
|
|
||||||
ffzUpdatePlayerStats: function() {
|
ffzUpdatePlayerStats: function() {
|
||||||
|
if ( this._ffz_update_stats ) {
|
||||||
|
clearTimeout(this._ffz_update_stats);
|
||||||
|
this._ffz_update_stats = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule an update.
|
||||||
|
if ( f.settings.player_stats )
|
||||||
|
this._ffz_update_stats = setTimeout(this.ffzUpdatePlayerStats.bind(this), 1000);
|
||||||
|
|
||||||
var channel_id = this.get('controller.content.id') || this.get('controller.id'),
|
var channel_id = this.get('controller.content.id') || this.get('controller.id'),
|
||||||
hosted_id = this.get('controller.hostModeTarget.id'),
|
hosted_id = this.get('controller.hostModeTarget.id'),
|
||||||
|
|
||||||
|
@ -478,12 +493,12 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
player = player_cont && player_cont.get && player_cont.get('player');
|
player = player_cont && player_cont.get && player_cont.get('player');
|
||||||
stats = player && player.stats;
|
stats = player && player.getVideoInfo();
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
f.error("Channel ffzUpdatePlayerStats: player.stats: " + err);
|
f.error("Channel ffzUpdatePlayerStats: player.getVideoInfo: " + err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! container || ! f.settings.player_stats || ! stats || ! stats.hlsLatencyBroadcaster || stats.hlsLatencyBroadcaster === 'NaN' || Number.isNaN(stats.hlsLatencyBroadcaster) ) {
|
if ( ! container || ! f.settings.player_stats || ! stats || ! stats.hls_latency_broadcaster || Number.isNaN(stats.hls_latency_broadcaster) ) {
|
||||||
if ( stat_el )
|
if ( stat_el )
|
||||||
stat_el.parentElement.removeChild(stat_el);
|
stat_el.parentElement.removeChild(stat_el);
|
||||||
} else {
|
} else {
|
||||||
|
@ -505,21 +520,20 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
jQuery(stat_el).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
jQuery(stat_el).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
}
|
}
|
||||||
|
|
||||||
var delay = parseFloat(stats.hlsLatencyBroadcaster);
|
var delay = Math.round(stats.hls_latency_broadcaster / 10) / 100,
|
||||||
|
bitrate = Math.round(stats.current_bitrate * 1000) / 1000;
|
||||||
|
|
||||||
if ( delay > 180 ) {
|
if ( delay > 180 ) {
|
||||||
delay = Math.floor(delay);
|
delay = Math.floor(delay);
|
||||||
stat_el.setAttribute('original-title', 'Video Information<br>Broadcast ' + utils.time_to_string(delay, true) + ' Ago<br><br>Video: ' + stats.videoResolution + 'p @ ' + stats.fps + '<br>Playback Rate: ' + stats.playbackRate + ' Kbps')
|
stat_el.setAttribute('original-title', 'Video Information<br>Broadcast ' + utils.time_to_string(delay, true) + ' Ago<br><br>Video: ' + stats.vid_width + 'x' + stats.vid_height + 'p @ ' + stats.current_fps + '<br>Playback Rate: ' + bitrate + ' Kbps')
|
||||||
el.textContent = utils.time_to_string(Math.floor(delay), true, delay > 172800) + ' old';
|
el.textContent = utils.time_to_string(Math.floor(delay), true, delay > 172800) + ' old';
|
||||||
} else {
|
} else {
|
||||||
stat_el.setAttribute('original-title', 'Stream Latency<br>Video: ' + stats.videoResolution + 'p @ ' + stats.fps + '<br>Playback Rate: ' + stats.playbackRate + ' Kbps');
|
stat_el.setAttribute('original-title', 'Stream Latency<br>Video: ' + stats.vid_width + 'x' + stats.vid_height + 'p @ ' + stats.current_fps + '<br>Playback Rate: ' + stats.current_bitrate + ' Kbps');
|
||||||
|
delay = delay.toString();
|
||||||
delay = stats.hlsLatencyBroadcaster;
|
var ind = delay.indexOf('.');
|
||||||
var pos = delay.lastIndexOf('.');
|
if ( ind === -1 )
|
||||||
|
|
||||||
if ( pos === -1 )
|
|
||||||
delay = delay + '.00';
|
delay = delay + '.00';
|
||||||
else if ( delay.length - pos < 3 )
|
else if ( ind >= delay.length - 2 )
|
||||||
delay = delay + '0';
|
delay = delay + '0';
|
||||||
|
|
||||||
el.textContent = delay + 's';
|
el.textContent = delay + 's';
|
||||||
|
@ -544,7 +558,7 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ( ! container || ! f.settings.player_stats || ! stats || ! stats.hlsLatencyBroadcaster || stats.hlsLatencyBroadcaster === 'NaN' || Number.isNaN(stats.hlsLatencyBroadcaster) ) {
|
if ( ! container || ! f.settings.player_stats || ! stats || ! stats.hls_latency_broadcaster || Number.isNaN(stats.hls_latency_broadcaster) ) {
|
||||||
if ( stat_el )
|
if ( stat_el )
|
||||||
stat_el.parentElement.removeChild(stat_el);
|
stat_el.parentElement.removeChild(stat_el);
|
||||||
} else {
|
} else {
|
||||||
|
@ -566,21 +580,20 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
jQuery(stat_el).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
jQuery(stat_el).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
}
|
}
|
||||||
|
|
||||||
var delay = parseFloat(stats.hlsLatencyBroadcaster);
|
var delay = Math.round(stats.hls_latency_broadcaster / 10) / 100,
|
||||||
|
bitrate = Math.round(stats.current_bitrate * 1000) / 1000;
|
||||||
|
|
||||||
if ( delay > 180 ) {
|
if ( delay > 180 ) {
|
||||||
delay = Math.floor(delay);
|
delay = Math.floor(delay);
|
||||||
stat_el.setAttribute('original-title', 'Video Information<br>Broadcast ' + utils.time_to_string(delay, true) + ' Ago<br><br>Video: ' + stats.videoResolution + 'p @ ' + stats.fps + '<br>Playback Rate: ' + stats.playbackRate + ' Kbps')
|
stat_el.setAttribute('original-title', 'Video Information<br>Broadcast ' + utils.time_to_string(delay, true) + ' Ago<br><br>Video: ' + stats.vid_width + 'x' + stats.vid_height + 'p @ ' + stats.current_fps + '<br>Playback Rate: ' + bitrate + ' Kbps')
|
||||||
el.textContent = utils.time_to_string(Math.floor(delay), true, delay > 172800) + ' old';
|
el.textContent = utils.time_to_string(Math.floor(delay), true, delay > 172800) + ' old';
|
||||||
} else {
|
} else {
|
||||||
stat_el.setAttribute('original-title', 'Stream Latency<br>Video: ' + stats.videoResolution + 'p @ ' + stats.fps + '<br>Playback Rate: ' + stats.playbackRate + ' Kbps');
|
stat_el.setAttribute('original-title', 'Stream Latency<br>Video: ' + stats.vid_width + 'x' + stats.vid_height + 'p @ ' + stats.current_fps + '<br>Playback Rate: ' + stats.current_bitrate + ' Kbps');
|
||||||
|
delay = delay.toString();
|
||||||
delay = stats.hlsLatencyBroadcaster;
|
var ind = delay.indexOf('.');
|
||||||
var pos = delay.lastIndexOf('.');
|
if ( ind === -1 )
|
||||||
|
|
||||||
if ( pos === -1 )
|
|
||||||
delay = delay + '.00';
|
delay = delay + '.00';
|
||||||
else if ( delay.length - pos < 3 )
|
else if ( ind >= delay.length - 2 )
|
||||||
delay = delay + '0';
|
delay = delay + '0';
|
||||||
|
|
||||||
el.textContent = delay + 's';
|
el.textContent = delay + 's';
|
||||||
|
@ -651,19 +664,6 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
}
|
}
|
||||||
|
|
||||||
el.innerHTML = utils.time_to_string(uptime, false, false, false, f.settings.stream_uptime === 1 || f.settings.stream_uptime === 3);
|
el.innerHTML = utils.time_to_string(uptime, false, false, false, f.settings.stream_uptime === 1 || f.settings.stream_uptime === 3);
|
||||||
},
|
|
||||||
|
|
||||||
ffzTeardown: function() {
|
|
||||||
var id = this.get('controller.content.id') || this.get('controller.id');
|
|
||||||
if ( id )
|
|
||||||
f.ws_send("unsub", "channel." + id);
|
|
||||||
|
|
||||||
this.get('element').setAttribute('data-channel', '');
|
|
||||||
f._cindex = undefined;
|
|
||||||
if ( this._ffz_update_uptime )
|
|
||||||
clearTimeout(this._ffz_update_uptime);
|
|
||||||
|
|
||||||
utils.update_css(f._channel_style, id, null);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -686,6 +686,28 @@ FFZ.settings_info.auto_theater = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.settings_info.small_player = {
|
||||||
|
type: "boolean",
|
||||||
|
value: false,
|
||||||
|
no_mobile: true,
|
||||||
|
no_bttv: true,
|
||||||
|
|
||||||
|
category: "Appearance",
|
||||||
|
name: "Mini-Player on Scroll",
|
||||||
|
help: "When you scroll down on the page, shrink the player and put it in the upper right corner so you can still watch.",
|
||||||
|
|
||||||
|
on_update: function(val) {
|
||||||
|
if ( ! val )
|
||||||
|
return document.body.classList.remove('ffz-small-player');
|
||||||
|
|
||||||
|
else if ( this._vodc )
|
||||||
|
this._vodc.ffzOnScroll();
|
||||||
|
else if ( this._cindex )
|
||||||
|
this._cindex.ffzOnScroll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.settings_info.chatter_count = {
|
FFZ.settings_info.chatter_count = {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: false,
|
value: false,
|
||||||
|
|
|
@ -210,35 +210,13 @@ FFZ.settings_info.input_emoji = {
|
||||||
|
|
||||||
FFZ.prototype.setup_chat_input = function() {
|
FFZ.prototype.setup_chat_input = function() {
|
||||||
this.log("Hooking the Ember Chat Input component.");
|
this.log("Hooking the Ember Chat Input component.");
|
||||||
var Input = utils.ember_resolve('component:chat/twitch-chat-input'),
|
this.update_views("component:chat/twitch-chat-input", this.modify_chat_input);
|
||||||
f = this;
|
|
||||||
|
|
||||||
if ( ! Input )
|
|
||||||
return this.log("Unable to get Chat Input component.");
|
|
||||||
|
|
||||||
this._modify_chat_input(Input);
|
|
||||||
|
|
||||||
try { Input.create().destroy()
|
|
||||||
} catch(err) { }
|
|
||||||
|
|
||||||
var views = utils.ember_views();
|
|
||||||
for(var key in views) {
|
|
||||||
var v = views[key];
|
|
||||||
if ( v instanceof Input ) {
|
|
||||||
this.log("Manually modifying Chat Input component.", v);
|
|
||||||
if ( ! v.ffzInit )
|
|
||||||
this._modify_chat_input(v);
|
|
||||||
|
|
||||||
v.ffzInit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype._modify_chat_input = function(component) {
|
FFZ.prototype.modify_chat_input = function(component) {
|
||||||
var f = this;
|
var f = this;
|
||||||
|
utils.ember_reopen_view(component, {
|
||||||
component.reopen({
|
|
||||||
ffz_mru_index: -1,
|
ffz_mru_index: -1,
|
||||||
ffz_current_suggestion: 0,
|
ffz_current_suggestion: 0,
|
||||||
ffz_partial_word: '',
|
ffz_partial_word: '',
|
||||||
|
@ -249,22 +227,7 @@ FFZ.prototype._modify_chat_input = function(component) {
|
||||||
ffz_name_suggestions: [],
|
ffz_name_suggestions: [],
|
||||||
ffz_chatters: [],
|
ffz_chatters: [],
|
||||||
|
|
||||||
didInsertElement: function() {
|
ffz_init: function() {
|
||||||
this._super();
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.ffzInit();
|
|
||||||
} catch(err) { f.error("ChatInput didInsertElement: " + err); }
|
|
||||||
},
|
|
||||||
|
|
||||||
willClearRender: function() {
|
|
||||||
try {
|
|
||||||
this.ffzTeardown();
|
|
||||||
} catch(err) { f.error("ChatInput willClearRender: " + err); }
|
|
||||||
return this._super();
|
|
||||||
},
|
|
||||||
|
|
||||||
ffzInit: function() {
|
|
||||||
f._inputv = this;
|
f._inputv = this;
|
||||||
|
|
||||||
var s = this._ffz_minimal_style = document.createElement('style');
|
var s = this._ffz_minimal_style = document.createElement('style');
|
||||||
|
@ -290,7 +253,7 @@ FFZ.prototype._modify_chat_input = function(component) {
|
||||||
setTimeout(this.ffzResizeInput.bind(this), 500);
|
setTimeout(this.ffzResizeInput.bind(this), 500);
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzTeardown: function() {
|
ffz_destroy: function() {
|
||||||
if ( f._inputv === this )
|
if ( f._inputv === this )
|
||||||
f._inputv = undefined;
|
f._inputv = undefined;
|
||||||
|
|
||||||
|
@ -322,11 +285,10 @@ FFZ.prototype._modify_chat_input = function(component) {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var t = this,
|
var t = this,
|
||||||
el = document.createElement('div'),
|
el = utils.createElement('div', 'suggestion'),
|
||||||
inner = document.createElement('div'),
|
inner = utils.createElement('div'),
|
||||||
width = item.width ? (246 - item.width) + 'px' : null;
|
width = item.width ? (246 - item.width) + 'px' : null;
|
||||||
|
|
||||||
el.className = 'suggestion';
|
|
||||||
el.setAttribute('data-id', i);
|
el.setAttribute('data-id', i);
|
||||||
el.classList.toggle('ffz-is-favorite', item.favorite || false);
|
el.classList.toggle('ffz-is-favorite', item.favorite || false);
|
||||||
|
|
||||||
|
@ -342,7 +304,7 @@ FFZ.prototype._modify_chat_input = function(component) {
|
||||||
el.appendChild(inner);
|
el.appendChild(inner);
|
||||||
|
|
||||||
if ( f.settings.input_complete_emotes && item.info ) {
|
if ( f.settings.input_complete_emotes && item.info ) {
|
||||||
var info = document.createElement('span');
|
var info = utils.createElement('span');
|
||||||
info.innerHTML = item.info;
|
info.innerHTML = item.info;
|
||||||
el.classList.add('has-info');
|
el.classList.add('has-info');
|
||||||
if ( width )
|
if ( width )
|
||||||
|
@ -394,8 +356,7 @@ FFZ.prototype._modify_chat_input = function(component) {
|
||||||
current = this.get('ffz_current_suggestion') || 0;
|
current = this.get('ffz_current_suggestion') || 0;
|
||||||
|
|
||||||
if ( ! el ) {
|
if ( ! el ) {
|
||||||
el = this.ffz_suggestions_el = document.createElement('div');
|
el = this.ffz_suggestions_el = utils.createElement('div', 'suggestions ffz-suggestions');
|
||||||
el.className = 'suggestions ffz-suggestions';
|
|
||||||
this.get('element').appendChild(el);
|
this.get('element').appendChild(el);
|
||||||
|
|
||||||
} else
|
} else
|
||||||
|
@ -430,8 +391,7 @@ FFZ.prototype._modify_chat_input = function(component) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! added ) {
|
if ( ! added ) {
|
||||||
var item_el = document.createElement('div');
|
var item_el = utils.createElement('div', 'suggestion disabled');
|
||||||
item_el.className = 'suggestion disabled';
|
|
||||||
item_el.textContent = 'No matches.';
|
item_el.textContent = 'No matches.';
|
||||||
el.appendChild(item_el);
|
el.appendChild(item_el);
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,6 +107,7 @@ FFZ.settings_info.chat_batching = {
|
||||||
type: "select",
|
type: "select",
|
||||||
options: {
|
options: {
|
||||||
0: "No Batching",
|
0: "No Batching",
|
||||||
|
125: "Minimal (0.125s)",
|
||||||
250: "Minor (0.25s)",
|
250: "Minor (0.25s)",
|
||||||
500: "Normal (0.5s)",
|
500: "Normal (0.5s)",
|
||||||
750: "Large (0.75s)",
|
750: "Large (0.75s)",
|
||||||
|
@ -474,36 +475,7 @@ FFZ.prototype.setup_chatview = function() {
|
||||||
|
|
||||||
|
|
||||||
this.log("Hooking the Ember Chat view.");
|
this.log("Hooking the Ember Chat view.");
|
||||||
|
this.update_views('view:chat', this.modify_chat_view);
|
||||||
var Chat = utils.ember_resolve('view:chat');
|
|
||||||
this._modify_cview(Chat);
|
|
||||||
|
|
||||||
// For some reason, this doesn't work unless we create an instance of the
|
|
||||||
// chat view and then destroy it immediately.
|
|
||||||
try {
|
|
||||||
Chat.create().destroy();
|
|
||||||
} catch(err) { }
|
|
||||||
|
|
||||||
|
|
||||||
// Modify all existing Chat views.
|
|
||||||
var views = utils.ember_views();
|
|
||||||
for(var key in views) {
|
|
||||||
if ( ! views.hasOwnProperty(key) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var view = views[key];
|
|
||||||
if ( !(view instanceof Chat) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
this.log("Manually updating existing Chat view.", view);
|
|
||||||
try {
|
|
||||||
if ( ! view.ffzInit )
|
|
||||||
this._modify_cview(view);
|
|
||||||
view.ffzInit();
|
|
||||||
} catch(err) {
|
|
||||||
this.error("setup: build_ui_link: " + err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -511,35 +483,10 @@ FFZ.prototype.setup_chatview = function() {
|
||||||
// Modify Chat View
|
// Modify Chat View
|
||||||
// --------------------
|
// --------------------
|
||||||
|
|
||||||
FFZ.prototype._modify_cview = function(view) {
|
FFZ.prototype.modify_chat_view = function(view) {
|
||||||
var f = this;
|
var f = this;
|
||||||
|
utils.ember_reopen_view(view, {
|
||||||
view.reopen({
|
ffz_init: function() {
|
||||||
didInsertElement: function() {
|
|
||||||
this._super();
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.ffzInit();
|
|
||||||
} catch(err) {
|
|
||||||
f.error("view:chat ffzInit error: " + err);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
didUpdate: function() {
|
|
||||||
this._super();
|
|
||||||
f.log("view:chat didUpdate", this)
|
|
||||||
},
|
|
||||||
|
|
||||||
willClearRender: function() {
|
|
||||||
try {
|
|
||||||
this.ffzTeardown();
|
|
||||||
} catch(err) {
|
|
||||||
f.error("view:chat ffzTeardown error: " + err);
|
|
||||||
}
|
|
||||||
this._super();
|
|
||||||
},
|
|
||||||
|
|
||||||
ffzInit: function() {
|
|
||||||
f._chatv = this;
|
f._chatv = this;
|
||||||
|
|
||||||
var room_id = this.get('controller.currentRoom.id'),
|
var room_id = this.get('controller.currentRoom.id'),
|
||||||
|
@ -567,7 +514,7 @@ FFZ.prototype._modify_cview = function(view) {
|
||||||
}, 1000);
|
}, 1000);
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzTeardown: function() {
|
ffz_destroy: function() {
|
||||||
if ( f._chatv === this )
|
if ( f._chatv === this )
|
||||||
f._chatv = null;
|
f._chatv = null;
|
||||||
|
|
||||||
|
@ -868,10 +815,9 @@ FFZ.prototype._modify_cview = function(view) {
|
||||||
chan_table = this._ffz_chan_table || room_list.querySelector('#ffz-channel-table tbody');
|
chan_table = this._ffz_chan_table || room_list.querySelector('#ffz-channel-table tbody');
|
||||||
|
|
||||||
if ( ! chan_table ) {
|
if ( ! chan_table ) {
|
||||||
var tbl = document.createElement('table');
|
var tbl = utils.createElement('table', 'ffz');
|
||||||
tbl.setAttribute('cellspacing', '0');
|
tbl.setAttribute('cellspacing', '0');
|
||||||
tbl.id = 'ffz-channel-table';
|
tbl.id = 'ffz-channel-table';
|
||||||
tbl.className = 'ffz';
|
|
||||||
tbl.innerHTML = '<thead><tr><th colspan="2">Channels</th><th class="ffz-row-switch" title="Pinning a channel makes it so you always join that channel\'s chat, no matter where you are on Twitch.">Pin</th></tr></thead><tbody></tbody>';
|
tbl.innerHTML = '<thead><tr><th colspan="2">Channels</th><th class="ffz-row-switch" title="Pinning a channel makes it so you always join that channel\'s chat, no matter where you are on Twitch.">Pin</th></tr></thead><tbody></tbody>';
|
||||||
room_list.insertBefore(tbl, room_list.firstChild);
|
room_list.insertBefore(tbl, room_list.firstChild);
|
||||||
|
|
||||||
|
@ -914,10 +860,9 @@ FFZ.prototype._modify_cview = function(view) {
|
||||||
// Group Chat Table
|
// Group Chat Table
|
||||||
var group_table = this._ffz_group_table || room_list.querySelector('#ffz-group-table tbody');
|
var group_table = this._ffz_group_table || room_list.querySelector('#ffz-group-table tbody');
|
||||||
if ( ! group_table ) {
|
if ( ! group_table ) {
|
||||||
var tbl = document.createElement('table');
|
var tbl = utils.createElement('table', 'ffz');
|
||||||
tbl.setAttribute('cellspacing', '0');
|
tbl.setAttribute('cellspacing', '0');
|
||||||
tbl.id = 'ffz-group-table';
|
tbl.id = 'ffz-group-table';
|
||||||
tbl.className = 'ffz';
|
|
||||||
tbl.innerHTML = '<thead><tr><th colspan="2">Group Chats</th></tr></thead><tbody></tbody>';
|
tbl.innerHTML = '<thead><tr><th colspan="2">Group Chats</th></tr></thead><tbody></tbody>';
|
||||||
|
|
||||||
var before = room_list.querySelector('#ffz-channel-table');
|
var before = room_list.querySelector('#ffz-channel-table');
|
||||||
|
@ -1007,8 +952,7 @@ FFZ.prototype._modify_cview = function(view) {
|
||||||
this.classList.toggle('active', !is_pinned);
|
this.classList.toggle('active', !is_pinned);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
btn = document.createElement('a');
|
btn = utils.createElement('a', 'leave-chat html-tooltip');
|
||||||
btn.className = 'leave-chat html-tooltip';
|
|
||||||
btn.innerHTML = constants.CLOSE;
|
btn.innerHTML = constants.CLOSE;
|
||||||
btn.title = 'Leave Group';
|
btn.title = 'Leave Group';
|
||||||
|
|
||||||
|
@ -1085,12 +1029,10 @@ FFZ.prototype._modify_cview = function(view) {
|
||||||
if ( f.has_bttv || ! f.settings.group_tabs )
|
if ( f.has_bttv || ! f.settings.group_tabs )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var link = document.createElement('a'),
|
var link = utils.createElement('a', 'button button--icon-only'),
|
||||||
view = this;
|
view = this;
|
||||||
|
|
||||||
|
|
||||||
// Chat Room Management Button
|
// Chat Room Management Button
|
||||||
link.className = 'button button--icon-only';
|
|
||||||
link.title = "Chat Room Management";
|
link.title = "Chat Room Management";
|
||||||
link.innerHTML = '<figure class="icon">' + constants.ROOMS + '</figure><span class="notifications"></span>';
|
link.innerHTML = '<figure class="icon">' + constants.ROOMS + '</figure><span class="notifications"></span>';
|
||||||
|
|
||||||
|
@ -1105,8 +1047,7 @@ FFZ.prototype._modify_cview = function(view) {
|
||||||
|
|
||||||
|
|
||||||
// Invite Button
|
// Invite Button
|
||||||
link = document.createElement('a'),
|
link = utils.createElement('a', 'button button--icon-only html-tooltip invite');
|
||||||
link.className = 'button button--icon-only html-tooltip invite';
|
|
||||||
link.title = "Invite a User";
|
link.title = "Invite a User";
|
||||||
link.innerHTML = '<figure class="icon">' + constants.INVITE + '</figure>';
|
link.innerHTML = '<figure class="icon">' + constants.INVITE + '</figure>';
|
||||||
|
|
||||||
|
@ -1216,6 +1157,10 @@ FFZ.prototype._modify_cview = function(view) {
|
||||||
|
|
||||||
now = Date.now();
|
now = Date.now();
|
||||||
|
|
||||||
|
// Non-Existant Rooms
|
||||||
|
if ( ! room )
|
||||||
|
return false;
|
||||||
|
|
||||||
if ( is_current || is_channel || room_id === this._ffz_host || f.settings.group_tabs === 3 )
|
if ( is_current || is_channel || room_id === this._ffz_host || f.settings.group_tabs === 3 )
|
||||||
// Important Tabs
|
// Important Tabs
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -71,42 +71,16 @@ FFZ.prototype.setup_conversations = function() {
|
||||||
document.body.classList.toggle('ffz-minimize-conversations', this.settings.minimize_conversations);
|
document.body.classList.toggle('ffz-minimize-conversations', this.settings.minimize_conversations);
|
||||||
document.body.classList.toggle('ffz-theatre-conversations', this.settings.hide_conversations_in_theatre);
|
document.body.classList.toggle('ffz-theatre-conversations', this.settings.hide_conversations_in_theatre);
|
||||||
|
|
||||||
var ConvWindow = utils.ember_resolve('component:twitch-conversations/conversation-window');
|
this.update_views('component:twitch-conversations/conversation-window', this.modify_conversation_window);
|
||||||
if ( ConvWindow ) {
|
this.update_views('component:twitch-conversations/conversation-settings-menu', this.modify_conversation_menu);
|
||||||
this.log("Hooking the Ember Conversation Window component.");
|
this.update_views('component:twitch-conversations/conversation-line', this.modify_conversation_line);
|
||||||
this._modify_conversation_window(ConvWindow);
|
|
||||||
try { ConvWindow.create().destroy() }
|
|
||||||
catch(err) { }
|
|
||||||
} else
|
|
||||||
this.log("Unable to resolve: component:twitch-conversations/conversation-window");
|
|
||||||
|
|
||||||
|
|
||||||
var ConvSettings = utils.ember_resolve('component:twitch-conversations/conversation-settings-menu');
|
|
||||||
if ( ConvSettings ) {
|
|
||||||
this.log("Hooking the Ember Conversation Settings Menu component.");
|
|
||||||
this._modify_conversation_menu(ConvSettings);
|
|
||||||
try { ConvSettings.create().destroy() }
|
|
||||||
catch(err) { }
|
|
||||||
} else
|
|
||||||
this.log("Unable to resolve: component:twitch-conversations/conversation-settings-menu");
|
|
||||||
|
|
||||||
|
|
||||||
var ConvLine = utils.ember_resolve('component:twitch-conversations/conversation-line');
|
|
||||||
if ( ConvLine ) {
|
|
||||||
this.log("Hooking the Ember Conversation Line component.");
|
|
||||||
this._modify_conversation_line(ConvLine);
|
|
||||||
try { ConvLine.create().destroy() }
|
|
||||||
catch(err) { }
|
|
||||||
} else
|
|
||||||
this.log("Unable to resolve: component:twitch-conversations/conversation-line");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype._modify_conversation_menu = function(component) {
|
FFZ.prototype.modify_conversation_menu = function(component) {
|
||||||
var f = this;
|
var f = this;
|
||||||
|
utils.ember_reopen_view(component, {
|
||||||
component.reopen({
|
ffz_init: function() {
|
||||||
didInsertElement: function() {
|
|
||||||
var user = this.get('thread.otherUsername'),
|
var user = this.get('thread.otherUsername'),
|
||||||
el = this.get('element'),
|
el = this.get('element'),
|
||||||
sections = el && el.querySelectorAll('.options-section');
|
sections = el && el.querySelectorAll('.options-section');
|
||||||
|
@ -132,11 +106,11 @@ FFZ.prototype._modify_conversation_menu = function(component) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype._modify_conversation_window = function(component) {
|
FFZ.prototype.modify_conversation_window = function(component) {
|
||||||
var f = this,
|
var f = this,
|
||||||
Layout = utils.ember_lookup('service:layout');
|
Layout = utils.ember_lookup('service:layout');
|
||||||
|
|
||||||
component.reopen({
|
utils.ember_reopen_view(component, {
|
||||||
headerBadges: Ember.computed("thread.participants", "currentUsername", function() {
|
headerBadges: Ember.computed("thread.participants", "currentUsername", function() {
|
||||||
return [];
|
return [];
|
||||||
}),
|
}),
|
||||||
|
@ -154,7 +128,7 @@ FFZ.prototype._modify_conversation_window = function(component) {
|
||||||
badge_el.innerHTML = f.render_badges(badges);
|
badge_el.innerHTML = f.render_badges(badges);
|
||||||
}.observes('ffzHeaderBadges'),
|
}.observes('ffzHeaderBadges'),
|
||||||
|
|
||||||
didInsertElement: function() {
|
ffz_init: function() {
|
||||||
var el = this.get('element'),
|
var el = this.get('element'),
|
||||||
header = el && el.querySelector('.conversation-header'),
|
header = el && el.querySelector('.conversation-header'),
|
||||||
header_name = header && header.querySelector('.conversation-header-name'),
|
header_name = header && header.querySelector('.conversation-header-name'),
|
||||||
|
@ -178,11 +152,11 @@ FFZ.prototype._modify_conversation_window = function(component) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype._modify_conversation_line = function(component) {
|
FFZ.prototype.modify_conversation_line = function(component) {
|
||||||
var f = this,
|
var f = this,
|
||||||
Layout = utils.ember_lookup('service:layout');
|
Layout = utils.ember_lookup('service:layout');
|
||||||
|
|
||||||
component.reopen({
|
utils.ember_reopen_view(component, {
|
||||||
tokenizedMessage: function() {
|
tokenizedMessage: function() {
|
||||||
try {
|
try {
|
||||||
return f.tokenize_conversation_line(this.get('message'));
|
return f.tokenize_conversation_line(this.get('message'));
|
||||||
|
@ -204,7 +178,7 @@ FFZ.prototype._modify_conversation_line = function(component) {
|
||||||
},
|
},
|
||||||
|
|
||||||
didUpdate: function() { this.ffzRender() },
|
didUpdate: function() { this.ffzRender() },
|
||||||
didInsertElement: function() { this.ffzRender() },
|
ffz_init: function() { this.ffzRender() },
|
||||||
|
|
||||||
ffzRender: function() {
|
ffzRender: function() {
|
||||||
var el = this.get('element'),
|
var el = this.get('element'),
|
||||||
|
|
|
@ -77,14 +77,44 @@ FFZ.settings_info.directory_group_hosts = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
FFZ.settings_info.banned_games = {
|
FFZ.settings_info.enable_recommended_vods = {
|
||||||
type: "button",
|
type: "boolean",
|
||||||
value: [],
|
value: true,
|
||||||
|
|
||||||
category: "Directory",
|
category: "Directory",
|
||||||
no_mobile: true,
|
no_mobile: true,
|
||||||
name: "Banned Games",
|
experiment_warn: true,
|
||||||
help: "A list of games that will not be displayed in the Directory.",
|
|
||||||
|
name: 'Show Twitch\'s Recommended Videos',
|
||||||
|
help: 'Show the "Based on your Viewing History" section of the directory rather than <nobr>Most Recent Videos.</nobr>',
|
||||||
|
|
||||||
|
on_update: function(val) {
|
||||||
|
Ember.propertyDidChange(utils.ember_lookup('service:vod-coviews'), 'areVodsViewable');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.settings_info.recommended_above_hosts = {
|
||||||
|
type: "boolean",
|
||||||
|
value: function() { var s = utils.ember_lookup('service:vod-coviews'); return s && s.get('isFollowingAboveHost') },
|
||||||
|
|
||||||
|
category: "Directory",
|
||||||
|
no_mobile: true,
|
||||||
|
experiment_warn: true,
|
||||||
|
|
||||||
|
name: "Show Twitch's Recommended Videos above Hosts",
|
||||||
|
help: 'Enable this to place the "Based on your Viewing History" section above Live Hosts.',
|
||||||
|
|
||||||
|
on_update: function(val) {
|
||||||
|
Ember.propertyDidChange(utils.ember_lookup('service:vod-coviews'), 'isFollowingAboveHost');
|
||||||
|
//utils.ember_lookup('service:vod-coviews').set('isFollowingAboveHost', val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.settings_info.banned_games = {
|
||||||
|
visible: false,
|
||||||
|
value: [],
|
||||||
|
|
||||||
on_update: function() {
|
on_update: function() {
|
||||||
var banned = this.settings.banned_games,
|
var banned = this.settings.banned_games,
|
||||||
|
@ -96,34 +126,14 @@ FFZ.settings_info.banned_games = {
|
||||||
|
|
||||||
el.classList.toggle('ffz-game-banned', banned.indexOf(game && game.toLowerCase()) !== -1);
|
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 = {
|
FFZ.settings_info.spoiler_games = {
|
||||||
type: "button",
|
visible: false,
|
||||||
value: [],
|
value: [],
|
||||||
|
|
||||||
category: "Directory",
|
|
||||||
no_mobile: true,
|
|
||||||
name: "No-Thumbnail Games",
|
|
||||||
help: "Stream and video thumbnails will be hidden for games that you add to this list.",
|
|
||||||
|
|
||||||
on_update: function() {
|
on_update: function() {
|
||||||
var spoiled = this.settings.spoiler_games,
|
var spoiled = this.settings.spoiler_games,
|
||||||
els = document.querySelectorAll('.ffz-directory-preview');
|
els = document.querySelectorAll('.ffz-directory-preview');
|
||||||
|
@ -134,21 +144,6 @@ FFZ.settings_info.spoiler_games = {
|
||||||
|
|
||||||
el.classList.toggle('ffz-game-spoilered', spoiled.indexOf(game && game.toLowerCase()) !== -1);
|
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(
|
|
||||||
"No-Thumbnail 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,88 +193,46 @@ FFZ.prototype.setup_directory = function() {
|
||||||
document.body.classList.toggle('ffz-creative-tags', this.settings.directory_creative_all_tags);
|
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-creative-showcase', this.settings.directory_creative_showcase);
|
||||||
|
|
||||||
|
var f = this,
|
||||||
|
VodCoviews = utils.ember_lookup('service:vod-coviews');
|
||||||
|
|
||||||
|
if ( VodCoviews ) {
|
||||||
|
VodCoviews.reopen({
|
||||||
|
// checkExperiment likes setting this back. Don't let it.
|
||||||
|
isFollowingAboveHost: Ember.computed('_ffz', {
|
||||||
|
get: function(key) {
|
||||||
|
return f.settings.recommended_above_hosts;
|
||||||
|
},
|
||||||
|
set: function(key, val) {
|
||||||
|
return f.settings.recommended_above_hosts;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
areVodsViewable: function() {
|
||||||
|
var filtered = this.get('filteredVods');
|
||||||
|
return f.settings.enable_recommended_vods && filtered && filtered.length > 0;
|
||||||
|
}.property('filteredVods')
|
||||||
|
});
|
||||||
|
|
||||||
|
Ember.propertyDidChange(VodCoviews, 'isFollowingAboveHost');
|
||||||
|
Ember.propertyDidChange(VodCoviews, 'areVodsViewable');
|
||||||
|
|
||||||
|
} else
|
||||||
|
this.log("Unable to locate the Ember service:vod-coviews");
|
||||||
|
|
||||||
|
|
||||||
this.log("Attempting to modify the Following collection.");
|
this.log("Attempting to modify the Following collection.");
|
||||||
this._modify_following();
|
this._modify_following();
|
||||||
|
|
||||||
this.log("Hooking the Ember Directory views.");
|
this.log("Hooking the Ember Directory views.");
|
||||||
|
|
||||||
var ChannelView = utils.ember_resolve('component:stream-preview');
|
this.update_views('component:stream-preview', function(x) { this.modify_directory_live(x, false) }, true);
|
||||||
if ( ChannelView ) {
|
this.update_views('component:creative-preview', function(x) { this.modify_directory_live(x, false) }, true);
|
||||||
this._modify_directory_live(ChannelView, false);
|
this.update_views('component:csgo-channel-preview', function(x) { this.modify_directory_live(x, true) }, true);
|
||||||
try {
|
this.update_views('component:host-preview', this.modify_directory_host, true);
|
||||||
ChannelView.create().destroy();
|
this.update_views('component:video-preview', this.modify_video_preview, true);
|
||||||
} catch(err) { }
|
|
||||||
} else
|
|
||||||
this.log("Unable to locate the Ember component:stream-preview");
|
|
||||||
|
|
||||||
var CreativeChannel = utils.ember_resolve('component:creative-preview');
|
this.update_views('component:game-follow-button', this.modify_game_follow_button);
|
||||||
if ( CreativeChannel ) {
|
|
||||||
this._modify_directory_live(CreativeChannel, false);
|
|
||||||
try {
|
|
||||||
CreativeChannel.create().destroy();
|
|
||||||
} catch(err) { }
|
|
||||||
} else
|
|
||||||
this.log("Unable to locate the Ember component:creative-preview");
|
|
||||||
|
|
||||||
var CSGOChannel = utils.ember_resolve('component:csgo-channel-preview');
|
|
||||||
CSGOChannel = this._modify_directory_live(CSGOChannel, true, 'component:csgo-channel-preview');
|
|
||||||
try {
|
|
||||||
CSGOChannel.create().destroy();
|
|
||||||
} catch(err) { }
|
|
||||||
|
|
||||||
var HostView = utils.ember_resolve('component:host-preview');
|
|
||||||
HostView = this._modify_directory_host(HostView);
|
|
||||||
try {
|
|
||||||
HostView.create().destroy();
|
|
||||||
} catch(err) { }
|
|
||||||
|
|
||||||
|
|
||||||
var VideoPreview = utils.ember_resolve('component:video-preview');
|
|
||||||
if ( VideoPreview ) {
|
|
||||||
this._modify_video_preview(VideoPreview);
|
|
||||||
try { VideoPreview.create().destroy();
|
|
||||||
} catch(err) { }
|
|
||||||
} else
|
|
||||||
this.log("Unable to locate the Ember component:video-preview");
|
|
||||||
|
|
||||||
|
|
||||||
var GameFollow = utils.ember_resolve('component:game-follow-button');
|
|
||||||
if ( GameFollow ) {
|
|
||||||
this._modify_game_follow(GameFollow);
|
|
||||||
try { GameFollow.create().destroy() }
|
|
||||||
catch(err) { }
|
|
||||||
} else
|
|
||||||
this.log("Unable to locate the Ember component:game-follow-button");
|
|
||||||
|
|
||||||
|
|
||||||
// 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, 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 if ( GameFollow && view instanceof GameFollow ) {
|
|
||||||
if ( ! view.ffzInit )
|
|
||||||
this._modify_game_follow(view);
|
|
||||||
} else
|
|
||||||
continue;
|
|
||||||
|
|
||||||
try {
|
|
||||||
view.ffzInit();
|
|
||||||
} catch(err) {
|
|
||||||
this.error("Directory Setup: " + err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -407,15 +360,10 @@ FFZ.prototype._modify_following = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype._modify_game_follow = function(component) {
|
FFZ.prototype.modify_game_follow_button = function(component) {
|
||||||
var f = this;
|
var f = this;
|
||||||
component.reopen({
|
utils.ember_reopen_view(component, {
|
||||||
didInsertElement: function() {
|
ffz_init: function() {
|
||||||
this._super();
|
|
||||||
this.ffzInit();
|
|
||||||
},
|
|
||||||
|
|
||||||
ffzInit: function() {
|
|
||||||
var el = this.get('element'),
|
var el = this.get('element'),
|
||||||
game = this.get('game.id').toLowerCase(),
|
game = this.get('game.id').toLowerCase(),
|
||||||
|
|
||||||
|
@ -436,37 +384,33 @@ FFZ.prototype._modify_game_follow = function(component) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Block Button
|
// Block Button
|
||||||
var block = utils.createElement('div', 'follow-button ffz-block-button'),
|
var block = utils.createElement('button', 'button tooltip ffz-block-button'),
|
||||||
block_link = utils.createElement('a', 'tooltip follow block');
|
|
||||||
|
|
||||||
update_block = function() {
|
update_block = function() {
|
||||||
var is_blocked = f.settings.banned_games.indexOf(game) !== -1;
|
var is_blocked = f.settings.banned_games.indexOf(game) !== -1;
|
||||||
block_link.classList.toggle('active', is_blocked);
|
block.classList.toggle('active', is_blocked);
|
||||||
|
|
||||||
block_link.innerHTML = '<span>' + (is_blocked ? 'Unblock' : 'Block') + '</span>';
|
block.innerHTML = (is_blocked ? 'Unblock' : 'Block');
|
||||||
block_link.title = 'Click to ' + (is_blocked ? 'unblock' : 'block') + " this game.\n\nBlocking a game hides all the streams and videos of the game when you're not viewing it directly.";
|
block.title = 'Click to ' + (is_blocked ? 'unblock' : 'block') + " this game.\n\nBlocking a game hides all the streams and videos of the game when you're not viewing it directly.";
|
||||||
|
jQuery(block).trigger('mouseout').trigger('mouseover');
|
||||||
};
|
};
|
||||||
|
|
||||||
update_block();
|
update_block();
|
||||||
block_link.addEventListener('click', click_button('banned_games', update_block));
|
block.addEventListener('click', click_button('banned_games', update_block));
|
||||||
block.appendChild(block_link);
|
|
||||||
el.appendChild(block);
|
el.appendChild(block);
|
||||||
|
|
||||||
// Spoiler Button
|
// Spoiler Button
|
||||||
var spoiler = utils.createElement('div', 'follow-button ffz-spoiler-button'),
|
var spoiler = utils.createElement('button', 'button tooltip ffz-spoiler-button'),
|
||||||
spoiler_link = utils.createElement('a', 'tooltip follow spoiler'),
|
|
||||||
|
|
||||||
update_spoiler = function() {
|
update_spoiler = function() {
|
||||||
var is_spoiled = f.settings.spoiler_games.indexOf(game) !== -1;
|
var is_spoiled = f.settings.spoiler_games.indexOf(game) !== -1;
|
||||||
spoiler_link.classList.toggle('active', is_spoiled);
|
spoiler.classList.toggle('active', is_spoiled);
|
||||||
|
|
||||||
spoiler_link.innerHTML = '<span>' + (is_spoiled ? 'Show Thumbnails' : 'Hide Thumbnails') + '</span>';
|
spoiler.innerHTML = (is_spoiled ? 'Show Thumbnails' : 'Hide Thumbnails');
|
||||||
spoiler_link.title = 'Click to ' + (is_spoiled ? 'show' : 'hide') + " thumbnails for this game.\n\nHiding thumbnails for a game will help you avoid spoilers for a game that you haven't played yet.";
|
spoiler.title = 'Click to ' + (is_spoiled ? 'show' : 'hide') + " thumbnails for this game.\n\nHiding thumbnails for a game will help you avoid spoilers for a game that you haven't played yet.";
|
||||||
|
jQuery(spoiler).trigger('mouseout').trigger('mouseover');
|
||||||
}
|
}
|
||||||
|
|
||||||
update_spoiler();
|
update_spoiler();
|
||||||
spoiler_link.addEventListener('click', click_button('spoiler_games', update_spoiler));
|
spoiler.addEventListener('click', click_button('spoiler_games', update_spoiler));
|
||||||
spoiler.appendChild(spoiler_link);
|
|
||||||
el.appendChild(spoiler);
|
el.appendChild(spoiler);
|
||||||
|
|
||||||
jQuery('.tooltip', el).tipsy();
|
jQuery('.tooltip', el).tipsy();
|
||||||
|
@ -475,17 +419,12 @@ FFZ.prototype._modify_game_follow = function(component) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype._modify_directory_live = function(dir, is_csgo, component_name) {
|
FFZ.prototype.modify_directory_live = function(component, is_csgo) {
|
||||||
var f = this,
|
var f = this,
|
||||||
pref = is_csgo ? 'channel.' : 'stream.';
|
pref = is_csgo ? 'channel.' : 'stream.';
|
||||||
|
|
||||||
var mutator = {
|
utils.ember_reopen_view(component, {
|
||||||
didInsertElement: function() {
|
ffz_init: function() {
|
||||||
this._super();
|
|
||||||
this.ffzInit();
|
|
||||||
},
|
|
||||||
|
|
||||||
ffzInit: function() {
|
|
||||||
var el = this.get('element'),
|
var el = this.get('element'),
|
||||||
meta = el && el.querySelector('.meta'),
|
meta = el && el.querySelector('.meta'),
|
||||||
thumb = el && el.querySelector('.thumb'),
|
thumb = el && el.querySelector('.thumb'),
|
||||||
|
@ -532,12 +471,12 @@ FFZ.prototype._modify_directory_live = function(dir, is_csgo, component_name) {
|
||||||
if ( e.button !== 0 || e.altKey || e.ctrlKey || e.shiftKey || e.metaKey )
|
if ( e.button !== 0 || e.altKey || e.ctrlKey || e.shiftKey || e.metaKey )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var Channel = utils.ember_resolve('model:channel');
|
var Channel = utils.ember_resolve('model:deprecated-channel');
|
||||||
if ( ! Channel )
|
if ( ! Channel )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
e.preventDefault();
|
|
||||||
utils.ember_lookup('router:main').transitionTo('channel.index', Channel.find({id: channel_id}).load());
|
utils.ember_lookup('router:main').transitionTo('channel.index', Channel.find({id: channel_id}).load());
|
||||||
|
e.preventDefault();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -546,7 +485,7 @@ FFZ.prototype._modify_directory_live = function(dir, is_csgo, component_name) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
willClearRender: function() {
|
ffz_destroy: function() {
|
||||||
if ( this._ffz_uptime ) {
|
if ( this._ffz_uptime ) {
|
||||||
this._ffz_uptime.parentElement.removeChild(this._ffz_uptime);
|
this._ffz_uptime.parentElement.removeChild(this._ffz_uptime);
|
||||||
this._ffz_uptime = null;
|
this._ffz_uptime = null;
|
||||||
|
@ -557,8 +496,6 @@ FFZ.prototype._modify_directory_live = function(dir, is_csgo, component_name) {
|
||||||
|
|
||||||
if ( this._ffz_image_timer )
|
if ( this._ffz_image_timer )
|
||||||
clearInterval(this._ffz_image_timer);
|
clearInterval(this._ffz_image_timer);
|
||||||
|
|
||||||
this._super();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzRotateImage: function() {
|
ffzRotateImage: function() {
|
||||||
|
@ -587,32 +524,14 @@ FFZ.prototype._modify_directory_live = function(dir, is_csgo, component_name) {
|
||||||
this._ffz_uptime.innerHTML = '';
|
this._ffz_uptime.innerHTML = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if ( dir )
|
|
||||||
dir.reopen(mutator);
|
|
||||||
else {
|
|
||||||
dir = Ember.Component.extend(mutator);
|
|
||||||
App.__deprecatedInstance__.registry.register(component_name, dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dir;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype._modify_video_preview = function(vp) {
|
FFZ.prototype.modify_video_preview = function(component) {
|
||||||
var f = this;
|
var f = this;
|
||||||
vp.reopen({
|
utils.ember_reopen_view(component, {
|
||||||
didInsertElement: function() {
|
ffz_init: function() {
|
||||||
this._super();
|
|
||||||
try {
|
|
||||||
this.ffzInit();
|
|
||||||
} catch(err) {
|
|
||||||
f.error("component:video-preview ffzInit: " + err);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
ffzInit: function() {
|
|
||||||
var el = this.get('element'),
|
var el = this.get('element'),
|
||||||
game = this.get('video.game'),
|
game = this.get('video.game'),
|
||||||
|
|
||||||
|
@ -659,30 +578,11 @@ FFZ.prototype._modify_video_preview = function(vp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype._modify_directory_host = function(dir) {
|
FFZ.prototype.modify_directory_host = function(component) {
|
||||||
var f = this, mutator;
|
var f = this;
|
||||||
|
utils.ember_reopen_view(component, {
|
||||||
mutator = {
|
|
||||||
didInsertElement: function() {
|
|
||||||
this._super();
|
|
||||||
try {
|
|
||||||
this.ffzInit();
|
|
||||||
} catch(err) {
|
|
||||||
f.error("component:host-preview ffzInit: " + err);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
willClearRender: function() {
|
|
||||||
this._super();
|
|
||||||
try {
|
|
||||||
this.ffzCleanup();
|
|
||||||
} catch(err) {
|
|
||||||
f.error("component:host-preview ffzCleanup: " + err);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
ffzVisitChannel: function(target, e) {
|
ffzVisitChannel: function(target, e) {
|
||||||
var Channel = utils.ember_resolve('model:channel');
|
var Channel = utils.ember_resolve('model:deprecated-channel');
|
||||||
if ( ! Channel )
|
if ( ! Channel )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -773,7 +673,7 @@ FFZ.prototype._modify_directory_host = function(dir) {
|
||||||
this.$('.thumb .cap img').attr('src', url);
|
this.$('.thumb .cap img').attr('src', url);
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzCleanup: function() {
|
ffz_destroy: function() {
|
||||||
var target = this.get('stream.target.channel');
|
var target = this.get('stream.target.channel');
|
||||||
if ( f._popup && f._popup.classList.contains('ffz-channel-selector') && f._popup.getAttribute('data-channel') === target )
|
if ( f._popup && f._popup.classList.contains('ffz-channel-selector') && f._popup.getAttribute('data-channel') === target )
|
||||||
f.close_popup();
|
f.close_popup();
|
||||||
|
@ -782,7 +682,7 @@ FFZ.prototype._modify_directory_host = function(dir) {
|
||||||
clearInterval(this._ffz_image_timer);
|
clearInterval(this._ffz_image_timer);
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzInit: function() {
|
ffz_init: function() {
|
||||||
var el = this.get('element'),
|
var el = this.get('element'),
|
||||||
meta = el && el.querySelector('.meta'),
|
meta = el && el.querySelector('.meta'),
|
||||||
thumb = el && el.querySelector('.thumb'),
|
thumb = el && el.querySelector('.thumb'),
|
||||||
|
@ -839,14 +739,5 @@ FFZ.prototype._modify_directory_host = function(dir) {
|
||||||
cap.addEventListener('click', this.ffzShowHostMenu.bind(this));
|
cap.addEventListener('click', this.ffzShowHostMenu.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if ( dir )
|
|
||||||
dir.reopen(mutator);
|
|
||||||
else {
|
|
||||||
dir = Ember.Component.extend(mutator);
|
|
||||||
App.__deprecatedInstance__.registry.register('component:host-preview', dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dir;
|
|
||||||
}
|
}
|
|
@ -21,15 +21,8 @@ var FFZ = window.FrankerFaceZ,
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype.setup_feed_cards = function() {
|
FFZ.prototype.setup_feed_cards = function() {
|
||||||
var FeedCard = utils.ember_resolve('component:channel-feed/card');
|
this.update_views('component:channel-feed/card', this.modify_feed_card);
|
||||||
if ( ! FeedCard )
|
this.update_views('component:channel-feed/comment', this.modify_feed_comment);
|
||||||
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();
|
|
||||||
} catch(err) { }
|
|
||||||
|
|
||||||
this.rerender_feed_cards();
|
this.rerender_feed_cards();
|
||||||
}
|
}
|
||||||
|
@ -37,6 +30,7 @@ FFZ.prototype.setup_feed_cards = function() {
|
||||||
|
|
||||||
FFZ.prototype.rerender_feed_cards = function(for_set) {
|
FFZ.prototype.rerender_feed_cards = function(for_set) {
|
||||||
var FeedCard = utils.ember_resolve('component:channel-feed/card'),
|
var FeedCard = utils.ember_resolve('component:channel-feed/card'),
|
||||||
|
FeedComment = utils.ember_resolve('component:channel-feed/comment'),
|
||||||
views = utils.ember_views();
|
views = utils.ember_views();
|
||||||
|
|
||||||
if ( ! FeedCard )
|
if ( ! FeedCard )
|
||||||
|
@ -46,30 +40,31 @@ FFZ.prototype.rerender_feed_cards = function(for_set) {
|
||||||
var view = views[view_id];
|
var view = views[view_id];
|
||||||
if ( view instanceof FeedCard ) {
|
if ( view instanceof FeedCard ) {
|
||||||
try {
|
try {
|
||||||
if ( ! view.ffzInit )
|
if ( ! view.ffz_init )
|
||||||
this._modify_feed_card(view);
|
this.modify_feed_card(view);
|
||||||
view.ffzInit(for_set);
|
view.ffz_init(for_set);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
this.error("setup component:channel-feed/card ffzInit: " + err)
|
this.error("setup component:channel-feed/card ffzInit", err)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( FeedComment && view instanceof FeedComment ) {
|
||||||
FFZ.prototype._modify_feed_card = function(component) {
|
|
||||||
var f = this;
|
|
||||||
component.reopen({
|
|
||||||
didInsertElement: function() {
|
|
||||||
this._super();
|
|
||||||
try {
|
try {
|
||||||
this.ffzInit();
|
if ( ! view.ffz_init )
|
||||||
|
this.modify_feed_comment(view);
|
||||||
|
view.ffz_init(for_set);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
f.error("component:channel-feed/card ffzInit: " + err);
|
this.error("setup component:channel-feed/comment ffzInit", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
ffzInit: function(for_set) {
|
|
||||||
|
FFZ.prototype.modify_feed_card = function(component) {
|
||||||
|
var f = this;
|
||||||
|
utils.ember_reopen_view(component, {
|
||||||
|
ffz_init: function(for_set) {
|
||||||
var el = this.get('element'),
|
var el = this.get('element'),
|
||||||
message = this.get('post.body'),
|
message = this.get('post.body'),
|
||||||
emotes = parse_emotes(this.get('post.emotes')),
|
emotes = parse_emotes(this.get('post.emotes')),
|
||||||
|
@ -97,3 +92,33 @@ FFZ.prototype._modify_feed_card = function(component) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.prototype.modify_feed_comment = function(component) {
|
||||||
|
var f = this;
|
||||||
|
utils.ember_reopen_view(component, {
|
||||||
|
ffz_init: function(for_set) {
|
||||||
|
var el = this.get('element'),
|
||||||
|
message = this.get('comment.body'),
|
||||||
|
emotes = parse_emotes(this.get('comment.emotes')),
|
||||||
|
user_id = this.get('comment.user.login'),
|
||||||
|
room_id = this.get('parentView.parentView.channelId') || this.get('parentView.parentView.post.user.login') || null,
|
||||||
|
pbody = el && el.querySelector('.activity-body');
|
||||||
|
|
||||||
|
if ( ! message || ! el || ! pbody )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If this is for a specific emote set, only rerender if it matters.
|
||||||
|
if ( for_set && f.rooms && f.rooms[room_id] ) {
|
||||||
|
var sets = f.getEmotes(user_id, room_id);
|
||||||
|
if ( sets.indexOf(for_set) === -1 )
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokens = f.tokenize_feed_body(message, emotes, user_id, room_id),
|
||||||
|
output = f.render_tokens(tokens, true, false);
|
||||||
|
|
||||||
|
pbody.innerHTML = '<p>' + output + '</p>';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -167,7 +167,7 @@ FFZ.prototype.setup_profile_following = function() {
|
||||||
|
|
||||||
// Refresh all existing following data.
|
// Refresh all existing following data.
|
||||||
var count = 0,
|
var count = 0,
|
||||||
Channel = utils.ember_resolve('model:channel');
|
Channel = utils.ember_resolve('model:deprecated-channel');
|
||||||
|
|
||||||
if ( Channel && Channel._cache )
|
if ( Channel && Channel._cache )
|
||||||
for(var key in Channel._cache) {
|
for(var key in Channel._cache) {
|
||||||
|
|
|
@ -240,16 +240,26 @@ FFZ.prototype.setup_layout = function() {
|
||||||
}.observes("isTooSmallForRightColumn"),
|
}.observes("isTooSmallForRightColumn"),
|
||||||
|
|
||||||
ffzUpdateCss: function() {
|
ffzUpdateCss: function() {
|
||||||
var out = '';
|
var window_height = this.get('windowHeight'),
|
||||||
|
window_width = this.get('windowWidth'),
|
||||||
|
out = 'body.ffz-small-player #player .dynamic-player {' +
|
||||||
|
'position: fixed;' +
|
||||||
|
'z-index: 9;' +
|
||||||
|
'box-shadow: 0 0 20px 0 black;';
|
||||||
|
|
||||||
|
if ( .25 * window_width >= .5 * window_height )
|
||||||
|
out += 'width: 25vw !important; height: 14.0625vw !important;';
|
||||||
|
else
|
||||||
|
out += 'width: 50vh !important; height: 28.125vh !important;';
|
||||||
|
|
||||||
if ( ! f.has_bttv ) {
|
if ( ! f.has_bttv ) {
|
||||||
if ( this.get('isRightColumnClosed') )
|
if ( this.get('isRightColumnClosed') )
|
||||||
out = '';
|
out += 'top: 0; right: 0}';
|
||||||
|
|
||||||
else {
|
else {
|
||||||
if ( this.get('portraitMode') ) {
|
if ( this.get('portraitMode') ) {
|
||||||
var size = this.get('playerSize'),
|
var size = this.get('playerSize'),
|
||||||
video_below = this.get('portraitVideoBelow'),
|
video_below = this.get('portraitVideoBelow'),
|
||||||
window_height = this.get('windowHeight'),
|
|
||||||
window_width = this.get('windowWidth'),
|
|
||||||
|
|
||||||
video_height = size[1] + 120 + 60,
|
video_height = size[1] + 120 + 60,
|
||||||
chat_height = window_height - video_height,
|
chat_height = window_height - video_height,
|
||||||
|
@ -263,7 +273,8 @@ FFZ.prototype.setup_layout = function() {
|
||||||
theatre_video_top = video_below ? theatre_chat_height : 0,
|
theatre_video_top = video_below ? theatre_chat_height : 0,
|
||||||
theatre_chat_top = video_below ? 0 : theatre_video_height;
|
theatre_chat_top = video_below ? 0 : theatre_video_height;
|
||||||
|
|
||||||
out = 'body[data-current-path^="user."] #left_col .warp { min-height: inherit }' +
|
out += 'top: ' + video_top + 'px;right: 0}' +
|
||||||
|
'body[data-current-path^="user."] #left_col .warp { min-height: inherit }' +
|
||||||
'body[data-current-path^="user."] #left_col { overflow: hidden }' +
|
'body[data-current-path^="user."] #left_col { overflow: hidden }' +
|
||||||
'body[data-current-path^="user."] #left_col .warp,' +
|
'body[data-current-path^="user."] #left_col .warp,' +
|
||||||
'body[data-current-path^="user."] #left_col,' +
|
'body[data-current-path^="user."] #left_col,' +
|
||||||
|
@ -290,7 +301,9 @@ FFZ.prototype.setup_layout = function() {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
var width = this.get('rightColumnWidth');
|
var width = this.get('rightColumnWidth');
|
||||||
out = '#main_col.expandRight #right_close{left: none !important}' +
|
|
||||||
|
out += 'top: 0; right: ' + width + 'px}' +
|
||||||
|
'#main_col.expandRight #right_close{left: none !important}' +
|
||||||
'#right_col{width:' + width + 'px}' +
|
'#right_col{width:' + width + 'px}' +
|
||||||
'body:not(.ffz-sidebar-swap) #main_col:not(.expandRight){' +
|
'body:not(.ffz-sidebar-swap) #main_col:not(.expandRight){' +
|
||||||
'margin-right:' + width + 'px}' +
|
'margin-right:' + width + 'px}' +
|
||||||
|
@ -317,7 +330,8 @@ FFZ.prototype.setup_layout = function() {
|
||||||
ffzFixTabs: function() {
|
ffzFixTabs: function() {
|
||||||
if ( f.settings.group_tabs && f._chatv && f._chatv._ffz_tabs ) {
|
if ( f.settings.group_tabs && f._chatv && f._chatv._ffz_tabs ) {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
f._chatv && f._chatv.$('.chat-room').css('top', f._chatv._ffz_tabs.offsetHeight + "px");
|
var cr = f._chatv && f._chatv.$('.chat-room');
|
||||||
|
cr && cr.css && cr.css('top', f._chatv._ffz_tabs.offsetHeight + "px");
|
||||||
},0);
|
},0);
|
||||||
}
|
}
|
||||||
}.observes("isRightColumnClosed", "rightColumnWidth", "portraitMode", "playerSize")
|
}.observes("isRightColumnClosed", "rightColumnWidth", "portraitMode", "playerSize")
|
||||||
|
|
|
@ -51,6 +51,18 @@ FFZ.settings_info.replace_bad_emotes = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.settings_info.parse_emoticons = {
|
||||||
|
type: "boolean",
|
||||||
|
value: true,
|
||||||
|
|
||||||
|
category: "Chat Appearance",
|
||||||
|
no_bttv: true,
|
||||||
|
|
||||||
|
name: "Display Emoticons",
|
||||||
|
help: "Display emoticons in chat messages rather than just text."
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
FFZ.settings_info.parse_emoji = {
|
FFZ.settings_info.parse_emoji = {
|
||||||
type: "select",
|
type: "select",
|
||||||
options: {
|
options: {
|
||||||
|
@ -74,7 +86,7 @@ FFZ.settings_info.parse_emoji = {
|
||||||
|
|
||||||
category: "Chat Appearance",
|
category: "Chat Appearance",
|
||||||
|
|
||||||
name: "Emoji Display",
|
name: "Display Emoji",
|
||||||
help: "Replace emoji in chat messages with nicer looking images from either Twitter or Google."
|
help: "Replace emoji in chat messages with nicer looking images from either Twitter or Google."
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -354,6 +366,19 @@ FFZ.settings_info.old_sub_notices = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.settings_info.emote_alignment = {
|
||||||
|
type: "boolean",
|
||||||
|
value: false,
|
||||||
|
|
||||||
|
category: "Chat Appearance",
|
||||||
|
no_bttv: true,
|
||||||
|
|
||||||
|
name: "Baseline Emoticon Alignment",
|
||||||
|
help: "Align emotes on the text baseline, making messages taller but ensuring emotes don't overlap.",
|
||||||
|
|
||||||
|
on_update: function(val) { document.body.classList.toggle('ffz-baseline-emoticons', !this.has_bttv && val) }
|
||||||
|
};
|
||||||
|
|
||||||
FFZ.settings_info.chat_padding = {
|
FFZ.settings_info.chat_padding = {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: false,
|
value: false,
|
||||||
|
@ -588,6 +613,7 @@ FFZ.prototype.setup_line = function() {
|
||||||
|
|
||||||
// Chat Enhancements
|
// Chat Enhancements
|
||||||
document.body.classList.toggle('ffz-alias-italics', this.settings.alias_italics);
|
document.body.classList.toggle('ffz-alias-italics', this.settings.alias_italics);
|
||||||
|
document.body.classList.toggle('ffz-baseline-emoticons', !this.has_bttv && this.settings.emote_alignment);
|
||||||
|
|
||||||
this.toggle_style('chat-setup', !this.has_bttv && (this.settings.chat_rows || this.settings.chat_separators || this.settings.highlight_messages_with_mod_card));
|
this.toggle_style('chat-setup', !this.has_bttv && (this.settings.chat_rows || this.settings.chat_separators || this.settings.highlight_messages_with_mod_card));
|
||||||
this.toggle_style('chat-padding', !this.has_bttv && this.settings.chat_padding);
|
this.toggle_style('chat-padding', !this.has_bttv && this.settings.chat_padding);
|
||||||
|
@ -710,7 +736,7 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
|
||||||
if ( is_whisper || this_ul >= other_ul || f.settings.mod_buttons.length === 0 )
|
if ( is_whisper || this_ul >= other_ul || f.settings.mod_buttons.length === 0 )
|
||||||
return '';
|
return '';
|
||||||
|
|
||||||
output = '<span class="mod-icons float-left">';
|
output = '<span class="mod-icons">';
|
||||||
|
|
||||||
for(var i=0, l = f.settings.mod_buttons.length; i < l; i++) {
|
for(var i=0, l = f.settings.mod_buttons.length; i < l; i++) {
|
||||||
var pair = f.settings.mod_buttons[i],
|
var pair = f.settings.mod_buttons[i],
|
||||||
|
@ -720,22 +746,22 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
|
||||||
|
|
||||||
if ( btn === false ) {
|
if ( btn === false ) {
|
||||||
if ( deleted )
|
if ( deleted )
|
||||||
output += '<a class="mod-icon float-left html-tooltip unban" title="Unban User" href="#">Unban</a>';
|
output += '<a class="mod-icon html-tooltip unban" title="Unban User" href="#">Unban</a>';
|
||||||
else
|
else
|
||||||
output += '<a class="mod-icon float-left html-tooltip ban" title="Ban User" href="#">Ban</a>';
|
output += '<a class="mod-icon html-tooltip ban" title="Ban User" href="#">Ban</a>';
|
||||||
|
|
||||||
} else if ( btn === 600 )
|
} else if ( btn === 600 )
|
||||||
output += '<a class="mod-icon float-left html-tooltip timeout" title="Timeout User (10m)" href="#">Timeout</a>';
|
output += '<a class="mod-icon html-tooltip timeout" title="Timeout User (10m)" href="#">Timeout</a>';
|
||||||
|
|
||||||
else {
|
else {
|
||||||
if ( typeof btn === "string" ) {
|
if ( typeof btn === "string" ) {
|
||||||
cmd = btn.replace(/{user}/g, user).replace(/ *<LINE> */, "\n");
|
cmd = btn.replace(/{user}/g, user).replace(/{id}/g, this.get('msgObject.tags.id')).replace(/ *<LINE> */, "\n");
|
||||||
tip = "Custom Command" + (cmd.indexOf("\n") !== -1 ? 's' : '') + '<br>' + utils.quote_san(cmd).replace('\n','<br>');
|
tip = "Custom Command" + (cmd.indexOf("\n") !== -1 ? 's' : '') + '<br>' + utils.quote_san(cmd).replace('\n','<br>');
|
||||||
} else {
|
} else {
|
||||||
cmd = "/timeout " + user + " " + btn;
|
cmd = "/timeout " + user + " " + btn;
|
||||||
tip = "Timeout User (" + utils.duration_string(btn) + ")";
|
tip = "Timeout User (" + utils.duration_string(btn) + ")";
|
||||||
}
|
}
|
||||||
output += '<a class="mod-icon float-left html-tooltip' + (cmd.substr(0,9) === '/timeout' ? ' is-timeout' : '') + ' custom" data-cmd="' + utils.quote_attr(cmd) + '" title="' + tip + '" href="#">' + prefix + '</a>';
|
output += '<a class="mod-icon html-tooltip' + (cmd.substr(0,9) === '/timeout' ? ' is-timeout' : '') + ' custom" data-cmd="' + utils.quote_attr(cmd) + '" title="' + tip + '" href="#">' + prefix + '</a>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -770,18 +796,18 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
|
||||||
// System Message
|
// System Message
|
||||||
if ( system_msg ) {
|
if ( system_msg ) {
|
||||||
output += '<div class="system-msg">' + utils.sanitize(system_msg) + '</div>';
|
output += '<div class="system-msg">' + utils.sanitize(system_msg) + '</div>';
|
||||||
if ( this.get('shouldRenderMessageBody') === false )
|
if ( this.get('ffzShouldRenderMessageBody') === false )
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timestamp
|
// Timestamp
|
||||||
output += '<span class="timestamp float-left">' + this.get('timestamp') + '</span> ';
|
output += '<span class="timestamp">' + this.get('timestamp') + '</span> ';
|
||||||
|
|
||||||
// Moderator Actions
|
// Moderator Actions
|
||||||
output += this.buildModIconsHTML();
|
output += this.buildModIconsHTML();
|
||||||
|
|
||||||
// Badges
|
// Badges
|
||||||
output += '<span class="badges float-left">' + f.render_badges(f.get_line_badges(this.get('msgObject'))) + '</span>';
|
output += '<span class="badges">' + f.render_badges(f.get_line_badges(this.get('msgObject'))) + '</span>';
|
||||||
|
|
||||||
// Alias Support
|
// Alias Support
|
||||||
var alias = f.aliases[user],
|
var alias = f.aliases[user],
|
||||||
|
@ -842,7 +868,7 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
|
||||||
} else
|
} else
|
||||||
output = '<span class="message">';
|
output = '<span class="message">';
|
||||||
|
|
||||||
output += f.render_tokens(this.get('ffzTokenizedMessage'), true, is_whisper && f.settings.filter_whispered_links && this.get("ffzUserLevel") < 4);
|
output += f.render_tokens(this.get('ffzTokenizedMessage'), true, is_whisper && f.settings.filter_whispered_links && this.get("ffzUserLevel") < 4, this.get('isBitsEnabled'));
|
||||||
|
|
||||||
var old_messages = this.get('msgObject.ffz_old_messages');
|
var old_messages = this.get('msgObject.ffz_old_messages');
|
||||||
if ( old_messages && old_messages.length )
|
if ( old_messages && old_messages.length )
|
||||||
|
@ -856,7 +882,7 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
|
||||||
output = this.buildSenderHTML();
|
output = this.buildSenderHTML();
|
||||||
|
|
||||||
// If this is a whisper, or if we should render the message body, render it.
|
// If this is a whisper, or if we should render the message body, render it.
|
||||||
if ( this.get('shouldRenderMessageBody') !== false )
|
if ( this.get('ffzShouldRenderMessageBody') !== false )
|
||||||
if ( this.get('msgObject.deleted') )
|
if ( this.get('msgObject.deleted') )
|
||||||
output += this.buildDeletedMessageHTML()
|
output += this.buildDeletedMessageHTML()
|
||||||
else
|
else
|
||||||
|
@ -865,6 +891,14 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
|
||||||
el.innerHTML = output;
|
el.innerHTML = output;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ffzShouldRenderMessageBody: function() {
|
||||||
|
return ! this.get('hasSystemMsg') || this.get('hasMessageBody');
|
||||||
|
}.property('hasSystemMsg', 'hasMessageBody'),
|
||||||
|
|
||||||
|
shouldRenderMessageBody: function() {
|
||||||
|
return false;
|
||||||
|
}.property('hasSystemMsg', 'hasMessageBody'),
|
||||||
|
|
||||||
ffzWasDeleted: function() {
|
ffzWasDeleted: function() {
|
||||||
return f.settings.prevent_clear && this.get("msgObject.ffz_deleted")
|
return f.settings.prevent_clear && this.get("msgObject.ffz_deleted")
|
||||||
}.property("msgObject.ffz_deleted"),
|
}.property("msgObject.ffz_deleted"),
|
||||||
|
@ -883,8 +917,8 @@ FFZ.prototype._modify_chat_subline = function(component) {
|
||||||
this._modify_chat_line(component);
|
this._modify_chat_line(component);
|
||||||
|
|
||||||
component.reopen({
|
component.reopen({
|
||||||
classNameBindings: [":message-line", ":chat-line", "msgObject.style", "msgObject.ffz_has_mention:ffz-mentioned", "ffzWasDeleted:ffz-deleted", "ffzHasOldMessages:clearfix", "ffzHasOldMessages:ffz-has-deleted"],
|
classNameBindings: ["msgObject.style", "msgObject.ffz_has_mention:ffz-mentioned", "ffzWasDeleted:ffz-deleted", "ffzHasOldMessages:clearfix", "ffzHasOldMessages:ffz-has-deleted"],
|
||||||
attributeBindings: ["msgObject.room:data-room", "msgObject.from:data-sender", "msgObject.deleted:data-deleted"],
|
attributeBindings: ["msgObject.tags.id:data-id", "msgObject.room:data-room", "msgObject.from:data-sender", "msgObject.deleted:data-deleted"],
|
||||||
|
|
||||||
didInsertElement: function() {
|
didInsertElement: function() {
|
||||||
this.set('msgObject._line', this);
|
this.set('msgObject._line', this);
|
||||||
|
@ -1024,10 +1058,10 @@ FFZ.prototype._modify_vod_line = function(component) {
|
||||||
if ( ! this.get("isViewerModeratorOrHigher") || this.get("isModeratorOrHigher") )
|
if ( ! this.get("isViewerModeratorOrHigher") || this.get("isModeratorOrHigher") )
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
return '<span class="mod-icons float-left">' +
|
return '<span class="mod-icons">' +
|
||||||
(this.get('msgObject.deleted') ?
|
(this.get('msgObject.deleted') ?
|
||||||
'<em class="mod-icon float-left unban"></em>' :
|
'<em class="mod-icon unban"></em>' :
|
||||||
'<a class="mod-icon float-left html-tooltip delete" title="Delete Message" href="#">Delete</a>') + '</span>';
|
'<a class="mod-icon html-tooltip delete" title="Delete Message" href="#">Delete</a>') + '</span>';
|
||||||
},
|
},
|
||||||
|
|
||||||
buildDeletedMesageHTML: function() {
|
buildDeletedMesageHTML: function() {
|
||||||
|
|
|
@ -353,7 +353,8 @@ FFZ.settings_info.mod_buttons = {
|
||||||
"Custom In-Line Moderation Icons",
|
"Custom In-Line Moderation Icons",
|
||||||
"Please enter a list of commands to be made available as mod icons within chat lines. Commands are separated by spaces. " +
|
"Please enter a list of commands to be made available as mod icons within chat lines. Commands are separated by spaces. " +
|
||||||
"To include spaces in a command, surround the command with double quotes (\"). Use <code>{user}</code> to insert the user's name " +
|
"To include spaces in a command, surround the command with double quotes (\"). Use <code>{user}</code> to insert the user's name " +
|
||||||
"into the command, otherwise it will be appended to the end.</p><p><b>Example:</b> <code>!permit \"!reg add {user}\"</code></p><p>To " +
|
"into the command, otherwise it will be appended to the end. Use <code>{id}</code> to insert the unique message ID into the command.</p>" +
|
||||||
|
"<p><b>Example:</b> <code>!permit \"!reg add {user}\" \"/timeout {user} 1 {id}\"</code></p><p>To " +
|
||||||
"send multiple commands, separate them with <code><LINE></code>.</p><p>Numeric values will become timeout buttons for " +
|
"send multiple commands, separate them with <code><LINE></code>.</p><p>Numeric values will become timeout buttons for " +
|
||||||
"that number of seconds. The text <code><BAN></code> is a special value that will act like the normal Ban button in chat.</p><p>" +
|
"that number of seconds. The text <code><BAN></code> is a special value that will act like the normal Ban button in chat.</p><p>" +
|
||||||
"To assign a specific letter for use as the icon, specify it at the start of the command followed by an equals sign.</p><p>" +
|
"To assign a specific letter for use as the icon, specify it at the start of the command followed by an equals sign.</p><p>" +
|
||||||
|
@ -583,7 +584,6 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
helpers = window.require && window.require("web-client/helpers/chat/chat-line-helpers");
|
helpers = window.require && window.require("web-client/helpers/chat/chat-line-helpers");
|
||||||
} catch(err) { }
|
} catch(err) { }
|
||||||
|
|
||||||
|
|
||||||
this.log("Listening to the Settings controller to catch mod icon state changes.");
|
this.log("Listening to the Settings controller to catch mod icon state changes.");
|
||||||
var f = this,
|
var f = this,
|
||||||
Settings = utils.ember_lookup('controller:settings');
|
Settings = utils.ember_lookup('controller:settings');
|
||||||
|
@ -594,7 +594,6 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
f.settings.set('chat_mod_icon_visibility', 1);
|
f.settings.set('chat_mod_icon_visibility', 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
this.log("Modifying Mousetrap stopCallback so we can catch ESC.");
|
this.log("Modifying Mousetrap stopCallback so we can catch ESC.");
|
||||||
var orig_stop = Mousetrap.stopCallback;
|
var orig_stop = Mousetrap.stopCallback;
|
||||||
Mousetrap.stopCallback = function(e, element, combo) {
|
Mousetrap.stopCallback = function(e, element, combo) {
|
||||||
|
@ -609,11 +608,13 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
el && el.classList.toggle('ffz-flip');
|
el && el.classList.toggle('ffz-flip');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
this.log("Hooking the Ember Moderation Card view.");
|
this.log("Hooking the Ember Moderation Card view.");
|
||||||
var Card = utils.ember_resolve('component:chat/moderation-card');
|
this.update_views('component:chat/moderation-card', this.modify_moderation_card);
|
||||||
|
}
|
||||||
|
|
||||||
Card.reopen({
|
FFZ.prototype.modify_moderation_card = function(component) {
|
||||||
|
var f = this;
|
||||||
|
utils.ember_reopen_view(component, {
|
||||||
ffzForceRedraw: function() {
|
ffzForceRedraw: function() {
|
||||||
this.rerender();
|
this.rerender();
|
||||||
if ( f.settings.mod_card_history )
|
if ( f.settings.mod_card_history )
|
||||||
|
@ -667,18 +668,14 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
return alias || this.get("cardInfo.user.display_name") || user_id.capitalize();
|
return alias || this.get("cardInfo.user.display_name") || user_id.capitalize();
|
||||||
}),
|
}),
|
||||||
|
|
||||||
willDestroy: function() {
|
ffz_destroy: function() {
|
||||||
if ( f._mod_card === this )
|
if ( f._mod_card === this )
|
||||||
f._mod_card = undefined;
|
f._mod_card = undefined;
|
||||||
|
|
||||||
utils.update_css(f._chat_style, 'mod-card-highlight');
|
utils.update_css(f._chat_style, 'mod-card-highlight');
|
||||||
|
|
||||||
this._super();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
didInsertElement: function() {
|
ffz_init: function() {
|
||||||
this._super();
|
|
||||||
try {
|
|
||||||
if ( f.has_bttv )
|
if ( f.has_bttv )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -744,11 +741,10 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
|
|
||||||
// Info-tize it!
|
// Info-tize it!
|
||||||
if ( f.settings.mod_card_info ) {
|
if ( f.settings.mod_card_info ) {
|
||||||
var info = document.createElement('div'),
|
var info = utils.createElement('div', 'info channel-stats'),
|
||||||
after = el.querySelector('h3.name');
|
after = el.querySelector('h3.name');
|
||||||
if ( after ) {
|
if ( after ) {
|
||||||
el.classList.add('ffz-has-info');
|
el.classList.add('ffz-has-info');
|
||||||
info.className = 'info channel-stats';
|
|
||||||
after.parentElement.insertBefore(info, after.nextSibling);
|
after.parentElement.insertBefore(info, after.nextSibling);
|
||||||
this.ffzRebuildInfo();
|
this.ffzRebuildInfo();
|
||||||
}
|
}
|
||||||
|
@ -756,8 +752,7 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
|
|
||||||
// Additional Buttons
|
// Additional Buttons
|
||||||
if ( is_mod && f.settings.mod_card_buttons && f.settings.mod_card_buttons.length ) {
|
if ( is_mod && f.settings.mod_card_buttons && f.settings.mod_card_buttons.length ) {
|
||||||
line = document.createElement('div');
|
line = utils.createElement('div', 'extra-interface interface clearfix');
|
||||||
line.className = 'extra-interface interface clearfix';
|
|
||||||
|
|
||||||
var cmds = {},
|
var cmds = {},
|
||||||
add_btn_click = function(cmd) {
|
add_btn_click = function(cmd) {
|
||||||
|
@ -884,8 +879,7 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
},
|
},
|
||||||
|
|
||||||
btn_make = function(timeout) {
|
btn_make = function(timeout) {
|
||||||
var btn = document.createElement('button')
|
var btn = utils.createElement('button', 'button ffz-no-bg');
|
||||||
btn.className = 'button ffz-no-bg';
|
|
||||||
btn.innerHTML = utils.duration_string(timeout);
|
btn.innerHTML = utils.duration_string(timeout);
|
||||||
btn.title = "Timeout User for " + utils.number_commas(timeout) + " Second" + (timeout != 1 ? "s" : "");
|
btn.title = "Timeout User for " + utils.number_commas(timeout) + " Second" + (timeout != 1 ? "s" : "");
|
||||||
|
|
||||||
|
@ -902,13 +896,10 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
|
|
||||||
if ( f.settings.mod_card_durations && f.settings.mod_card_durations.length ) {
|
if ( f.settings.mod_card_durations && f.settings.mod_card_durations.length ) {
|
||||||
// Extra Moderation
|
// Extra Moderation
|
||||||
line = document.createElement('div');
|
line = utils.createElement('div', 'extra-interface interface clearfix');
|
||||||
line.className = 'extra-interface interface clearfix';
|
|
||||||
|
|
||||||
line.appendChild(btn_make(1));
|
line.appendChild(btn_make(1));
|
||||||
|
|
||||||
var s = document.createElement('span');
|
var s = utils.createElement('span', 'right');
|
||||||
s.className = 'right';
|
|
||||||
line.appendChild(s);
|
line.appendChild(s);
|
||||||
|
|
||||||
for(var i=0; i < f.settings.mod_card_durations.length; i++)
|
for(var i=0; i < f.settings.mod_card_durations.length; i++)
|
||||||
|
@ -943,8 +934,7 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
ban_btn.setAttribute('title', '(B)an User');
|
ban_btn.setAttribute('title', '(B)an User');
|
||||||
|
|
||||||
// Unban Button
|
// Unban Button
|
||||||
var unban_btn = document.createElement('button');
|
var unban_btn = utils.createElement('button', 'unban button button--icon-only light');
|
||||||
unban_btn.className = 'unban button button--icon-only light';
|
|
||||||
unban_btn.innerHTML = '<figure class="icon">' + CHECK + '</figure>';
|
unban_btn.innerHTML = '<figure class="icon">' + CHECK + '</figure>';
|
||||||
unban_btn.title = (f.settings.mod_card_hotkeys ? "(U)" : "U") + "nban User";
|
unban_btn.title = (f.settings.mod_card_hotkeys ? "(U)" : "U") + "nban User";
|
||||||
|
|
||||||
|
@ -970,7 +960,7 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
|
|
||||||
|
|
||||||
// Follow Button
|
// Follow Button
|
||||||
var follow_button = el.querySelector(".interface > .follow-button");
|
var follow_button = el.querySelector(".follow-button");
|
||||||
if ( follow_button )
|
if ( follow_button )
|
||||||
jQuery(follow_button).tipsy({title: function() { return follow_button.classList.contains('is-following') ? "Unfollow" : "Follow"}});
|
jQuery(follow_button).tipsy({title: function() { return follow_button.classList.contains('is-following') ? "Unfollow" : "Follow"}});
|
||||||
|
|
||||||
|
@ -986,8 +976,7 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
jQuery(msg_btn).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
jQuery(msg_btn).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
|
|
||||||
|
|
||||||
var real_msg = document.createElement('button');
|
var real_msg = utils.createElement('button', 'message-button button button--icon-only message html-tooltip');
|
||||||
real_msg.className = 'message-button button button--icon-only message html-tooltip';
|
|
||||||
real_msg.innerHTML = '<figure class="icon">' + MESSAGE + '</figure>';
|
real_msg.innerHTML = '<figure class="icon">' + MESSAGE + '</figure>';
|
||||||
real_msg.title = "Message User";
|
real_msg.title = "Message User";
|
||||||
|
|
||||||
|
@ -1000,8 +989,7 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
|
|
||||||
|
|
||||||
// Alias Button
|
// Alias Button
|
||||||
var alias_btn = document.createElement('button');
|
var alias_btn = utils.createElement('button', 'alias button button--icon-only html-tooltip');
|
||||||
alias_btn.className = 'alias button button--icon-only html-tooltip';
|
|
||||||
alias_btn.innerHTML = '<figure class="icon">' + constants.EDIT + '</figure>';
|
alias_btn.innerHTML = '<figure class="icon">' + constants.EDIT + '</figure>';
|
||||||
alias_btn.title = "Set Alias";
|
alias_btn.title = "Set Alias";
|
||||||
|
|
||||||
|
@ -1057,12 +1045,6 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
}});
|
}});
|
||||||
|
|
||||||
el.focus();
|
el.focus();
|
||||||
|
|
||||||
} catch(err) {
|
|
||||||
try {
|
|
||||||
f.error("ModerationCardView didInsertElement: " + err);
|
|
||||||
} catch(err) { }
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzReposition: function() {
|
ffzReposition: function() {
|
||||||
|
@ -1104,8 +1086,7 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
history = el && el.querySelector('.chat-history');
|
history = el && el.querySelector('.chat-history');
|
||||||
|
|
||||||
if ( ! history ) {
|
if ( ! history ) {
|
||||||
history = document.createElement('ul');
|
history = utils.createElement('ul', 'interface clearfix chat-history');
|
||||||
history.className = 'interface clearfix chat-history';
|
|
||||||
el.appendChild(history);
|
el.appendChild(history);
|
||||||
} else {
|
} else {
|
||||||
history.classList.remove('loading');
|
history.classList.remove('loading');
|
||||||
|
@ -1118,7 +1099,7 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
if ( ! success )
|
if ( ! success )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
f.parse_history(data, null, room_id, delete_links, tmiSession);
|
f.parse_history(data, null, null, room_id, delete_links, tmiSession);
|
||||||
|
|
||||||
var i = data.length,
|
var i = data.length,
|
||||||
was_at_top = history && history.scrollTop >= (history.scrollHeight - history.clientHeight),
|
was_at_top = history && history.scrollTop >= (history.scrollHeight - history.clientHeight),
|
||||||
|
@ -1211,10 +1192,9 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
logs.innerHTML = '';
|
logs.innerHTML = '';
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
logs = document.createElement('ul');
|
logs = utils.createElement('ul', 'interface clearfix chat-history adjacent-history');
|
||||||
back = document.createElement('button');
|
back = utils.createElement('button', 'button ffz-no-bg back-button');
|
||||||
|
|
||||||
back.className = 'button ffz-no-bg back-button';
|
|
||||||
back.innerHTML = '« Back';
|
back.innerHTML = '« Back';
|
||||||
|
|
||||||
back.addEventListener('click', function() {
|
back.addEventListener('click', function() {
|
||||||
|
@ -1222,12 +1202,10 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
back.parentElement.removeChild(back);
|
back.parentElement.removeChild(back);
|
||||||
history.classList.remove('hidden');
|
history.classList.remove('hidden');
|
||||||
});
|
});
|
||||||
|
|
||||||
logs.className = 'interface clearfix chat-history adjacent-history';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
f.parse_history(data, null, room_id, delete_links, tmiSession, function(msg) {
|
f.parse_history(data, null, null, room_id, delete_links, tmiSession, function(msg) {
|
||||||
msg.from_server = true;
|
msg.from_server = true;
|
||||||
|
|
||||||
var line_time = line.date.getTime() - (line.from_server ? 0 : (f._ws_server_offset || 0)),
|
var line_time = line.date.getTime() - (line.from_server ? 0 : (f._ws_server_offset || 0)),
|
||||||
|
@ -1276,7 +1254,7 @@ FFZ.prototype._build_mod_card_history = function(msg, modcard, show_from) {
|
||||||
style = '', colored = '';
|
style = '', colored = '';
|
||||||
|
|
||||||
if ( helpers && helpers.getTime )
|
if ( helpers && helpers.getTime )
|
||||||
out.push('<span class="timestamp float-left">' + helpers.getTime(msg.date) + '</span>');
|
out.push('<span class="timestamp">' + helpers.getTime(msg.date) + '</span>');
|
||||||
|
|
||||||
|
|
||||||
var alias = this.aliases[msg.from],
|
var alias = this.aliases[msg.from],
|
||||||
|
@ -1284,7 +1262,7 @@ FFZ.prototype._build_mod_card_history = function(msg, modcard, show_from) {
|
||||||
|
|
||||||
if ( show_from ) {
|
if ( show_from ) {
|
||||||
// Badges
|
// Badges
|
||||||
out.push('<span class="badges float-left">');
|
out.push('<span class="badges">');
|
||||||
out.push(this.render_badges(this.get_line_badges(msg, false)));
|
out.push(this.render_badges(this.get_line_badges(msg, false)));
|
||||||
out.push('</span>');
|
out.push('</span>');
|
||||||
|
|
||||||
|
@ -1349,6 +1327,7 @@ FFZ.prototype._build_mod_card_history = function(msg, modcard, show_from) {
|
||||||
|
|
||||||
l_el.setAttribute('data-room', msg.room);
|
l_el.setAttribute('data-room', msg.room);
|
||||||
l_el.setAttribute('data-sender', msg.from);
|
l_el.setAttribute('data-sender', msg.from);
|
||||||
|
l_el.setAttribute('data-id', msg.tags && msg.tags.id);
|
||||||
l_el.setAttribute('data-deleted', msg.deleted || false);
|
l_el.setAttribute('data-deleted', msg.deleted || false);
|
||||||
|
|
||||||
l_el.innerHTML = out.join("");
|
l_el.innerHTML = out.join("");
|
||||||
|
|
|
@ -18,12 +18,6 @@ FFZ.settings_info.player_stats = {
|
||||||
help: "Display your current stream latency (how far behind the broadcast you are) under the player, with a few useful statistics in a tooltip.",
|
help: "Display your current stream latency (how far behind the broadcast you are) under the player, with a few useful statistics in a tooltip.",
|
||||||
|
|
||||||
on_update: function(val) {
|
on_update: function(val) {
|
||||||
for(var key in this.players) {
|
|
||||||
var player = this.players[key];
|
|
||||||
if ( player && player.player && player.player.ffzSetStatsEnabled )
|
|
||||||
player.player.ffzSetStatsEnabled(val || player.player.ffz_stats);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! this._cindex )
|
if ( ! this._cindex )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -79,36 +73,7 @@ FFZ.prototype.setup_player = function() {
|
||||||
|
|
||||||
this.players = {};
|
this.players = {};
|
||||||
|
|
||||||
var Player2 = utils.ember_resolve('component:twitch-player2');
|
this.update_views('component:twitch-player2', this.modify_twitch_player);
|
||||||
if ( ! Player2 )
|
|
||||||
return this.log("Unable to find twitch-player2 component.");
|
|
||||||
|
|
||||||
this.log("Hooking HTML5 Player UI.");
|
|
||||||
this._modify_player(Player2)
|
|
||||||
|
|
||||||
try {
|
|
||||||
Player2.create().destroy();
|
|
||||||
} catch(err) { }
|
|
||||||
|
|
||||||
// Modify all existing players.
|
|
||||||
var views = utils.ember_views();
|
|
||||||
for(var key in views) {
|
|
||||||
if ( ! views.hasOwnProperty(key) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var view = views[key];
|
|
||||||
if ( !(view instanceof Player2) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
this.log("Manually updating existing Player instance.", view);
|
|
||||||
try {
|
|
||||||
this._modify_player(view);
|
|
||||||
view.ffzInit();
|
|
||||||
|
|
||||||
} catch(err) {
|
|
||||||
this.error("Player2 setup ffzInit: " + err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -116,29 +81,22 @@ FFZ.prototype.setup_player = function() {
|
||||||
// Component
|
// Component
|
||||||
// ---------------
|
// ---------------
|
||||||
|
|
||||||
FFZ.prototype._modify_player = function(player) {
|
FFZ.prototype.modify_twitch_player = function(player) {
|
||||||
var f = this,
|
var f = this;
|
||||||
update_stats = function() {
|
utils.ember_reopen_view(player, {
|
||||||
f._cindex && f._cindex.ffzUpdatePlayerStats();
|
ffz_init: function() {
|
||||||
};
|
var id = this.get('channel.id');
|
||||||
|
f.players[id] = this;
|
||||||
|
|
||||||
player.reopen({
|
var player = this.get('player');
|
||||||
didInsertElement: function() {
|
if ( player )
|
||||||
this._super();
|
this.ffzPostPlayer();
|
||||||
try {
|
|
||||||
this.ffzInit();
|
|
||||||
} catch(err) {
|
|
||||||
f.error("Player2 didInsertElement: " + err);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
willClearRender: function() {
|
ffz_destroy: function() {
|
||||||
try {
|
var id = this.get('channel.id');
|
||||||
this.ffzTeardown();
|
if ( f.players[id] === this )
|
||||||
} catch(err) {
|
f.players[id] = undefined;
|
||||||
f.error("Player2 willClearRender: " + err);
|
|
||||||
}
|
|
||||||
this._super();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
postPlayerSetup: function() {
|
postPlayerSetup: function() {
|
||||||
|
@ -150,24 +108,21 @@ FFZ.prototype._modify_player = function(player) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzInit: function() {
|
ffzRecreatePlayer: function() {
|
||||||
var id = this.get('channel.id');
|
var player = this.get('player'),
|
||||||
f.players[id] = this;
|
theatre = player && player.getTheatre();
|
||||||
|
|
||||||
var player = this.get('player');
|
// Tell the player to destroy itself.
|
||||||
if ( player )
|
if ( player )
|
||||||
this.ffzPostPlayer();
|
player.destroy();
|
||||||
},
|
|
||||||
|
|
||||||
ffzTeardown: function() {
|
// Break down everything left over from that player.
|
||||||
var id = this.get('channel.id');
|
this.$('#video-1').html('');
|
||||||
if ( f.players[id] === this )
|
Mousetrap.unbind(['alt+x', 'alt+t', 'esc']);
|
||||||
f.players[id] = undefined;
|
this.set('player', null);
|
||||||
|
|
||||||
if ( this._ffz_stat_interval ) {
|
// Now, let Twitch create a new player as usual.
|
||||||
clearInterval(this._ffz_stat_interval);
|
Ember.run.next(this.insertPlayer.bind(this));
|
||||||
this._ffz_stat_interval = null;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzPostPlayer: function() {
|
ffzPostPlayer: function() {
|
||||||
|
@ -175,74 +130,29 @@ FFZ.prototype._modify_player = function(player) {
|
||||||
if ( ! player )
|
if ( ! player )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
// Make the stats window draggable and fix the button.
|
// Make the stats window draggable and fix the button.
|
||||||
var stats = this.$('.player .js-playback-stats');
|
var stats = this.$('.player .js-playback-stats');
|
||||||
stats.draggable({cancel: 'li', containment: 'parent'});
|
stats.draggable({cancel: 'li', containment: 'parent'});
|
||||||
|
|
||||||
|
// Add an option to the menu to recreate the player.
|
||||||
// Only set up the stats hooks if we need stats.
|
|
||||||
var has_video = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
has_video = player.getVideo();
|
|
||||||
} catch(err) {
|
|
||||||
f.error("Player2 ffzPostPlayer: getVideo: " + err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! has_video )
|
|
||||||
this.ffzInitStats();
|
|
||||||
},
|
|
||||||
|
|
||||||
ffzInitStats: function() {
|
|
||||||
if ( this.get('ffzStatsInitialized') )
|
|
||||||
return;
|
|
||||||
|
|
||||||
var t = this,
|
var t = this,
|
||||||
player = this.get('player');
|
el = this.$('.player-menu .player-menu__item--stats')[0],
|
||||||
|
container = el && el.parentElement;
|
||||||
|
|
||||||
if ( ! player )
|
if ( el && ! container.querySelector('.js-player-reset') ) {
|
||||||
return;
|
var btn_link = utils.createElement('a', 'player-text-link js-player-reset', 'Reset Player'),
|
||||||
|
btn = utils.createElement('p', 'player-menu__item player-menu__item--reset', btn_link);
|
||||||
|
|
||||||
this.set('ffzStatsInitialized', true);
|
btn_link.tabindex = '-1';
|
||||||
|
btn_link.href = '#';
|
||||||
|
|
||||||
// Make it so stats can no longer be disabled if we want them.
|
btn_link.addEventListener('click', function(e) {
|
||||||
if ( player.setStatsEnabled ) {
|
t.ffzRecreatePlayer();
|
||||||
player.ffzSetStatsEnabled = player.setStatsEnabled;
|
e.preventDefault();
|
||||||
try {
|
return false;
|
||||||
player.ffz_stats = player.getStatsEnabled();
|
});
|
||||||
} catch(err) {
|
|
||||||
// Assume stats are off.
|
|
||||||
f.log("Player2 ffzInitStats: getStatsEnabled still doesn't work.");
|
|
||||||
player.ffz_stats = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
player.setStatsEnabled = function(e, s) {
|
container.insertBefore(btn, el.nextSibling);
|
||||||
if ( s !== false )
|
|
||||||
player.ffz_stats = e;
|
|
||||||
|
|
||||||
var out = player.ffzSetStatsEnabled(e || f.settings.player_stats);
|
|
||||||
|
|
||||||
if ( ! t._ffz_player_stats_initialized ) {
|
|
||||||
t._ffz_player_stats_initialized = true;
|
|
||||||
player.addEventListener('statschange', update_stats);
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._ffz_stat_interval = setInterval(function() {
|
|
||||||
if ( f.settings.player_stats || player.ffz_stats ) {
|
|
||||||
player.ffzSetStatsEnabled(false);
|
|
||||||
player.ffzSetStatsEnabled(true);
|
|
||||||
}
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( f.settings.player_stats && ( ! player.setStatsEnabled || ! player.ffz_stats ) ) {
|
|
||||||
this._ffz_player_stats_initialized = true;
|
|
||||||
player.addEventListener('statschange', update_stats);
|
|
||||||
player.ffzSetStatsEnabled(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -50,7 +50,8 @@ FFZ.prototype.setup_room = function() {
|
||||||
|
|
||||||
if ( RC ) {
|
if ( RC ) {
|
||||||
var orig_ban = RC._actions.banUser,
|
var orig_ban = RC._actions.banUser,
|
||||||
orig_to = RC._actions.timeoutUser;
|
orig_to = RC._actions.timeoutUser,
|
||||||
|
orig_show = RC._actions.showModOverlay;
|
||||||
|
|
||||||
RC._actions.banUser = function(e) {
|
RC._actions.banUser = function(e) {
|
||||||
orig_ban.call(this, e);
|
orig_ban.call(this, e);
|
||||||
|
@ -62,12 +63,15 @@ FFZ.prototype.setup_room = function() {
|
||||||
this.get("model").clearMessages(e.user, null, true);
|
this.get("model").clearMessages(e.user, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
RC._actions.showModOverlay = function(e) {
|
|
||||||
var Channel = utils.ember_resolve('model:channel');
|
|
||||||
if ( ! Channel )
|
|
||||||
return;
|
|
||||||
|
|
||||||
var chan = Channel.find({id: e.sender});
|
RC._actions.showModOverlay = function(e) {
|
||||||
|
var Channel = utils.ember_resolve('model:deprecated-channel'),
|
||||||
|
chan = Channel && Channel.find && Channel.find({id: e.sender});
|
||||||
|
|
||||||
|
if ( ! chan ) {
|
||||||
|
f.log("Error opening mod card. model:deprecated-channel does not exist or does not have find!");
|
||||||
|
return orig_show.call(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
// Don't try loading the channel if it's already loaded. Don't make mod cards
|
// Don't try loading the channel if it's already loaded. Don't make mod cards
|
||||||
// refresh the channel page when you click the broadcaster, basically.
|
// refresh the channel page when you click the broadcaster, basically.
|
||||||
|
@ -111,33 +115,7 @@ FFZ.prototype.setup_room = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.log("Hooking the Ember Room view.");
|
this.log("Hooking the Ember Room view.");
|
||||||
|
this.update_views('view:room', this.modify_room_view);
|
||||||
var RoomView = utils.ember_resolve('view:room');
|
|
||||||
this._modify_rview(RoomView);
|
|
||||||
|
|
||||||
// For some reason, this doesn't work unless we create an instance of the
|
|
||||||
// room view and then destroy it immediately.
|
|
||||||
try {
|
|
||||||
RoomView.create().destroy();
|
|
||||||
} catch(err) { }
|
|
||||||
|
|
||||||
// Modify all existing Room views.
|
|
||||||
var views = utils.ember_views();
|
|
||||||
for(var key in views) {
|
|
||||||
if ( ! views.hasOwnProperty(key) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var view = views[key];
|
|
||||||
if ( !(view instanceof RoomView) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
this.log("Manually updating existing Room view.", view);
|
|
||||||
try {
|
|
||||||
view.ffzInit();
|
|
||||||
} catch(err) {
|
|
||||||
this.error("RoomView setup ffzInit: " + err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -145,29 +123,10 @@ FFZ.prototype.setup_room = function() {
|
||||||
// View Customization
|
// View Customization
|
||||||
// --------------------
|
// --------------------
|
||||||
|
|
||||||
FFZ.prototype._modify_rview = function(view) {
|
FFZ.prototype.modify_room_view = function(view) {
|
||||||
var f = this;
|
var f = this;
|
||||||
view.reopen({
|
utils.ember_reopen_view(view, {
|
||||||
didInsertElement: function() {
|
ffz_init: function() {
|
||||||
this._super();
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.ffzInit();
|
|
||||||
} catch(err) {
|
|
||||||
f.error("RoomView didInsertElement: " + err);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
willClearRender: function() {
|
|
||||||
try {
|
|
||||||
this.ffzTeardown();
|
|
||||||
} catch(err) {
|
|
||||||
f.error("RoomView willClearRender: " + err);
|
|
||||||
}
|
|
||||||
this._super();
|
|
||||||
},
|
|
||||||
|
|
||||||
ffzInit: function() {
|
|
||||||
f._roomv = this;
|
f._roomv = this;
|
||||||
|
|
||||||
this.ffz_frozen = false;
|
this.ffz_frozen = false;
|
||||||
|
@ -196,6 +155,34 @@ FFZ.prototype._modify_rview = function(view) {
|
||||||
var controller = this.get('controller');
|
var controller = this.get('controller');
|
||||||
if ( controller ) {
|
if ( controller ) {
|
||||||
controller.reopen({
|
controller.reopen({
|
||||||
|
calcRecipientEligibility: function(e) {
|
||||||
|
// Because this doesn't work properly with multiple channel rooms
|
||||||
|
// by default, do it ourselves.
|
||||||
|
var id = controller.get('model.roomProperties._id'),
|
||||||
|
update = function(data) {
|
||||||
|
if ( controller.isDestroyed || controller.get('model.roomProperties._id') !== id )
|
||||||
|
return;
|
||||||
|
|
||||||
|
controller.set('model._ffz_bits_eligibility', data);
|
||||||
|
controller.set('isRecipientBitsIneligible', ! data.eligible);
|
||||||
|
controller.set('isBitsHelperShown', data.eligible);
|
||||||
|
controller.set('minimumBits', data.minBits);
|
||||||
|
|
||||||
|
if ( ! data.eligible )
|
||||||
|
controller.set('isBitsTooltipActive', false);
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( id === undefined )
|
||||||
|
return;
|
||||||
|
|
||||||
|
var data = controller.get('model._ffz_bits_eligibility');
|
||||||
|
if ( data === undefined )
|
||||||
|
controller.get('bits').loadRecipientEligibility(id).then(update);
|
||||||
|
else
|
||||||
|
update(data);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
submitButtonText: function() {
|
submitButtonText: function() {
|
||||||
if ( this.get("model.isWhisperMessage") && this.get("model.isWhispersEnabled") )
|
if ( this.get("model.isWhisperMessage") && this.get("model.isWhispersEnabled") )
|
||||||
return i18n("Whisper");
|
return i18n("Whisper");
|
||||||
|
@ -214,7 +201,7 @@ FFZ.prototype._modify_rview = function(view) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzTeardown: function() {
|
ffz_destroy: function() {
|
||||||
if ( f._roomv === this )
|
if ( f._roomv === this )
|
||||||
f._roomv = undefined;
|
f._roomv = undefined;
|
||||||
|
|
||||||
|
@ -280,7 +267,7 @@ FFZ.prototype._modify_rview = function(view) {
|
||||||
btn.classList.toggle('ffz-banned', (room && room.get('ffz_banned') || false));
|
btn.classList.toggle('ffz-banned', (room && room.get('ffz_banned') || false));
|
||||||
}
|
}
|
||||||
|
|
||||||
var badge, id, info, vis_count = 0;
|
var badge, id, info, vis_count = 0, label;
|
||||||
for(var i=0; i < STATUS_BADGES.length; i++) {
|
for(var i=0; i < STATUS_BADGES.length; i++) {
|
||||||
info = STATUS_BADGES[i];
|
info = STATUS_BADGES[i];
|
||||||
id = 'ffz-stat-' + info[0];
|
id = 'ffz-stat-' + info[0];
|
||||||
|
@ -289,13 +276,18 @@ FFZ.prototype._modify_rview = function(view) {
|
||||||
if ( typeof visible === "string" )
|
if ( typeof visible === "string" )
|
||||||
visible = visible === "1";
|
visible = visible === "1";
|
||||||
|
|
||||||
|
label = typeof info[3] === "function" ? info[3].call(f, room) : undefined;
|
||||||
|
|
||||||
if ( ! badge ) {
|
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 = utils.createElement('span', 'ffz room-state stat float-right', (label || info[0]).charAt(0).toUpperCase() + '<span>' + (label || info[0]).substr(1).toUpperCase() + '</span>');
|
||||||
badge.id = id;
|
badge.id = id;
|
||||||
jQuery(badge).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'se')});
|
jQuery(badge).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'se')});
|
||||||
cont.appendChild(badge);
|
cont.appendChild(badge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( label )
|
||||||
|
badge.innerHTML = (label || info[0]).charAt(0).toUpperCase() + '<span>' + (label || info[0]).substr(1).toUpperCase() + '</span>';
|
||||||
|
|
||||||
badge.title = typeof info[2] === "function" ? info[2].call(f, room) : info[2];
|
badge.title = typeof info[2] === "function" ? info[2].call(f, room) : info[2];
|
||||||
badge.classList.toggle('hidden', ! visible);
|
badge.classList.toggle('hidden', ! visible);
|
||||||
if ( visible )
|
if ( visible )
|
||||||
|
@ -494,7 +486,6 @@ FFZ.prototype._modify_rview = function(view) {
|
||||||
warning.classList.remove('hidden');
|
warning.classList.remove('hidden');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
ffzUnwarnPaused: function() {
|
ffzUnwarnPaused: function() {
|
||||||
var el = this.get('element'),
|
var el = this.get('element'),
|
||||||
warning = el && el.querySelector('.chat-interface .more-messages-indicator.ffz-freeze-indicator');
|
warning = el && el.querySelector('.chat-interface .more-messages-indicator.ffz-freeze-indicator');
|
||||||
|
@ -502,7 +493,6 @@ FFZ.prototype._modify_rview = function(view) {
|
||||||
if ( warning )
|
if ( warning )
|
||||||
warning.classList.add('hidden');
|
warning.classList.add('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,12 +630,13 @@ FFZ.ffz_commands.help.help = "Usage: /ffz help [command]\nList available command
|
||||||
|
|
||||||
FFZ.prototype.update_room_important = function(id, controller) {
|
FFZ.prototype.update_room_important = function(id, controller) {
|
||||||
var Chat = controller || utils.ember_lookup('controller:chat'),
|
var Chat = controller || utils.ember_lookup('controller:chat'),
|
||||||
|
current_room = Chat && Chat.get('currentChannelRoom'),
|
||||||
room = this.rooms[id];
|
room = this.rooms[id];
|
||||||
|
|
||||||
if ( ! room )
|
if ( ! room )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
room.important = (Chat && room.room && Chat.get('currentChannelRoom') === room.room) || (room.room && room.room.get('isGroupRoom')) || (this.settings.pinned_rooms.indexOf(id) !== -1);
|
room.important = (room.room && current_room === room.room) || (current_room && current_room.ffz_host_target === id) || (room.room && room.room.get('isGroupRoom')) || (this.settings.pinned_rooms.indexOf(id) !== -1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -798,7 +789,7 @@ FFZ.prototype._insert_history = function(room_id, data, from_server) {
|
||||||
before = first_existing.date && first_existing.date.getTime();
|
before = first_existing.date && first_existing.date.getTime();
|
||||||
|
|
||||||
|
|
||||||
this.parse_history(data, null, room_id, delete_links, tmiSession, function(msg) {
|
this.parse_history(data, null, null, room_id, delete_links, tmiSession, function(msg) {
|
||||||
if ( from_server )
|
if ( from_server )
|
||||||
msg.from_server = true;
|
msg.from_server = true;
|
||||||
|
|
||||||
|
@ -815,7 +806,7 @@ FFZ.prototype._insert_history = function(room_id, data, from_server) {
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Display the Ban Reason if we're a moderator or that user.
|
// Display the Ban Reason if we're a moderator or that user.
|
||||||
if ( msg.tags['ban-reason'] && is_mine || r.get('isModeratorOrHigher') ) {
|
if ( msg.tags['ban-reason'] && (is_mine || r.get('isModeratorOrHigher')) ) {
|
||||||
msg.message = msg.message.substr(0, msg.message.length - 1) + ' with reason: ' + msg.tags['ban-reason'];
|
msg.message = msg.message.substr(0, msg.message.length - 1) + ' with reason: ' + msg.tags['ban-reason'];
|
||||||
msg.cachedTokens = [utils.sanitize(msg.message)];
|
msg.cachedTokens = [utils.sanitize(msg.message)];
|
||||||
}
|
}
|
||||||
|
@ -834,6 +825,12 @@ FFZ.prototype._insert_history = function(room_id, data, from_server) {
|
||||||
if ( ! first_inserted )
|
if ( ! first_inserted )
|
||||||
first_inserted = msg;
|
first_inserted = msg;
|
||||||
|
|
||||||
|
// Store the message ID for this message, of course.
|
||||||
|
var msg_id = msg.tags && msg.tags.id,
|
||||||
|
ids = r.ffz_ids = r.ffz_ids || {};
|
||||||
|
if ( msg_id && ! ids[msg_id] )
|
||||||
|
ids[msg_id] = msg;
|
||||||
|
|
||||||
messages.unshiftObject(msg);
|
messages.unshiftObject(msg);
|
||||||
inserted += 1;
|
inserted += 1;
|
||||||
|
|
||||||
|
@ -870,6 +867,11 @@ FFZ.prototype._insert_history = function(room_id, data, from_server) {
|
||||||
if ( r.shouldShowMessage(msg) ) {
|
if ( r.shouldShowMessage(msg) ) {
|
||||||
messages.insertAt(inserted, msg);
|
messages.insertAt(inserted, msg);
|
||||||
while ( messages.length > buffer_size ) {
|
while ( messages.length > buffer_size ) {
|
||||||
|
// Remove this message from the ID tracker.
|
||||||
|
var m = messages.get(0);
|
||||||
|
if ( m.tags && m.tags.id && r.ffz_ids && r.ffz_ids[m.tags.id] )
|
||||||
|
delete r.ffz_ids[m.tags.id];
|
||||||
|
|
||||||
messages.removeAt(0);
|
messages.removeAt(0);
|
||||||
removed++;
|
removed++;
|
||||||
}
|
}
|
||||||
|
@ -1042,6 +1044,7 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
try {
|
try {
|
||||||
f.add_room(this.id, this);
|
f.add_room(this.id, this);
|
||||||
this.set("ffz_chatters", {});
|
this.set("ffz_chatters", {});
|
||||||
|
this.set("ffz_ids", this.get('ffz_ids') || {});
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
f.error("add_room: " + err);
|
f.error("add_room: " + err);
|
||||||
}
|
}
|
||||||
|
@ -1063,6 +1066,7 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
if ( user ) {
|
if ( user ) {
|
||||||
var duration = Infinity,
|
var duration = Infinity,
|
||||||
reason = undefined,
|
reason = undefined,
|
||||||
|
msg_id = undefined,
|
||||||
current_user = f.get_user(),
|
current_user = f.get_user(),
|
||||||
is_me = current_user && current_user.login === user;
|
is_me = current_user && current_user.login === user;
|
||||||
|
|
||||||
|
@ -1077,6 +1081,18 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
reason = tags['ban-reason'];
|
reason = tags['ban-reason'];
|
||||||
|
|
||||||
|
|
||||||
|
// Is there a UUID on the end of the ban reason?
|
||||||
|
if ( reason ) {
|
||||||
|
var match = constants.UUID_TEST.exec(reason);
|
||||||
|
if ( match ) {
|
||||||
|
msg_id = match[1];
|
||||||
|
reason = reason.substr(0, reason.length - match[0].length);
|
||||||
|
if ( ! reason.length )
|
||||||
|
reason = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// If we were banned, set the state and update the UI.
|
// If we were banned, set the state and update the UI.
|
||||||
if ( is_me ) {
|
if ( is_me ) {
|
||||||
t.set('ffz_banned', true);
|
t.set('ffz_banned', true);
|
||||||
|
@ -1098,6 +1114,44 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
t.ffzRecentlyBanned.shift();
|
t.ffzRecentlyBanned.shift();
|
||||||
|
|
||||||
|
|
||||||
|
// Are we deleting a specific message?
|
||||||
|
if ( msg_id && this.ffz_ids ) {
|
||||||
|
var msg = this.ffz_ids[msg_id];
|
||||||
|
if ( msg && msg.from === user ) {
|
||||||
|
msg.ffz_deleted = true;
|
||||||
|
if ( ! f.settings.prevent_clear )
|
||||||
|
msg.deleted = true;
|
||||||
|
|
||||||
|
if ( f.settings.remove_deleted )
|
||||||
|
if ( msg.pending )
|
||||||
|
msg.removed = true;
|
||||||
|
else {
|
||||||
|
var msgs = t.get('messages'),
|
||||||
|
total = msgs.get('length'),
|
||||||
|
i = total;
|
||||||
|
|
||||||
|
while(i--) {
|
||||||
|
var msg = msgs.get(i);
|
||||||
|
if ( msg.tags && msg.tags.id === msg_id ) {
|
||||||
|
msgs.removeAt(i);
|
||||||
|
delete this.ffz_ids[msg_id];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( msg._line ) {
|
||||||
|
Ember.propertyDidChange(msg._line, 'msgObject.ffz_deleted');
|
||||||
|
Ember.propertyDidChange(msg._line, 'msgObject.deleted');
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ( msg.from !== user )
|
||||||
|
f.log("Banned Message ID #" + msg_id + " not owned by: " + user);
|
||||||
|
else
|
||||||
|
f.log("Banned Message ID #" + msg_id + " not found in chat.");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Delete all messages from this user / chat.
|
||||||
// Delete Visible Messages
|
// Delete Visible Messages
|
||||||
var msgs = t.get('messages'),
|
var msgs = t.get('messages'),
|
||||||
total = msgs.get('length'),
|
total = msgs.get('length'),
|
||||||
|
@ -1106,9 +1160,12 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
|
|
||||||
while(i--) {
|
while(i--) {
|
||||||
var msg = msgs.get(i);
|
var msg = msgs.get(i);
|
||||||
|
|
||||||
if ( msg.from === user ) {
|
if ( msg.from === user ) {
|
||||||
if ( f.settings.remove_deleted ) {
|
if ( f.settings.remove_deleted ) {
|
||||||
|
// Remove this message from the ID tracker.
|
||||||
|
if ( msg.tags && msg.tags.id && this.ffz_ids && this.ffz_ids[msg.tags.id] )
|
||||||
|
delete this.ffz_ids[msg.tags.id];
|
||||||
|
|
||||||
msgs.removeAt(i);
|
msgs.removeAt(i);
|
||||||
removed++;
|
removed++;
|
||||||
continue;
|
continue;
|
||||||
|
@ -1133,6 +1190,7 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
msg.removed = f.settings.remove_deleted;
|
msg.removed = f.settings.remove_deleted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Now we need to see about displaying a ban notice.
|
// Now we need to see about displaying a ban notice.
|
||||||
|
@ -1164,6 +1222,7 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
date: now,
|
date: now,
|
||||||
ffz_ban_target: user,
|
ffz_ban_target: user,
|
||||||
reasons: reason ? [reason] : [],
|
reasons: reason ? [reason] : [],
|
||||||
|
msg_ids: msg_id ? [msg_id] : [],
|
||||||
durations: [duration],
|
durations: [duration],
|
||||||
end_time: end_time,
|
end_time: end_time,
|
||||||
timeouts: 1,
|
timeouts: 1,
|
||||||
|
@ -1176,6 +1235,9 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
this.addMessage(msg);
|
this.addMessage(msg);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
if ( msg_id && last_ban.msg_ids.indexOf(msg_id) === -1 )
|
||||||
|
last_ban.msg_ids.push(msg_id);
|
||||||
|
|
||||||
if ( reason && last_ban.reasons.indexOf(reason) === -1 )
|
if ( reason && last_ban.reasons.indexOf(reason) === -1 )
|
||||||
last_ban.reasons.push(reason);
|
last_ban.reasons.push(reason);
|
||||||
|
|
||||||
|
@ -1205,6 +1267,9 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
last_ban = null;
|
last_ban = null;
|
||||||
|
|
||||||
if ( last_ban ) {
|
if ( last_ban ) {
|
||||||
|
if ( msg_id && last_ban.msg_ids.indexOf(msg_id) === -1 )
|
||||||
|
last_ban.msg_ids.push(msg_id);
|
||||||
|
|
||||||
if ( reason && last_ban.reasons.indexOf(reason) === -1 )
|
if ( reason && last_ban.reasons.indexOf(reason) === -1 )
|
||||||
last_ban.reasons.push(reason);
|
last_ban.reasons.push(reason);
|
||||||
|
|
||||||
|
@ -1223,6 +1288,7 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
date: now,
|
date: now,
|
||||||
ffz_ban_target: user,
|
ffz_ban_target: user,
|
||||||
reasons: reason ? [reason] : [],
|
reasons: reason ? [reason] : [],
|
||||||
|
msg_ids: msg_id ? [msg_id] : [],
|
||||||
durations: [duration],
|
durations: [duration],
|
||||||
end_time: end_time,
|
end_time: end_time,
|
||||||
timeouts: 1,
|
timeouts: 1,
|
||||||
|
@ -1256,8 +1322,17 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
len = messages.get("length"),
|
len = messages.get("length"),
|
||||||
limit = this.get("messageBufferSize");
|
limit = this.get("messageBufferSize");
|
||||||
|
|
||||||
if ( len > limit )
|
if ( len > limit ) {
|
||||||
messages.removeAt(0, len - limit);
|
var to_remove = len - limit;
|
||||||
|
for(var i = 0; i < to_remove; i++) {
|
||||||
|
// Remove this message from the ID tracker.
|
||||||
|
var msg = messages.get(i);
|
||||||
|
if ( msg.tags && msg.tags.id && this.ffz_ids && this.ffz_ids[msg.tags.id] )
|
||||||
|
delete this.ffz_ids[msg.tags.id];
|
||||||
|
}
|
||||||
|
|
||||||
|
messages.removeAt(0, to_remove);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Artificial chat delay
|
// Artificial chat delay
|
||||||
|
@ -1267,6 +1342,7 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
this.ffzPending = [];
|
this.ffzPending = [];
|
||||||
|
|
||||||
var now = msg.time = Date.now();
|
var now = msg.time = Date.now();
|
||||||
|
msg.pending = true;
|
||||||
this.ffzPending.push(msg);
|
this.ffzPending.push(msg);
|
||||||
this.ffzSchedulePendingFlush(now);
|
this.ffzSchedulePendingFlush(now);
|
||||||
|
|
||||||
|
@ -1320,12 +1396,18 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
|
|
||||||
for (var i = 0, l = this.ffzPending.length; i < l; i++) {
|
for (var i = 0, l = this.ffzPending.length; i < l; i++) {
|
||||||
var msg = this.ffzPending[i];
|
var msg = this.ffzPending[i];
|
||||||
if ( msg.removed )
|
if ( msg.removed ) {
|
||||||
|
// Don't keep this message ID around.
|
||||||
|
var msg_id = msg && msg.tags && msg.tags.id;
|
||||||
|
if ( msg_id && this.ffz_ids && this.ffz_ids[msg_id] )
|
||||||
|
delete this.ffz_ids[msg_id];
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if ( f.settings.chat_delay !== 0 && (f.settings.chat_delay + msg.time > now) )
|
if ( f.settings.chat_delay !== 0 && (f.settings.chat_delay + msg.time > now) )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
msg.pending = false;
|
||||||
this.ffzActualPushMessage(msg);
|
this.ffzActualPushMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1367,10 +1449,16 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onMessage: function(msg) {
|
||||||
|
// We do our own batching. With blackjack, and hookers. You know what? Forget the batching.
|
||||||
|
this.addMessage(msg);
|
||||||
|
},
|
||||||
|
|
||||||
addMessage: function(msg) {
|
addMessage: function(msg) {
|
||||||
if ( msg ) {
|
if ( msg ) {
|
||||||
var is_resub = msg.tags && msg.tags['msg-id'] === 'resub',
|
var is_resub = msg.tags && msg.tags['msg-id'] === 'resub',
|
||||||
room_id = this.get('id');
|
room_id = this.get('id'),
|
||||||
|
msg_id = msg.tags && msg.tags.id;
|
||||||
|
|
||||||
// Ignore resubs in other rooms.
|
// Ignore resubs in other rooms.
|
||||||
if ( is_resub && ! f.settings.hosted_sub_notices && (msg.tags['room-id'] != this.get('roomProperties._id') || HOSTED_SUB.test(msg.tags['system-msg'])) )
|
if ( is_resub && ! f.settings.hosted_sub_notices && (msg.tags['room-id'] != this.get('roomProperties._id') || HOSTED_SUB.test(msg.tags['system-msg'])) )
|
||||||
|
@ -1515,6 +1603,13 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
if ( f._chat_filters[i](msg) === false )
|
if ( f._chat_filters[i](msg) === false )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// We're past the last return, so store the message
|
||||||
|
// now that we know we're keeping it.
|
||||||
|
if ( msg_id ) {
|
||||||
|
var ids = this.ffz_ids = this.ffz_ids || {};
|
||||||
|
ids[msg_id] = msg;
|
||||||
|
}
|
||||||
|
|
||||||
// Report this message to the dashboard.
|
// Report this message to the dashboard.
|
||||||
if ( window !== window.parent && parent.postMessage && msg.from && msg.from !== "jtv" && msg.from !== "twitchnotify" )
|
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/");
|
parent.postMessage({from_ffz: true, command: 'chat_message', data: {from: msg.from, room: msg.room}}, "*"); //location.protocol + "//www.twitch.tv/");
|
||||||
|
|
|
@ -12,16 +12,10 @@ var FFZ = window.FrankerFaceZ,
|
||||||
// ---------------------
|
// ---------------------
|
||||||
|
|
||||||
FFZ.prototype.setup_vod_chat = function() {
|
FFZ.prototype.setup_vod_chat = function() {
|
||||||
var f = this,
|
|
||||||
VRC = utils.ember_resolve('component:vod-right-column');
|
|
||||||
|
|
||||||
if ( VRC )
|
|
||||||
this._modify_vod_right_column(VRC);
|
|
||||||
else
|
|
||||||
f.error("Unable to locate VOD Right Column component.");
|
|
||||||
|
|
||||||
// Get the VOD Chat Service
|
// Get the VOD Chat Service
|
||||||
var VODService = utils.ember_lookup('service:vod-chat-service');
|
var f = this,
|
||||||
|
VODService = utils.ember_lookup('service:vod-chat-service');
|
||||||
|
|
||||||
if ( VODService )
|
if ( VODService )
|
||||||
VODService.reopen({
|
VODService.reopen({
|
||||||
messageBufferSize: f.settings.scrollback_length,
|
messageBufferSize: f.settings.scrollback_length,
|
||||||
|
@ -50,56 +44,59 @@ FFZ.prototype.setup_vod_chat = function() {
|
||||||
else
|
else
|
||||||
f.error("Unable to locate VOD Chat Service.");
|
f.error("Unable to locate VOD Chat Service.");
|
||||||
|
|
||||||
// Get the VOD Chat Display
|
this.update_views('component:vod-right-column', this.modify_vod_right_column);
|
||||||
var VODChat = utils.ember_resolve('component:vod-chat-display');
|
this.update_views('view:vod', this.modify_vod_view);
|
||||||
|
this.update_views('component:vod-chat-display', this.modify_vod_chat_display);
|
||||||
if ( VODChat )
|
|
||||||
this._modify_vod_chat_display(VODChat);
|
|
||||||
else
|
|
||||||
f.error("Unable to locate VOD Chat Display component.");
|
|
||||||
|
|
||||||
// Modify all existing VOD Chat views.
|
|
||||||
var views = utils.ember_views();
|
|
||||||
for(var key in views) {
|
|
||||||
var view = views[key];
|
|
||||||
|
|
||||||
if ( VRC && view instanceof VRC ) {
|
|
||||||
this.log("Manually updating existing VOD Right Column.");
|
|
||||||
try {
|
|
||||||
this._modify_vod_right_column(view);
|
|
||||||
view.ffzInit();
|
|
||||||
//Ember.propertyDidChange(view, 'canSeeDarkLaunch');
|
|
||||||
} catch(err) {
|
|
||||||
this.error("setup: setup_vod_chat: " + err);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if ( VODChat && view instanceof VODChat ) {
|
|
||||||
this.log("Manually updating existing VOD Chat view.", view);
|
|
||||||
try {
|
|
||||||
this._modify_vod_chat_display(view);
|
|
||||||
view.ffzInit();
|
|
||||||
} catch(err) {
|
|
||||||
this.error("setup: setup_vod_chat: " + err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype._modify_vod_right_column = function(component) {
|
FFZ.prototype.modify_vod_view = function(view) {
|
||||||
var f = this;
|
var f = this;
|
||||||
|
utils.ember_reopen_view(view, {
|
||||||
|
ffz_init: function() {
|
||||||
|
f._vodv = this;
|
||||||
|
|
||||||
component.reopen({
|
var channel_id = this.get('context.channel.name');
|
||||||
didInsertElement: function() {
|
|
||||||
this._super();
|
if ( f.settings.auto_theater ) {
|
||||||
try {
|
var player = f.players && f.players[channel_id] && f.players[channel_id].get('player');
|
||||||
this.ffzInit();
|
if ( player )
|
||||||
} catch(err) {
|
player.setTheatre(true);
|
||||||
f.error("VODRightColumn didInsertElement: " + err);
|
}
|
||||||
|
|
||||||
|
// Listen to scrolling.
|
||||||
|
this._ffz_scroller = this.ffzOnScroll.bind(this);
|
||||||
|
jQuery(this.get('element')).parents('.tse-scroll-content').on('scroll', this._ffz_scroller);
|
||||||
|
},
|
||||||
|
|
||||||
|
ffz_destroy: function() {
|
||||||
|
if ( f._vodv === this )
|
||||||
|
f._vodv = null;
|
||||||
|
|
||||||
|
if ( this._ffz_scroller ) {
|
||||||
|
jQuery(this.get('element')).parents('.tse-scroll-content').off('scroll', this._ffz_scroller);
|
||||||
|
this._ffz_scroller = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzInit: function() {
|
ffzOnScroll: function(event) {
|
||||||
|
// When we scroll past the bottom of the player, do stuff!
|
||||||
|
var top = event && event.target && event.target.scrollTop,
|
||||||
|
height = this.get('layout.playerSize.1');
|
||||||
|
|
||||||
|
if ( ! top )
|
||||||
|
top = jQuery(this.get('element')).parents('.tse-scroll-content').scrollTop();
|
||||||
|
|
||||||
|
document.body.classList.toggle('ffz-small-player', f.settings.small_player && top >= height);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.prototype.modify_vod_right_column = function(component) {
|
||||||
|
var f = this;
|
||||||
|
utils.ember_reopen_view(component, {
|
||||||
|
ffz_init: function() {
|
||||||
if ( f.settings.dark_twitch ) {
|
if ( f.settings.dark_twitch ) {
|
||||||
var el = this.get('element'),
|
var el = this.get('element'),
|
||||||
cont = el && el.querySelector('.chat-container');
|
cont = el && el.querySelector('.chat-container');
|
||||||
|
@ -112,29 +109,11 @@ FFZ.prototype._modify_vod_right_column = function(component) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype._modify_vod_chat_display = function(component) {
|
FFZ.prototype.modify_vod_chat_display = function(component) {
|
||||||
var f = this,
|
var f = this,
|
||||||
VODService = utils.ember_lookup('service:vod-chat-service');
|
VODService = utils.ember_lookup('service:vod-chat-service');
|
||||||
|
|
||||||
component.reopen({
|
utils.ember_reopen_view(component, {
|
||||||
didInsertElement: function() {
|
|
||||||
this._super();
|
|
||||||
try {
|
|
||||||
this.ffzInit();
|
|
||||||
} catch(err) {
|
|
||||||
f.error("VODChat didInsertElement: " + err);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
willClearRender: function() {
|
|
||||||
try {
|
|
||||||
this.ffzTeardown();
|
|
||||||
} catch(err) {
|
|
||||||
f.error("VODChat willClearRender: " + err);
|
|
||||||
}
|
|
||||||
this._super();
|
|
||||||
},
|
|
||||||
|
|
||||||
_prepareToolTips: function() {
|
_prepareToolTips: function() {
|
||||||
this.$(".tooltip").tipsy({
|
this.$(".tooltip").tipsy({
|
||||||
live: true,
|
live: true,
|
||||||
|
@ -142,7 +121,7 @@ FFZ.prototype._modify_vod_chat_display = function(component) {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzInit: function() {
|
ffz_init: function() {
|
||||||
f._vodc = this;
|
f._vodc = this;
|
||||||
|
|
||||||
// Load the room, if necessary
|
// Load the room, if necessary
|
||||||
|
@ -153,22 +132,9 @@ FFZ.prototype._modify_vod_chat_display = function(component) {
|
||||||
this.ffz_frozen = false;
|
this.ffz_frozen = false;
|
||||||
if ( f.settings.chat_hover_pause )
|
if ( f.settings.chat_hover_pause )
|
||||||
this.ffzEnableFreeze();
|
this.ffzEnableFreeze();
|
||||||
|
|
||||||
/*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'
|
|
||||||
})});
|
|
||||||
|
|
||||||
this.$('.chat-messages').find('.ffz-tooltip').tipsy({
|
|
||||||
live: true, html: true,
|
|
||||||
title: f.render_tooltip(),
|
|
||||||
gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, function() {
|
|
||||||
return this.classList.contains('right') ? 'e' : 'n'
|
|
||||||
})});*/
|
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzTeardown: function() {
|
ffz_destroy: function() {
|
||||||
if ( f._vodc === this )
|
if ( f._vodc === this )
|
||||||
f._vodc = undefined;
|
f._vodc = undefined;
|
||||||
|
|
||||||
|
@ -232,14 +198,6 @@ FFZ.prototype._modify_vod_chat_display = function(component) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/*ffzMouseDown: function(event) {
|
|
||||||
var scroller = this.get('chatMessagesScroller');
|
|
||||||
if ( scroller && scroller[0] && ((!this.ffz_frozen && "mousedown" === event.type) || "mousewheel" === event.type || (is_android && "scroll" === event.type) ) ) {
|
|
||||||
var r = scroller[0].scrollHeight - scroller[0].scrollTop - scroller[0].offsetHeight;
|
|
||||||
this._setStuckToBottom(10 >= r);
|
|
||||||
}
|
|
||||||
},*/
|
|
||||||
|
|
||||||
ffzMouseOut: function(event) {
|
ffzMouseOut: function(event) {
|
||||||
this._ffz_outside = true;
|
this._ffz_outside = true;
|
||||||
var e = this;
|
var e = this;
|
||||||
|
|
88
src/ember/wrapper.js
Normal file
88
src/ember/wrapper.js
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
var FFZ = window.FrankerFaceZ,
|
||||||
|
utils = require("../utils"),
|
||||||
|
constants = require("../constants");
|
||||||
|
|
||||||
|
// --------------------
|
||||||
|
// Initialization
|
||||||
|
// --------------------
|
||||||
|
|
||||||
|
FFZ.prototype.setup_ember_wrapper = function() {
|
||||||
|
this._views_to_update = [];
|
||||||
|
this._ember_finalized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.prototype.update_views = function(klass, modifier, if_not_exists) {
|
||||||
|
var original_klass;
|
||||||
|
if ( typeof klass === 'string' ) {
|
||||||
|
original_klass = klass;
|
||||||
|
klass = utils.ember_resolve(klass);
|
||||||
|
if ( ! klass && if_not_exists ) {
|
||||||
|
if ( typeof if_not_exists === "function" )
|
||||||
|
if_not_exists.call(this, klass, modifier);
|
||||||
|
else {
|
||||||
|
klass = Ember.Component.extend({});
|
||||||
|
App.__registry__.register(original_klass, klass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! klass ) {
|
||||||
|
this.error("Unable to locate the Ember " + original_klass);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
original_klass = klass.toString();
|
||||||
|
|
||||||
|
if ( this._ember_finalized )
|
||||||
|
this._update_views([[original_klass, klass, modifier]]);
|
||||||
|
else
|
||||||
|
this._views_to_update.push([original_klass, klass, modifier]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.prototype.finalize_ember_wrapper = function() {
|
||||||
|
this._ember_finalized = true;
|
||||||
|
var views = this._views_to_update;
|
||||||
|
this._views_to_update = null;
|
||||||
|
this._update_views(views);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.prototype._update_views = function(klasses) {
|
||||||
|
this.log("Updating Ember classes and instances.", klasses);
|
||||||
|
// Modify all pending classes and clear them from cache.
|
||||||
|
for(var i=0; i < klasses.length; i++) {
|
||||||
|
klasses[i][2].call(this, klasses[i][1]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
klasses[i][1].create().destroy()
|
||||||
|
} catch(err) {
|
||||||
|
this.log("There was an error creating and destroying an instance of the Ember class \"" + klasses[i][0] + "\" to clear its cache.", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over all existing views and update them as necessary.
|
||||||
|
var views = utils.ember_views();
|
||||||
|
for(var view_id in views) {
|
||||||
|
var view = views[view_id];
|
||||||
|
if ( ! view )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for(var i=0; i < klasses.length; i++)
|
||||||
|
if ( view instanceof klasses[i][1] ) {
|
||||||
|
try {
|
||||||
|
if ( ! view.ffz_modified )
|
||||||
|
klasses[i][2].call(this, view);
|
||||||
|
|
||||||
|
(view.ffz_update || view.ffz_init).call(view);
|
||||||
|
|
||||||
|
} catch(err) {
|
||||||
|
this.error("An error occured when updating an existing Ember instance of: " + klasses[i][0], err);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
var FFZ = window.FrankerFaceZ,
|
var FFZ = window.FrankerFaceZ,
|
||||||
utils = require('../utils'),
|
utils = require('../utils'),
|
||||||
|
|
||||||
|
|
||||||
build_css = function(emote) {
|
build_css = function(emote) {
|
||||||
if ( ! emote.margins && ! emote.css )
|
if ( ! emote.margins && ! emote.css )
|
||||||
return "";
|
return "";
|
||||||
|
@ -50,11 +49,15 @@ var API = FFZ.API = function(instance, name, icon, version) {
|
||||||
this.global_sets = [];
|
this.global_sets = [];
|
||||||
this.default_sets = [];
|
this.default_sets = [];
|
||||||
|
|
||||||
|
this.badges = {};
|
||||||
|
|
||||||
this.users = {};
|
this.users = {};
|
||||||
this.chat_filters = [];
|
this.chat_filters = [];
|
||||||
this.on_room_callbacks = [];
|
this.on_room_callbacks = [];
|
||||||
|
|
||||||
this.name = name || ("Extension#" + this.id);
|
this.name = name || ("Extension#" + this.id);
|
||||||
|
this.name_key = this.name.replace(/[^A-Z0-9_\-]/g, '').toLowerCase();
|
||||||
|
|
||||||
this.icon = icon || null;
|
this.icon = icon || null;
|
||||||
this.version = version || null;
|
this.version = version || null;
|
||||||
|
|
||||||
|
@ -386,13 +389,75 @@ API.prototype.unregister_room_set = function(room_id, id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------
|
||||||
|
// Badge APIs
|
||||||
|
// -----------------------
|
||||||
|
|
||||||
|
API.prototype.add_badge = function(badge_id, badge) {
|
||||||
|
var exact_id = this.id + '-' + badge_id,
|
||||||
|
|
||||||
|
real_badge = {
|
||||||
|
id: exact_id,
|
||||||
|
source_ext: this.id,
|
||||||
|
source_id: badge_id,
|
||||||
|
alpha_image: badge.alpha_image,
|
||||||
|
color: badge.color || "transparent",
|
||||||
|
no_invert: badge.no_invert,
|
||||||
|
invert_invert: badge.invert_invert,
|
||||||
|
css: badge.css,
|
||||||
|
image: badge.image,
|
||||||
|
name: badge.name,
|
||||||
|
title: badge.title,
|
||||||
|
slot: badge.slot,
|
||||||
|
visible: badge.visible,
|
||||||
|
replaces: badge.replaces,
|
||||||
|
replaces_type: badge.replaces_type
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ffz.badges[exact_id] = this.badges[badge_id] = real_badge;
|
||||||
|
utils.update_css(this.ffz._badge_style, exact_id, utils.badge_css(real_badge));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
API.prototype.remove_badge = function(badge_id) {
|
||||||
|
var exact_id = this.id + '-' + badge_id;
|
||||||
|
this.ffz.badges[exact_id] = this.badges[badge_id] = undefined;
|
||||||
|
utils.update_css(this.ffz._badge_style, exact_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----------------------
|
// -----------------------
|
||||||
// User Modifications
|
// User Modifications
|
||||||
// -----------------------
|
// -----------------------
|
||||||
|
|
||||||
API.prototype.user_add_set = function(user_name, set_id) {
|
API.prototype.user_add_badge = function(username, slot, badge_id) {
|
||||||
var user = this.users[user_name] = this.users[user_name] || {},
|
var user = this.users[username] = this.users[username] || {},
|
||||||
ffz_user = this.ffz.users[user_name] = this.ffz.users[user_name] || {},
|
ffz_user = this.ffz.users[username] = this.ffz.users[username] || {},
|
||||||
|
|
||||||
|
badges = user.badges = user.badges || {},
|
||||||
|
ffz_badges = ffz_user.badges = ffz_user.badges || {},
|
||||||
|
|
||||||
|
exact_id = this.id + '-' + badge_id,
|
||||||
|
badge = {id: exact_id};
|
||||||
|
|
||||||
|
badges[slot] = ffz_badges[slot] = badge;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
API.prototype.user_remove_badge = function(username, slot) {
|
||||||
|
var user = this.users[username] = this.users[username] || {},
|
||||||
|
ffz_user = this.ffz.users[username] = this.ffz.users[username] || {},
|
||||||
|
|
||||||
|
badges = user.badges = user.badges || {},
|
||||||
|
ffz_badges = ffz_user.badges = ffz_user.badges || {};
|
||||||
|
|
||||||
|
badges[slot] = ffz_badges[slot] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
API.prototype.user_add_set = function(username, set_id) {
|
||||||
|
var user = this.users[username] = this.users[username] || {},
|
||||||
|
ffz_user = this.ffz.users[username] = this.ffz.users[username] || {},
|
||||||
|
|
||||||
emote_sets = user.sets = user.sets || [],
|
emote_sets = user.sets = user.sets || [],
|
||||||
ffz_sets = ffz_user.sets = ffz_user.sets || [],
|
ffz_sets = ffz_user.sets = ffz_user.sets || [],
|
||||||
|
@ -407,14 +472,14 @@ API.prototype.user_add_set = function(user_name, set_id) {
|
||||||
|
|
||||||
// Update tab completion.
|
// Update tab completion.
|
||||||
var user = this.ffz.get_user();
|
var user = this.ffz.get_user();
|
||||||
if ( this.ffz._inputv && user && user.login === user_name )
|
if ( this.ffz._inputv && user && user.login === username )
|
||||||
Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons');
|
Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
API.prototype.user_remove_set = function(user_name, set_id) {
|
API.prototype.user_remove_set = function(username, set_id) {
|
||||||
var user = this.users[user_name],
|
var user = this.users[username],
|
||||||
ffz_user = this.ffz.users[user_name],
|
ffz_user = this.ffz.users[username],
|
||||||
|
|
||||||
emote_sets = user && user.sets,
|
emote_sets = user && user.sets,
|
||||||
ffz_sets = ffz_user && ffz_user.sets,
|
ffz_sets = ffz_user && ffz_user.sets,
|
||||||
|
@ -431,7 +496,7 @@ API.prototype.user_remove_set = function(user_name, set_id) {
|
||||||
|
|
||||||
// Update tab completion.
|
// Update tab completion.
|
||||||
var user = this.ffz.get_user();
|
var user = this.ffz.get_user();
|
||||||
if ( this.ffz._inputv && user && user.login === user_name )
|
if ( this.ffz._inputv && user && user.login === username )
|
||||||
Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons');
|
Ember.propertyDidChange(this.ffz._inputv, 'ffz_emoticons');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,7 +520,6 @@ API.prototype.unregister_chat_filter = function(filter) {
|
||||||
this.ffz._chat_filters.splice(ind, 1);
|
this.ffz._chat_filters.splice(ind, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----------------------
|
// -----------------------
|
||||||
// Channel Callbacks
|
// Channel Callbacks
|
||||||
// -----------------------
|
// -----------------------
|
||||||
|
|
|
@ -96,6 +96,10 @@ FFZ.prototype.setup_bttv = function(delay) {
|
||||||
this.toggle_style('chat-hc-background');*/
|
this.toggle_style('chat-hc-background');*/
|
||||||
|
|
||||||
this.toggle_style('chat-colors-gray');
|
this.toggle_style('chat-colors-gray');
|
||||||
|
this.toggle_style('badges-rounded');
|
||||||
|
this.toggle_style('badges-circular');
|
||||||
|
this.toggle_style('badges-blank');
|
||||||
|
this.toggle_style('badges-circular-small');
|
||||||
this.toggle_style('badges-transparent');
|
this.toggle_style('badges-transparent');
|
||||||
this.toggle_style('badges-sub-notice');
|
this.toggle_style('badges-sub-notice');
|
||||||
this.toggle_style('badges-sub-notice-on');
|
this.toggle_style('badges-sub-notice-on');
|
||||||
|
@ -114,12 +118,15 @@ FFZ.prototype.setup_bttv = function(delay) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send Message Behavior
|
// Send Message Behavior
|
||||||
var original_send = BetterTTV.chat.helpers.sendMessage, f = this;
|
var f = this,
|
||||||
BetterTTV.chat.helpers.sendMessage = function(message) {
|
BC = BetterTTV.chat,
|
||||||
|
original_send = BC.helpers.sendMessage;
|
||||||
|
|
||||||
|
BC.helpers.sendMessage = function(message) {
|
||||||
var cmd = message.split(' ', 1)[0].toLowerCase();
|
var cmd = message.split(' ', 1)[0].toLowerCase();
|
||||||
|
|
||||||
if ( cmd === "/ffz" )
|
if ( cmd === '/ffz' )
|
||||||
f.run_ffz_command(message.substr(5), BetterTTV.chat.store.currentRoom);
|
f.run_ffz_command(message.substr(5), BC.store.currentRoom);
|
||||||
else
|
else
|
||||||
return original_send(message);
|
return original_send(message);
|
||||||
}
|
}
|
||||||
|
@ -127,9 +134,10 @@ FFZ.prototype.setup_bttv = function(delay) {
|
||||||
|
|
||||||
// Ugly Hack for Current Room, as this is stripped out before we get to
|
// Ugly Hack for Current Room, as this is stripped out before we get to
|
||||||
// the actual privmsg renderer.
|
// the actual privmsg renderer.
|
||||||
var original_handler = BetterTTV.chat.handlers.onPrivmsg,
|
var original_handler = BC.handlers.onPrivmsg,
|
||||||
received_room;
|
received_room;
|
||||||
BetterTTV.chat.handlers.onPrivmsg = function(room, data) {
|
|
||||||
|
BC.handlers.onPrivmsg = function(room, data) {
|
||||||
received_room = room;
|
received_room = room;
|
||||||
var output = original_handler(room, data);
|
var output = original_handler(room, data);
|
||||||
received_room = null;
|
received_room = null;
|
||||||
|
@ -138,39 +146,48 @@ FFZ.prototype.setup_bttv = function(delay) {
|
||||||
|
|
||||||
|
|
||||||
// Message Display Behavior
|
// Message Display Behavior
|
||||||
var original_privmsg = BetterTTV.chat.templates.privmsg;
|
var original_privmsg = BC.templates.privmsg;
|
||||||
BetterTTV.chat.templates.privmsg = function(highlight, action, server, isMod, data) {
|
BC.templates.privmsg = function(data, opts) {
|
||||||
try {
|
try {
|
||||||
|
opts = opts || {};
|
||||||
|
|
||||||
// Handle badges.
|
// Handle badges.
|
||||||
f.bttv_badges(data);
|
f.bttv_badges(data);
|
||||||
|
|
||||||
// Now, do everything else manually because things are hard-coded.
|
// Now, do everything else manually because things are hard-coded.
|
||||||
return '<div class="chat-line'+(highlight?' highlight':'')+(action?' action':'')+(server?' admin':'')+'" data-sender="'+(data.sender||"").toLowerCase()+'" data-room="'+received_room+'">'+
|
return '<div class="chat-line'+(opts.highlight?' highlight':'')+(opts.action?' action':'')+(opts.server?' admin':'')+'" data-sender="'+(data.sender||"").toLowerCase()+'" data-room="'+received_room+'">'+
|
||||||
BetterTTV.chat.templates.timestamp(data.time)+' '+
|
BC.templates.timestamp(data.time)+' '+
|
||||||
(isMod?BetterTTV.chat.templates.modicons():'')+' '+
|
(opts.isMod ? BC.templates.modicons():'')+' '+
|
||||||
BetterTTV.chat.templates.badges(data.badges)+
|
BC.templates.badges(data.badges)+
|
||||||
BetterTTV.chat.templates.from(data.nickname, data.color)+
|
BC.templates.from(data.nickname, data.color)+
|
||||||
BetterTTV.chat.templates.message(data.sender, data.message, data.emotes, action?data.color:false)+
|
BC.templates.message(data.sender, data.message, {
|
||||||
|
emotes: data.emotes,
|
||||||
|
colored: (opts.action && !opts.highlight) ? data.color : false,
|
||||||
|
bits: data.bits
|
||||||
|
}) +
|
||||||
'</div>';
|
'</div>';
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
f.log("Error: ", err);
|
f.log("Error: ", err);
|
||||||
return original_privmsg(highlight, action, server, isMod, data);
|
return original_privmsg(data, opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whispers too!
|
// Whispers too!
|
||||||
var original_whisper = BetterTTV.chat.templates.whisper;
|
var original_whisper = BC.templates.whisper;
|
||||||
BetterTTV.chat.templates.whisper = function(data) {
|
BC.templates.whisper = function(data) {
|
||||||
try {
|
try {
|
||||||
// Handle badges.
|
// Handle badges.
|
||||||
f.bttv_badges(data);
|
f.bttv_badges(data);
|
||||||
|
|
||||||
// Now, do everything else manually because things are hard-coded.
|
// Now, do everything else manually because things are hard-coded.
|
||||||
return '<div class="chat-line whisper" data-sender="' + data.sender + '">' +
|
return '<div class="chat-line whisper" data-sender="' + data.sender + '">' +
|
||||||
BetterTTV.chat.templates.timestamp(data.time) + ' ' +
|
BC.templates.timestamp(data.time) + ' ' +
|
||||||
(data.badges && data.badges.length ? BetterTTV.chat.templates.badges(data.badges) : '') +
|
(data.badges && data.badges.length ? BC.templates.badges(data.badges) : '') +
|
||||||
BetterTTV.chat.templates.whisperName(data.sender, data.receiver, data.from, data.to, data.fromColor, data.toColor) +
|
BC.templates.whisperName(data.sender, data.receiver, data.from, data.to, data.fromColor, data.toColor) +
|
||||||
BetterTTV.chat.templates.message(data.sender, data.message, data.emotes, false) +
|
BC.templates.message(data.sender, data.message, {
|
||||||
|
emotes: data.emotes,
|
||||||
|
colored: false
|
||||||
|
}) +
|
||||||
'</div>';
|
'</div>';
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
f.log("Error: ", err);
|
f.log("Error: ", err);
|
||||||
|
@ -180,22 +197,24 @@ FFZ.prototype.setup_bttv = function(delay) {
|
||||||
|
|
||||||
// Message Renderer. I had to completely rewrite this method to get it to
|
// Message Renderer. I had to completely rewrite this method to get it to
|
||||||
// use my replacement emoticonizer.
|
// use my replacement emoticonizer.
|
||||||
var original_message = BetterTTV.chat.templates.message,
|
var original_message = BC.templates.message,
|
||||||
received_sender;
|
received_sender;
|
||||||
BetterTTV.chat.templates.message = function(sender, message, emotes, colored) {
|
BC.templates.message = function(sender, message, data) {
|
||||||
try {
|
try {
|
||||||
colored = colored || false;
|
var colored = data.colored || false,
|
||||||
var rawMessage = encodeURIComponent(message);
|
force = data.force || false,
|
||||||
|
emotes = data.emotes,
|
||||||
|
rawMessage = encodeURIComponent(message);
|
||||||
|
|
||||||
if(sender !== 'jtv') {
|
if(sender !== 'jtv') {
|
||||||
// Hackilly send our state across.
|
// Hackilly send our state across.
|
||||||
received_sender = sender;
|
received_sender = sender;
|
||||||
var tokenizedMessage = BetterTTV.chat.templates.emoticonize(message, emotes);
|
var tokenizedMessage = BC.templates.emoticonize(message, emotes);
|
||||||
received_sender = null;
|
received_sender = null;
|
||||||
|
|
||||||
for(var i=0; i<tokenizedMessage.length; i++) {
|
for(var i=0; i<tokenizedMessage.length; i++) {
|
||||||
if(typeof tokenizedMessage[i] === 'string') {
|
if(typeof tokenizedMessage[i] === 'string') {
|
||||||
tokenizedMessage[i] = BetterTTV.chat.templates.bttvMessageTokenize(sender, tokenizedMessage[i]);
|
tokenizedMessage[i] = BC.templates.bttvMessageTokenize(sender, tokenizedMessage[i], data.bits);
|
||||||
} else {
|
} else {
|
||||||
tokenizedMessage[i] = tokenizedMessage[i][0];
|
tokenizedMessage[i] = tokenizedMessage[i][0];
|
||||||
}
|
}
|
||||||
|
@ -204,7 +223,14 @@ FFZ.prototype.setup_bttv = function(delay) {
|
||||||
message = tokenizedMessage.join(' ');
|
message = tokenizedMessage.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
return '<span class="message" '+(colored?'style="color: '+colored+'" ':'')+'data-raw="'+rawMessage+'" data-emotes="'+(emotes ? encodeURIComponent(JSON.stringify(emotes)) : 'false')+'">'+message+'</span>';
|
var spam = false;
|
||||||
|
if ( BetterTTV.settings.get('hideSpam') && BC.helpers.isSpammer(sender) && !BC.helpers.isModerator(sender) && !force) {
|
||||||
|
message = '<span class="deleted"><spam deleted></span>';
|
||||||
|
spam = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '<span class="message ' + (spam ? 'spam' : '') + '" ' + (colored ? 'style="color: ' + colored + '" ' : '') + 'data-raw="' + rawMessage + '" data-emotes="' + (emotes ? encodeURIComponent(JSON.stringify(emotes)) : 'false') + '">' + message + '</span>';
|
||||||
|
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
f.log("Error: ", err);
|
f.log("Error: ", err);
|
||||||
return original_message(sender, message, emotes, colored);
|
return original_message(sender, message, emotes, colored);
|
||||||
|
@ -247,8 +273,8 @@ FFZ.prototype.setup_bttv = function(delay) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emoticonize
|
// Emoticonize
|
||||||
var original_emoticonize = BetterTTV.chat.templates.emoticonize;
|
var original_emoticonize = BC.templates.emoticonize;
|
||||||
BetterTTV.chat.templates.emoticonize = function(message, emotes) {
|
BC.templates.emoticonize = function(message, emotes) {
|
||||||
var tokens = original_emoticonize(message, emotes),
|
var tokens = original_emoticonize(message, emotes),
|
||||||
|
|
||||||
room = (received_room || BetterTTV.getChannel()),
|
room = (received_room || BetterTTV.getChannel()),
|
||||||
|
|
|
@ -1,305 +0,0 @@
|
||||||
var FFZ = window.FrankerFaceZ,
|
|
||||||
constants = require('../constants'),
|
|
||||||
utils = require('../utils');
|
|
||||||
|
|
||||||
|
|
||||||
// --------------------
|
|
||||||
// Initialization
|
|
||||||
// --------------------
|
|
||||||
|
|
||||||
FFZ.prototype.setup_rechat = function() {
|
|
||||||
if ( this.has_bttv || navigator.userAgent.indexOf('Android') !== -1 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._rechat_listening = false;
|
|
||||||
|
|
||||||
this.log("Installing ReChat mutation observer.");
|
|
||||||
|
|
||||||
var f = this;
|
|
||||||
this._rechat_observer = new MutationObserver(function(mutations) {
|
|
||||||
for(var i=0; i < mutations.length; i++) {
|
|
||||||
var mutation = mutations[i];
|
|
||||||
if ( mutation.type !== "childList" )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for(var x=0; x < mutation.addedNodes.length; x++) {
|
|
||||||
var added = mutation.addedNodes[x];
|
|
||||||
if ( added.nodeType !== added.ELEMENT_NODE || added.tagName !== "DIV" )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Is this a ReChat line?
|
|
||||||
if ( added.classList.contains('rechat-chat-line') && ! added.classList.contains('ffz-processed') )
|
|
||||||
f.process_rechat_line(added);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.log("Starting ReChat check loop.");
|
|
||||||
this._rechat_interval = setInterval(this.find_rechat.bind(this), 1000);
|
|
||||||
this.find_rechat();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// --------------------
|
|
||||||
// ReChat Detection
|
|
||||||
// --------------------
|
|
||||||
|
|
||||||
FFZ.prototype.find_rechat = function() {
|
|
||||||
var el = !this.has_bttv ? document.querySelector('.rechat-chat-line') : null;
|
|
||||||
|
|
||||||
if ( ! this._rechat_listening && ! el ) {
|
|
||||||
// Try darkening a chat container. We don't have chat.
|
|
||||||
var container = document.querySelector('.chat-container'),
|
|
||||||
header = container && container.querySelector('.chat-header');
|
|
||||||
|
|
||||||
if ( header && header.textContent.indexOf('ReChat') !== -1 ) {
|
|
||||||
// Look-up dark mode.
|
|
||||||
var dark_chat = this.settings.dark_twitch;
|
|
||||||
if ( ! dark_chat ) {
|
|
||||||
var Settings = utils.ember_lookup('controller:settings'),
|
|
||||||
model = Settings ? Settings.get('model') : undefined;
|
|
||||||
|
|
||||||
dark_chat = model && model.get('darkMode');
|
|
||||||
}
|
|
||||||
|
|
||||||
container.classList.toggle('dark', dark_chat);
|
|
||||||
jQuery(container).find('.chat-lines').addClass('ffz-scrollbar');
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's no change, don't continue.
|
|
||||||
if ( !!el === this._rechat_listening )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// If we're no longer listening, stop the observer and quit.
|
|
||||||
if ( ! el ) {
|
|
||||||
this._rechat_observer.disconnect();
|
|
||||||
this._rechat_listening = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're newly listening. Process all existing ReChat chat lines
|
|
||||||
// and darken the container if required, also enable the observer.
|
|
||||||
var container = jQuery(el).parents('.chat-container');
|
|
||||||
if ( ! container.length )
|
|
||||||
return;
|
|
||||||
|
|
||||||
container = container[0];
|
|
||||||
|
|
||||||
// Look-up dark mode.
|
|
||||||
var dark_chat = this.settings.dark_twitch;
|
|
||||||
if ( ! dark_chat ) {
|
|
||||||
var Settings = utils.ember_lookup('controller:settings'),
|
|
||||||
model = Settings ? Settings.get('model') : undefined;
|
|
||||||
|
|
||||||
dark_chat = model && model.get('darkMode');
|
|
||||||
}
|
|
||||||
|
|
||||||
container.classList.toggle('dark', dark_chat);
|
|
||||||
jQuery(container).find('.chat-lines').addClass('ffz-scrollbar');
|
|
||||||
|
|
||||||
// Tooltips
|
|
||||||
jQuery(container).find('.tooltip').tipsy({live: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
|
||||||
//jQuery(container).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
|
|
||||||
//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');
|
|
||||||
if ( room_id && ! this.rooms[room_id] )
|
|
||||||
this.load_room(room_id, this._reprocess_rechat.bind(this, container));
|
|
||||||
|
|
||||||
// Do stuff.
|
|
||||||
var lines = container.querySelectorAll('.rechat-chat-line');
|
|
||||||
for(var i=0; i < lines.length; i++) {
|
|
||||||
var line = lines[i];
|
|
||||||
if ( line.classList.contains('ffz-processed') )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
this.process_rechat_line(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start observing.
|
|
||||||
this._rechat_observer.observe(container, {
|
|
||||||
childList: true,
|
|
||||||
subtree: true
|
|
||||||
});
|
|
||||||
|
|
||||||
this._rechat_listening = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// --------------------
|
|
||||||
// ReChat Lines
|
|
||||||
// --------------------
|
|
||||||
|
|
||||||
FFZ.prototype._reprocess_rechat = function(container) {
|
|
||||||
var lines = container.querySelectorAll('.rechat-chat-line');
|
|
||||||
for(var i=0; i < lines.length; i++)
|
|
||||||
this.process_rechat_line(lines[i], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype.process_rechat_line = function(line, reprocess) {
|
|
||||||
if ( ! reprocess && line.classList.contains('ffz-processed') )
|
|
||||||
return;
|
|
||||||
|
|
||||||
line.classList.add('ffz-processed');
|
|
||||||
|
|
||||||
var f = this,
|
|
||||||
user_id = line.getAttribute('data-sender'),
|
|
||||||
room_id = line.getAttribute('data-room'),
|
|
||||||
|
|
||||||
Layout = utils.ember_lookup('service:layout'),
|
|
||||||
Settings = utils.ember_lookup('controller:settings'),
|
|
||||||
is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('settings.darkMode')),
|
|
||||||
|
|
||||||
badges_el = line.querySelector('.badges'),
|
|
||||||
from_el = line.querySelector('.from'),
|
|
||||||
message_el = line.querySelector('.message'),
|
|
||||||
|
|
||||||
badges = {},
|
|
||||||
had_badges = !!badges_el,
|
|
||||||
|
|
||||||
raw_color = from_el && FFZ.Color.RGB.fromCSS(from_el.style.color),
|
|
||||||
colors = raw_color && this._handle_color(raw_color),
|
|
||||||
|
|
||||||
alias = this.aliases[user_id];
|
|
||||||
|
|
||||||
|
|
||||||
if ( ! badges_el ) {
|
|
||||||
badges_el = document.createElement('span');
|
|
||||||
badges_el.className = 'badges float-left';
|
|
||||||
line.insertBefore(badges_el, from_el || line.firstElementChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! reprocess || ! had_badges ) {
|
|
||||||
// Read existing known badges.
|
|
||||||
var existing = badges_el.querySelectorAll('.badge');
|
|
||||||
for(var i=0; i < existing.length; i++) {
|
|
||||||
var badge = existing[i];
|
|
||||||
if ( badge.classList.contains('broadcaster') )
|
|
||||||
badges[0] = {klass: 'broadcaster', title: 'Broadcaster'};
|
|
||||||
else if ( badge.classList.contains('staff') )
|
|
||||||
badges[0] = {klass: 'staff', title: 'Staff'};
|
|
||||||
else if ( badge.classList.contains('admin') )
|
|
||||||
badges[0] = {klass: 'admin', title: 'Admin'};
|
|
||||||
else if ( badge.classList.contains('global-moderator') )
|
|
||||||
badges[0] = {klass: 'global-moderator', title: 'Global Moderator'};
|
|
||||||
else if ( badge.classList.contains('moderator') )
|
|
||||||
badges[0] = {klass: 'moderator', title: 'Moderator'};
|
|
||||||
else if ( badge.classList.contains('subscriber') )
|
|
||||||
badges[10] = {klass: 'subscriber', title: 'Subscriber'};
|
|
||||||
else if ( badge.classList.contains('turbo') )
|
|
||||||
badges[15] = {klass: 'turbo', title: 'Turbo'};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( user_id && user_id === room_id )
|
|
||||||
badges[0] = {klass: 'broadcaster', title: 'Broadcaster'};
|
|
||||||
|
|
||||||
if ( user_id )
|
|
||||||
badges = this.get_badges(user_id, room_id, badges, null);
|
|
||||||
|
|
||||||
badges_el.innerHTML = this.render_badges(badges);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! reprocess && from_el ) {
|
|
||||||
from_el.style.fontWeight = "";
|
|
||||||
if ( colors ) {
|
|
||||||
from_el.classList.add('has_color');
|
|
||||||
from_el.style.color = is_dark ? colors[1] : colors[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( alias ) {
|
|
||||||
from_el.classList.add('ffz-alias');
|
|
||||||
from_el.title = from_el.textContent;
|
|
||||||
from_el.textContent = alias;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! message_el )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ( ! reprocess && colors && message_el.style.color ) {
|
|
||||||
message_el.classList.add('has-color');
|
|
||||||
message_el.style.color = is_dark ? colors[1] : colors[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
var raw_tokens = line.getAttribute('data-tokens'),
|
|
||||||
tokens = raw_tokens ? JSON.parse(raw_tokens) : [];
|
|
||||||
|
|
||||||
if ( ! raw_tokens ) {
|
|
||||||
for(var i=0; i < message_el.childNodes.length; i++) {
|
|
||||||
var node = message_el.childNodes[i];
|
|
||||||
|
|
||||||
if ( node.nodeType === node.TEXT_NODE )
|
|
||||||
tokens.push(node.textContent);
|
|
||||||
|
|
||||||
else if ( node.nodeType === node.ELEMENT_NODE ) {
|
|
||||||
if ( node.tagName === 'IMG' )
|
|
||||||
tokens.push({
|
|
||||||
type: "emoticon",
|
|
||||||
altText: node.alt,
|
|
||||||
imgSrc: node.src
|
|
||||||
});
|
|
||||||
|
|
||||||
else if ( node.tagName === 'A' )
|
|
||||||
tokens.push({
|
|
||||||
type: "link",
|
|
||||||
isDeleted: false,
|
|
||||||
isLong: false,
|
|
||||||
length: node.textContent.length,
|
|
||||||
link: node.href,
|
|
||||||
text: node.textContent
|
|
||||||
});
|
|
||||||
|
|
||||||
else if ( node.tagName === 'SPAN' )
|
|
||||||
tokens.push({
|
|
||||||
type: "mention",
|
|
||||||
user: node.textContent,
|
|
||||||
isOwnMessage: node.classList.contains('mentioning')
|
|
||||||
});
|
|
||||||
|
|
||||||
else {
|
|
||||||
this.log("Unknown Tag Type: " + node.tagName);
|
|
||||||
tokens.push({
|
|
||||||
isRaw: true,
|
|
||||||
html: node.outerHTML
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
} else
|
|
||||||
this.log("Unknown Node Type Tokenizing Message: " + node.nodeType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
line.setAttribute('data-tokens', JSON.stringify(tokens));
|
|
||||||
|
|
||||||
// Further tokenization~!
|
|
||||||
if ( this.settings.replace_bad_emotes )
|
|
||||||
tokens = this.tokenize_replace_emotes(tokens);
|
|
||||||
|
|
||||||
tokens = this._remove_banned(tokens);
|
|
||||||
tokens = this.tokenize_emotes(user_id, room_id, tokens, false);
|
|
||||||
|
|
||||||
if ( this.settings.parse_emoji )
|
|
||||||
tokens = this.tokenize_emoji(tokens);
|
|
||||||
|
|
||||||
tokens = this.tokenize_mentions(tokens);
|
|
||||||
|
|
||||||
// Check for a mention
|
|
||||||
if ( ! line.classList.contains('ffz-mentioend') )
|
|
||||||
for(var i=0; i < tokens.length; i++)
|
|
||||||
if ( tokens[i].mentionedUser ) {
|
|
||||||
line.classList.add('ffz-mentioned');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, put the content back into the element.
|
|
||||||
message_el.innerHTML = this.render_tokens(tokens);
|
|
||||||
|
|
||||||
// Interactions
|
|
||||||
jQuery('a.deleted-link', message_el).click(f._deleted_link_click);
|
|
||||||
jQuery('img.emoticon', message_el).click(function(e) { f._click_emote(e.target, e); });
|
|
||||||
}
|
|
30
src/ext/warpworld.js
Normal file
30
src/ext/warpworld.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
var FFZ = window.FrankerFaceZ;
|
||||||
|
|
||||||
|
// --------------------
|
||||||
|
// Initialization
|
||||||
|
// --------------------
|
||||||
|
|
||||||
|
FFZ.settings_info.warp_world = {
|
||||||
|
type: "boolean",
|
||||||
|
value: true,
|
||||||
|
|
||||||
|
category: "Channel Metadata",
|
||||||
|
name: "Warp World <small>(Requires Refresh)</small>",
|
||||||
|
|
||||||
|
help: 'Automatically load <a href="https://warp.world" target="_blank">Warp World</a> when viewing a channel that uses Warp World.'
|
||||||
|
}
|
||||||
|
|
||||||
|
FFZ.ws_commands.warp_world = function(data) {
|
||||||
|
if ( ! data || ! this.settings.warp_world )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Make sure that Warp World isn't already loaded or loading.
|
||||||
|
var ww_script = document.querySelector('script#ww_script');
|
||||||
|
if ( ww_script || window.WarpWorld )
|
||||||
|
return;
|
||||||
|
|
||||||
|
ww_script = document.createElement('script');
|
||||||
|
ww_script.id = 'ww_script';
|
||||||
|
ww_script.src = '//cdn.warp.world/twitch_script/main.min.js?_=' + Date.now();
|
||||||
|
document.head.appendChild(ww_script);
|
||||||
|
}
|
14
src/main.js
14
src/main.js
|
@ -37,7 +37,7 @@ FFZ.msg_commands = {};
|
||||||
|
|
||||||
// Version
|
// Version
|
||||||
var VER = FFZ.version_info = {
|
var VER = FFZ.version_info = {
|
||||||
major: 3, minor: 5, revision: 216,
|
major: 3, minor: 5, revision: 247,
|
||||||
toString: function() {
|
toString: function() {
|
||||||
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
|
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
|
||||||
}
|
}
|
||||||
|
@ -167,8 +167,9 @@ require('./badges');
|
||||||
require('./tokenize');
|
require('./tokenize');
|
||||||
//require('./filtering');
|
//require('./filtering');
|
||||||
|
|
||||||
|
require('./ember/wrapper');
|
||||||
require('./ember/router');
|
require('./ember/router');
|
||||||
|
require('./ember/bits');
|
||||||
require('./ember/channel');
|
require('./ember/channel');
|
||||||
require('./ember/player');
|
require('./ember/player');
|
||||||
require('./ember/room');
|
require('./ember/room');
|
||||||
|
@ -188,7 +189,6 @@ require('./ember/sidebar');
|
||||||
|
|
||||||
require('./debug');
|
require('./debug');
|
||||||
|
|
||||||
//require('./ext/rechat');
|
|
||||||
require('./ext/betterttv');
|
require('./ext/betterttv');
|
||||||
require('./ext/emote_menu');
|
require('./ext/emote_menu');
|
||||||
|
|
||||||
|
@ -214,6 +214,7 @@ require('./ui/about_page');
|
||||||
|
|
||||||
require('./commands');
|
require('./commands');
|
||||||
require('./ext/api');
|
require('./ext/api');
|
||||||
|
require('./ext/warpworld');
|
||||||
|
|
||||||
|
|
||||||
// ---------------
|
// ---------------
|
||||||
|
@ -404,6 +405,7 @@ FFZ.prototype.init_ember = function(delay) {
|
||||||
|
|
||||||
// Initialize all the modules.
|
// Initialize all the modules.
|
||||||
this.load_settings();
|
this.load_settings();
|
||||||
|
this.setup_ember_wrapper();
|
||||||
|
|
||||||
// Start this early, for quick loading.
|
// Start this early, for quick loading.
|
||||||
this.setup_dark();
|
this.setup_dark();
|
||||||
|
@ -426,6 +428,7 @@ FFZ.prototype.init_ember = function(delay) {
|
||||||
this.setup_room();
|
this.setup_room();
|
||||||
this.setup_vod_chat();
|
this.setup_vod_chat();
|
||||||
this.setup_line();
|
this.setup_line();
|
||||||
|
this.setup_bits();
|
||||||
this.setup_layout();
|
this.setup_layout();
|
||||||
this.setup_chatview();
|
this.setup_chatview();
|
||||||
this.setup_conversations();
|
this.setup_conversations();
|
||||||
|
@ -446,10 +449,13 @@ FFZ.prototype.init_ember = function(delay) {
|
||||||
this.setup_following_count(true);
|
this.setup_following_count(true);
|
||||||
this.setup_races();
|
this.setup_races();
|
||||||
|
|
||||||
|
|
||||||
|
// Do all Ember modification before this point.
|
||||||
|
this.finalize_ember_wrapper();
|
||||||
|
|
||||||
this.fix_tooltips();
|
this.fix_tooltips();
|
||||||
this.connect_extra_chat();
|
this.connect_extra_chat();
|
||||||
|
|
||||||
//this.setup_rechat();
|
|
||||||
this.setup_message_event();
|
this.setup_message_event();
|
||||||
this.find_bttv(10);
|
this.find_bttv(10);
|
||||||
this.find_emote_menu(10);
|
this.find_emote_menu(10);
|
||||||
|
|
180
src/settings.js
180
src/settings.js
|
@ -9,6 +9,23 @@ var FFZ = window.FrankerFaceZ,
|
||||||
return "ffz_setting_" + key;
|
return "ffz_setting_" + key;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
favorite_setting = function(swit, key, info) {
|
||||||
|
var ind = this.settings.favorite_settings.indexOf(key);
|
||||||
|
|
||||||
|
if ( ind === -1 ) {
|
||||||
|
this.settings.favorite_settings.push(key);
|
||||||
|
swit.setAttribute('original-title', 'Unfavorite this Setting');
|
||||||
|
swit.classList.add('active');
|
||||||
|
} else {
|
||||||
|
this.settings.favorite_settings.splice(ind,1);
|
||||||
|
swit.setAttribute('original-title', 'Favorite this Setting');
|
||||||
|
swit.classList.remove('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery(swit).trigger('mouseout').trigger('mouseover');
|
||||||
|
this.settings.set('favorite_settings', this.settings.favorite_settings);
|
||||||
|
},
|
||||||
|
|
||||||
toggle_setting = function(swit, key, info) {
|
toggle_setting = function(swit, key, info) {
|
||||||
var val = !(info.get ? (typeof info.get === 'function' ? info.get.call(this) : this.settings.get(info.get)) : this.settings.get(key));
|
var val = !(info.get ? (typeof info.get === 'function' ? info.get.call(this) : this.settings.get(info.get)) : this.settings.get(key));
|
||||||
if ( typeof info.set === "function" )
|
if ( typeof info.set === "function" )
|
||||||
|
@ -208,12 +225,71 @@ FFZ.prototype._load_settings_file = function(data, hide_alert) {
|
||||||
// --------------------
|
// --------------------
|
||||||
|
|
||||||
var is_android = navigator.userAgent.indexOf('Android') !== -1,
|
var is_android = navigator.userAgent.indexOf('Android') !== -1,
|
||||||
settings_renderer = function(settings_data, collapsable, collapsed_key) {
|
settings_renderer = function(settings_data, collapsable, collapsed_key, show_pin) {
|
||||||
return function(view, container) {
|
return function(view, container) {
|
||||||
var f = this,
|
var f = this,
|
||||||
settings = {},
|
settings = {},
|
||||||
categories = [];
|
categories = [];
|
||||||
|
|
||||||
|
// Searching!
|
||||||
|
if ( show_pin ) {
|
||||||
|
var search_cont = utils.createElement('div', 'ffz-filter-container'),
|
||||||
|
search_input = utils.createElement('input', 'emoticon-selector__filter-input js-filter-input text text--full-width'),
|
||||||
|
filtered_cont = utils.createElement('div', 'ffz-filter-children ffz-ui-sub-menu-page');
|
||||||
|
|
||||||
|
search_input.placeholder = 'Search for Settings';
|
||||||
|
search_input.type = 'text';
|
||||||
|
|
||||||
|
filtered_cont.style.maxHeight = (parseInt(container.style.maxHeight) - 51) + 'px';
|
||||||
|
|
||||||
|
search_cont.appendChild(search_input);
|
||||||
|
container.appendChild(filtered_cont);
|
||||||
|
container.appendChild(search_cont);
|
||||||
|
|
||||||
|
container = filtered_cont;
|
||||||
|
|
||||||
|
search_input.addEventListener('input', function(e) {
|
||||||
|
var filter = search_input.value || '',
|
||||||
|
groups = filtered_cont.querySelectorAll('.chat-menu-content');
|
||||||
|
|
||||||
|
filter = filter.toLowerCase();
|
||||||
|
|
||||||
|
for(var i=0; i < groups.length; i++) {
|
||||||
|
var el = groups[i],
|
||||||
|
settings = el.querySelectorAll('.ffz-setting'),
|
||||||
|
hidden = true;
|
||||||
|
|
||||||
|
for(var j=0; j < settings.length; j++) {
|
||||||
|
var se = settings[j],
|
||||||
|
shidden = filter.length && se.getAttribute('data-filter').indexOf(filter) === -1;
|
||||||
|
|
||||||
|
se.classList.toggle('hidden', shidden);
|
||||||
|
hidden = hidden && shidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
var incompat = el.querySelector('.bttv-incompatibility'),
|
||||||
|
settings = incompat && incompat.querySelectorAll('b'),
|
||||||
|
incompat_hidden = true;
|
||||||
|
|
||||||
|
if ( incompat ) {
|
||||||
|
for(var j=0; j < settings.length; j++) {
|
||||||
|
var se = settings[j],
|
||||||
|
shidden = filter.length && se.getAttribute('data-filter').indexOf(filter) === -1;
|
||||||
|
|
||||||
|
se.classList.toggle('hidden', shidden);
|
||||||
|
incompat_hidden = incompat_hidden && shidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
incompat.classList.toggle('hidden', incompat_hidden);
|
||||||
|
hidden = hidden && incompat_hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
el.classList.toggle('collapsable', ! filter.length);
|
||||||
|
el.classList.toggle('hidden', hidden);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for(var key in settings_data) {
|
for(var key in settings_data) {
|
||||||
var info = settings_data[key],
|
var info = settings_data[key],
|
||||||
cat = info.category || "Miscellaneous",
|
cat = info.category || "Miscellaneous",
|
||||||
|
@ -254,7 +330,7 @@ var is_android = navigator.userAgent.indexOf('Android') !== -1,
|
||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
var current_category = (collapsed_key ? this[collapsed_key] : null) || categories[0];
|
var current_category = collapsed_key ? this[collapsed_key] || true : categories[0];
|
||||||
|
|
||||||
for(var ci=0; ci < categories.length; ci++) {
|
for(var ci=0; ci < categories.length; ci++) {
|
||||||
var category = categories[ci],
|
var category = categories[ci],
|
||||||
|
@ -274,15 +350,23 @@ var is_android = navigator.userAgent.indexOf('Android') !== -1,
|
||||||
if ( collapsable ) {
|
if ( collapsable ) {
|
||||||
menu.classList.add('collapsable');
|
menu.classList.add('collapsable');
|
||||||
menu.classList.toggle('collapsed', current_category !== category);
|
menu.classList.toggle('collapsed', current_category !== category);
|
||||||
menu.addEventListener('click', function() {
|
menu.addEventListener('click', function(e) {
|
||||||
var t = this;
|
var t = this;
|
||||||
if ( ! t.classList.contains('collapsed') )
|
if ( ! t.classList.contains('collapsable') )
|
||||||
return;
|
return;
|
||||||
|
else if ( ! t.classList.contains('collapsed') ) {
|
||||||
|
if ( e.target.classList.contains('heading') ) {
|
||||||
|
t.classList.add('collapsed');
|
||||||
|
if ( collapsed_key )
|
||||||
|
f[collapsed_key] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
jQuery(".chat-menu-content:not(.collapsed)", container).addClass("collapsed");
|
jQuery(".chat-menu-content:not(.collapsed)", container).addClass("collapsed");
|
||||||
t.classList.remove('collapsed');
|
t.classList.remove('collapsed');
|
||||||
if ( collapsed_key )
|
if ( collapsed_key )
|
||||||
f[collapsed_key] = t.getAttribute('data-category');
|
f[collapsed_key] = t.getAttribute('data-category');
|
||||||
|
}
|
||||||
|
|
||||||
setTimeout(function(){t.scrollIntoViewIfNeeded()});
|
setTimeout(function(){t.scrollIntoViewIfNeeded()});
|
||||||
});
|
});
|
||||||
|
@ -313,15 +397,26 @@ var is_android = navigator.userAgent.indexOf('Android') !== -1,
|
||||||
for(var i=0; i < cset.length; i++) {
|
for(var i=0; i < cset.length; i++) {
|
||||||
var key = cset[i][0],
|
var key = cset[i][0],
|
||||||
info = cset[i][1],
|
info = cset[i][1],
|
||||||
|
|
||||||
el = createElement('p'),
|
el = createElement('p'),
|
||||||
|
pin_btn = createElement('a'),
|
||||||
val = info.get ? (typeof info.get === 'function' ? info.get.call(this) : this.settings.get(info.get)) : this.settings.get(key);
|
val = info.get ? (typeof info.get === 'function' ? info.get.call(this) : this.settings.get(info.get)) : this.settings.get(key);
|
||||||
|
|
||||||
el.className = 'clearfix';
|
el.className = 'ffz-setting clearfix';
|
||||||
|
|
||||||
if ( this.has_bttv && info.no_bttv ) {
|
if ( this.has_bttv && info.no_bttv ) {
|
||||||
bttv_skipped.push([info.name, info.help]);
|
bttv_skipped.push([info.name, info.help]);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
|
if ( show_pin ) {
|
||||||
|
var faved = this.settings.favorite_settings.indexOf(key) !== -1;
|
||||||
|
pin_btn.className = 'pin-switch html-tooltip';
|
||||||
|
pin_btn.classList.toggle('active', faved);
|
||||||
|
pin_btn.addEventListener('click', favorite_setting.bind(this, pin_btn, key, info));
|
||||||
|
pin_btn.title = (faved ? 'Unf' : 'F') + 'avorite this Setting';
|
||||||
|
pin_btn.innerHTML = constants.STAR;
|
||||||
|
}
|
||||||
|
|
||||||
if ( info.type === "boolean" ) {
|
if ( info.type === "boolean" ) {
|
||||||
var swit = createElement('a'),
|
var swit = createElement('a'),
|
||||||
label = createElement('span');
|
label = createElement('span');
|
||||||
|
@ -334,6 +429,8 @@ var is_android = navigator.userAgent.indexOf('Android') !== -1,
|
||||||
label.innerHTML = info.name;
|
label.innerHTML = info.name;
|
||||||
|
|
||||||
el.appendChild(swit);
|
el.appendChild(swit);
|
||||||
|
if ( show_pin )
|
||||||
|
el.appendChild(pin_btn);
|
||||||
el.appendChild(label);
|
el.appendChild(label);
|
||||||
|
|
||||||
swit.addEventListener('click', toggle_setting.bind(this, swit, key, info))
|
swit.addEventListener('click', toggle_setting.bind(this, swit, key, info))
|
||||||
|
@ -356,6 +453,8 @@ var is_android = navigator.userAgent.indexOf('Android') !== -1,
|
||||||
|
|
||||||
select.addEventListener('change', option_setting.bind(this, select, key, info));
|
select.addEventListener('change', option_setting.bind(this, select, key, info));
|
||||||
|
|
||||||
|
if ( show_pin )
|
||||||
|
el.appendChild(pin_btn);
|
||||||
el.appendChild(label);
|
el.appendChild(label);
|
||||||
el.appendChild(select);
|
el.appendChild(select);
|
||||||
|
|
||||||
|
@ -364,6 +463,9 @@ var is_android = navigator.userAgent.indexOf('Android') !== -1,
|
||||||
var link = createElement('a');
|
var link = createElement('a');
|
||||||
link.innerHTML = info.name;
|
link.innerHTML = info.name;
|
||||||
link.href = '#';
|
link.href = '#';
|
||||||
|
|
||||||
|
if ( show_pin )
|
||||||
|
el.appendChild(pin_btn);
|
||||||
el.appendChild(link);
|
el.appendChild(link);
|
||||||
|
|
||||||
link.addEventListener('click', info.method.bind(this));
|
link.addEventListener('click', info.method.bind(this));
|
||||||
|
@ -371,14 +473,27 @@ var is_android = navigator.userAgent.indexOf('Android') !== -1,
|
||||||
} else
|
} else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ( info.help || (this.has_bttv && info.warn_bttv) ) {
|
if ( info.help || info.experiment_warn || (this.has_bttv && info.warn_bttv) ) {
|
||||||
var help = document.createElement('span');
|
var help = document.createElement('span');
|
||||||
help.className = 'help';
|
help.className = 'help';
|
||||||
help.innerHTML = (this.has_bttv && info.warn_bttv ? '<i>' + info.warn_bttv + (info.help ? '</i><br>' : '</i>') : '') + (info.help || "");
|
var parts = [];
|
||||||
|
if ( info.experiment_warn )
|
||||||
|
parts.push('<b>Note:</b> This affects an active Twitch experiment. Give feedback at: <a href="mailto:feedback@twitch.tv">feedback@twitch.tv</a>');
|
||||||
|
|
||||||
|
if ( this.has_bttv && info.warn_bttv )
|
||||||
|
parts.push('<i>' + info.warn_bttv + '</i>');
|
||||||
|
|
||||||
|
if ( info.help )
|
||||||
|
parts.push(info.help);
|
||||||
|
|
||||||
|
help.innerHTML = parts.join('<br>');
|
||||||
el.appendChild(help);
|
el.appendChild(help);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search by any of the present text.
|
||||||
|
el.setAttribute('data-filter', el.textContent.toLowerCase());
|
||||||
|
|
||||||
added++;
|
added++;
|
||||||
menu.appendChild(el);
|
menu.appendChild(el);
|
||||||
}
|
}
|
||||||
|
@ -397,8 +512,9 @@ var is_android = navigator.userAgent.indexOf('Android') !== -1,
|
||||||
|
|
||||||
help.className = 'help';
|
help.className = 'help';
|
||||||
for(var i=0; i < bttv_skipped.length; i++) {
|
for(var i=0; i < bttv_skipped.length; i++) {
|
||||||
var skipped = bttv_skipped[i];
|
var skipped = bttv_skipped[i],
|
||||||
help.innerHTML += (i > 0 ? ', ' : '') + '<b' + (skipped[1] ? ' class="html-tooltip" title="' + utils.quote_attr(skipped[1]) + '"' : '') + '>' + skipped[0] + '</b>';
|
filter_text = skipped[0].toLowerCase() + (skipped[1] ? ' ' + skipped[1].toLowerCase() : '');
|
||||||
|
help.innerHTML += '<b data-filter="' + utils.quote_attr(filter_text) + '"' + (skipped[1] ? ' class="html-tooltip" title="' + utils.quote_attr(skipped[1]) + '"' : '') + '>' + skipped[0] + '</b>';
|
||||||
}
|
}
|
||||||
|
|
||||||
el.appendChild(label);
|
el.appendChild(label);
|
||||||
|
@ -414,7 +530,13 @@ var is_android = navigator.userAgent.indexOf('Android') !== -1,
|
||||||
},
|
},
|
||||||
|
|
||||||
render_basic = settings_renderer(FFZ.basic_settings, false, '_ffz_basic_settings_page'),
|
render_basic = settings_renderer(FFZ.basic_settings, false, '_ffz_basic_settings_page'),
|
||||||
render_advanced = settings_renderer(FFZ.settings_info, true, '_ffz_settings_page');
|
render_advanced = settings_renderer(FFZ.settings_info, true, '_ffz_settings_page', true);
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.settings_info.favorite_settings = {
|
||||||
|
value: [],
|
||||||
|
hidden: true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.menu_pages.settings = {
|
FFZ.menu_pages.settings = {
|
||||||
|
@ -423,12 +545,42 @@ FFZ.menu_pages.settings = {
|
||||||
sort_order: 99999,
|
sort_order: 99999,
|
||||||
wide: true,
|
wide: true,
|
||||||
|
|
||||||
default_page: function() { return this.settings.advanced_settings ? 'advanced' : 'basic' },
|
default_page: function() { return this.settings.favorite_settings.length ? "favorites" : this.settings.advanced_settings ? 'advanced' : 'basic' },
|
||||||
|
|
||||||
pages: {
|
pages: {
|
||||||
|
favorites: {
|
||||||
|
name: "Favorites",
|
||||||
|
sort_order: 1,
|
||||||
|
|
||||||
|
render: function(view, container) {
|
||||||
|
var favorites = this.settings.favorite_settings;
|
||||||
|
if ( ! favorites.length ) {
|
||||||
|
var el = utils.createElement('div');
|
||||||
|
el.className = 'emoticon-grid ffz-no-emotes center';
|
||||||
|
el.innerHTML = "You have no favorite settings.<br>" +
|
||||||
|
'<img src=\"//cdn.frankerfacez.com/emoticon/26608/2\"><br>' +
|
||||||
|
'To make a setting a favorite, find it on the <nobr>Advanced</nobr> tab and click the star icon to the right.';
|
||||||
|
|
||||||
|
container.appendChild(el);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var favorite_settings = {};
|
||||||
|
for(var i=0, l = favorites.length; i < l; i++) {
|
||||||
|
var key = favorites[i],
|
||||||
|
val = FFZ.settings_info[key];
|
||||||
|
|
||||||
|
if ( val )
|
||||||
|
favorite_settings[key] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings_renderer(favorite_settings, false, '_ffz_favorite_settings_page').call(this, view, container);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
basic: {
|
basic: {
|
||||||
name: "Basic",
|
name: "Basic",
|
||||||
sort_order: 1,
|
sort_order: 2,
|
||||||
|
|
||||||
render: function(view, container) {
|
render: function(view, container) {
|
||||||
this.settings.set("advanced_settings", false);
|
this.settings.set("advanced_settings", false);
|
||||||
|
@ -438,7 +590,7 @@ FFZ.menu_pages.settings = {
|
||||||
|
|
||||||
advanced: {
|
advanced: {
|
||||||
name: "Advanced",
|
name: "Advanced",
|
||||||
sort_order: 2,
|
sort_order: 3,
|
||||||
|
|
||||||
render: function(view, container) {
|
render: function(view, container) {
|
||||||
this.settings.set("advanced_settings", true);
|
this.settings.set("advanced_settings", true);
|
||||||
|
@ -448,7 +600,7 @@ FFZ.menu_pages.settings = {
|
||||||
|
|
||||||
backup: {
|
backup: {
|
||||||
name: "Backup & Restore",
|
name: "Backup & Restore",
|
||||||
sort_order: 3,
|
sort_order: 4,
|
||||||
|
|
||||||
render: function(view, container) {
|
render: function(view, container) {
|
||||||
var backup_head = createElement('div'),
|
var backup_head = createElement('div'),
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
.badges .badge:not(.subscriber):not(.unknown-badge) {
|
.badges .badge:not(.subscriber):not(.unknown-badge) {
|
||||||
background-size: 0px;
|
background-size: 0px !important;
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
.badges .badge:not(.subscriber):not(.unknown-badge) {
|
.badges .badge:not(.unknown-badge):not(.transparent) {
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
background-size: 16px;
|
background-size: 16px;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
|
|
@ -4,15 +4,19 @@
|
||||||
|
|
||||||
|
|
||||||
/* Invert Some Badges */
|
/* Invert Some Badges */
|
||||||
.badge:not(.subscriber):not(.ffz-badge-1) {
|
.ffz-dark .badge.invert-invert,
|
||||||
|
.theatre .badge.invert-invert,
|
||||||
|
.dark .badge.invert-invert,
|
||||||
|
.force-dark .badge.invert-invert,
|
||||||
|
.badge:not(.no-invert):not(.invert-invert) {
|
||||||
filter: invert(75%);
|
filter: invert(75%);
|
||||||
-webkit-filter: invert(75%);
|
-webkit-filter: invert(75%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ffz-dark .badge,
|
.ffz-dark .badge:not(.invert-invert),
|
||||||
.theatre .badge,
|
.theatre .badge:not(.invert-invert),
|
||||||
.dark .badge,
|
.dark .badge:not(.invert-invert),
|
||||||
.force-dark .badge {
|
.force-dark .badge:not(.invert-invert) {
|
||||||
filter: none !important;
|
filter: none !important;
|
||||||
-webkit-filter: none !important;
|
-webkit-filter: none !important;
|
||||||
}
|
}
|
177
src/tokenize.js
177
src/tokenize.js
|
@ -4,6 +4,8 @@ var FFZ = window.FrankerFaceZ,
|
||||||
helpers,
|
helpers,
|
||||||
conv_helpers,
|
conv_helpers,
|
||||||
emote_helpers,
|
emote_helpers,
|
||||||
|
bits_helpers,
|
||||||
|
bits_service,
|
||||||
|
|
||||||
EXPLANATION_WARN = '<hr>This link has been sent to you via a whisper rather than standard chat, and has not been checked or approved of by any moderators or staff members. Please treat this link with caution and do not visit it if you do not trust the sender.',
|
EXPLANATION_WARN = '<hr>This link has been sent to you via a whisper rather than standard chat, and has not been checked or approved of by any moderators or staff members. Please treat this link with caution and do not visit it if you do not trust the sender.',
|
||||||
|
|
||||||
|
@ -13,6 +15,8 @@ var FFZ = window.FrankerFaceZ,
|
||||||
|
|
||||||
LINK = /(?:https?:\/\/)?(?:[-a-zA-Z0-9@:%_\+~#=]+\.)+[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)/g,
|
LINK = /(?:https?:\/\/)?(?:[-a-zA-Z0-9@:%_\+~#=]+\.)+[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)/g,
|
||||||
|
|
||||||
|
CLIP_URL = /(?:https?:\/\/)?clips\.twitch\.tv\/(\w+)\/(\w+)/,
|
||||||
|
|
||||||
LINK_SPLIT = /^(?:(https?):\/\/)?(?:(.*?)@)?([^\/:]+)(?::(\d+))?(.*?)(?:\?(.*?))?(?:\#(.*?))?$/,
|
LINK_SPLIT = /^(?:(https?):\/\/)?(?:(.*?)@)?([^\/:]+)(?::(\d+))?(.*?)(?:\?(.*?))?(?:\#(.*?))?$/,
|
||||||
YOUTUBE_CHECK = /^(?:https?:\/\/)?(?:m\.|www\.)?youtu(?:be\.com|\.be)\/(?:v\/|watch\/|.*?(?:embed|watch).*?v=)?([a-zA-Z0-9\-_]+)$/,
|
YOUTUBE_CHECK = /^(?:https?:\/\/)?(?:m\.|www\.)?youtu(?:be\.com|\.be)\/(?:v\/|watch\/|.*?(?:embed|watch).*?v=)?([a-zA-Z0-9\-_]+)$/,
|
||||||
IMGUR_PATH = /^\/(?:gallery\/)?[A-Za-z0-9]+(?:\.(?:png|jpg|jpeg|gif|gifv|bmp))?$/,
|
IMGUR_PATH = /^\/(?:gallery\/)?[A-Za-z0-9]+(?:\.(?:png|jpg|jpeg|gif|gifv|bmp))?$/,
|
||||||
|
@ -123,6 +127,18 @@ FFZ.settings_info.timestamp_seconds = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.settings_info.collect_bits = {
|
||||||
|
type: "boolean",
|
||||||
|
value: false,
|
||||||
|
|
||||||
|
category: "Chat Appearance",
|
||||||
|
no_bttv: true,
|
||||||
|
|
||||||
|
name: "Bits Stacking",
|
||||||
|
help: "Collect all the bits emoticons in a message into a single one at the start of the message."
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
FFZ.settings_info.show_deleted_links = {
|
FFZ.settings_info.show_deleted_links = {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: false,
|
value: false,
|
||||||
|
@ -155,6 +171,14 @@ FFZ.prototype.setup_tokenization = function() {
|
||||||
if ( ! helpers )
|
if ( ! helpers )
|
||||||
return this.log("Unable to get chat helper functions.");
|
return this.log("Unable to get chat helper functions.");
|
||||||
|
|
||||||
|
try {
|
||||||
|
bits_helpers = window.require && window.require("web-client/utilities/bits/tokenize");
|
||||||
|
} catch(err) {
|
||||||
|
this.error("Unable to get bits tokenizer.", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
bits_service = utils.ember_lookup('service:bits-rendering-config');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
conv_helpers = window.require && window.require("web-client/helpers/twitch-conversations/conversation-line-helpers");
|
conv_helpers = window.require && window.require("web-client/helpers/twitch-conversations/conversation-line-helpers");
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
|
@ -268,7 +292,31 @@ FFZ.prototype.load_twitch_emote_data = function(tries) {
|
||||||
FFZ.prototype.render_tooltip = function(el) {
|
FFZ.prototype.render_tooltip = function(el) {
|
||||||
var f = this,
|
var f = this,
|
||||||
func = function() {
|
func = function() {
|
||||||
if ( this.classList.contains('emoticon') ) {
|
if ( this.classList.contains('ffz-bit') ) {
|
||||||
|
var amount = parseInt(this.getAttribute('data-amount').replace(/,/g, '')),
|
||||||
|
individuals = JSON.parse(this.getAttribute('data-individuals') || "null"),
|
||||||
|
tier = bits_service.ffz_get_tier(amount),
|
||||||
|
preview_url,
|
||||||
|
image,
|
||||||
|
out = utils.number_commas(amount) + ' Bit' + utils.pluralize(amount);
|
||||||
|
|
||||||
|
if ( f.settings.emote_image_hover )
|
||||||
|
preview_url = bits_service.ffz_get_preview(tier[1]);
|
||||||
|
|
||||||
|
if ( individuals && individuals.length > 1 ) {
|
||||||
|
out += '<br>';
|
||||||
|
individuals.sort().reverse();
|
||||||
|
for(var i=0; i < individuals.length && i < 12; i++)
|
||||||
|
out += f.render_token(false, false, true, {type: "bits", amount: individuals[i]});
|
||||||
|
|
||||||
|
if ( individuals.length >= 12 )
|
||||||
|
out += '<br>(and ' + (individuals.length - 12) + ' more)';
|
||||||
|
}
|
||||||
|
|
||||||
|
image = preview_url ? '<img style="height:112px" class="emoticon ffz-image-hover" src="' + preview_url + '"?_=preview">' : '';
|
||||||
|
return image + out;
|
||||||
|
|
||||||
|
} else if ( this.classList.contains('emoticon') ) {
|
||||||
var preview_url, width=0, height=0, image, set_id, emote, emote_set,
|
var preview_url, width=0, height=0, image, set_id, emote, emote_set,
|
||||||
emote_id = this.getAttribute('data-ffz-emote');
|
emote_id = this.getAttribute('data-ffz-emote');
|
||||||
if ( emote_id ) {
|
if ( emote_id ) {
|
||||||
|
@ -356,17 +404,29 @@ FFZ.prototype.render_tooltip = function(el) {
|
||||||
} else if ( this.classList.contains('chat-link') ) {
|
} else if ( this.classList.contains('chat-link') ) {
|
||||||
// TODO: A lot of shit. Lookup data.
|
// TODO: A lot of shit. Lookup data.
|
||||||
var url = this.getAttribute("data-url"),
|
var url = this.getAttribute("data-url"),
|
||||||
|
data = url && f._link_data[url],
|
||||||
|
|
||||||
|
preview_url = null,
|
||||||
|
preview_iframe = true,
|
||||||
|
image = '',
|
||||||
text = '';
|
text = '';
|
||||||
|
|
||||||
if ( ! url )
|
if ( ! url )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ( f.settings.link_image_hover && is_image(url, f.settings.image_hover_all_domains) )
|
// Do we have data?
|
||||||
preview_url = url;
|
if ( data && data !== true ) {
|
||||||
else
|
text = data.html;
|
||||||
preview_url = null;
|
preview_url = data.image;
|
||||||
|
preview_iframe = data.image_iframe !== undefined ? data.image_iframe : true;
|
||||||
|
} else
|
||||||
|
preview_url = is_image(url, f.settings.image_hover_all_domains) ? url : null;
|
||||||
|
|
||||||
image = preview_url ? image_iframe(url) : '';
|
if ( f.settings.link_image_hover && preview_url )
|
||||||
|
if ( preview_iframe )
|
||||||
|
image = image_iframe(url);
|
||||||
|
else
|
||||||
|
image = '<img class="emoticon ffz-image-hover" src="' + utils.quote_attr(preview_url) + '">';
|
||||||
|
|
||||||
// If it's not a deleted link, don't waste time showing the URL in the tooltip.
|
// If it's not a deleted link, don't waste time showing the URL in the tooltip.
|
||||||
if ( this.classList.contains('deleted-link') )
|
if ( this.classList.contains('deleted-link') )
|
||||||
|
@ -412,11 +472,13 @@ FFZ.prototype.tokenize_conversation_line = function(message, prevent_notificatio
|
||||||
if ( user && user.login && helpers && helpers.mentionizeMessage )
|
if ( user && user.login && helpers && helpers.mentionizeMessage )
|
||||||
tokens = helpers.mentionizeMessage(tokens, user.login, from_me);
|
tokens = helpers.mentionizeMessage(tokens, user.login, from_me);
|
||||||
|
|
||||||
if ( helpers && helpers.emoticonizeMessage && emotes )
|
if ( helpers && helpers.emoticonizeMessage && emotes && this.settings.parse_emoticons )
|
||||||
tokens = helpers.emoticonizeMessage(tokens, emotes);
|
tokens = helpers.emoticonizeMessage(tokens, emotes);
|
||||||
|
|
||||||
// FrankerFaceZ Extras
|
// FrankerFaceZ Extras
|
||||||
tokens = this._remove_banned(tokens);
|
tokens = this._remove_banned(tokens);
|
||||||
|
|
||||||
|
if ( this.settings.parse_emoticons && this.settings.parse_emoticons !== 2 )
|
||||||
tokens = this.tokenize_emotes(from_user, undefined, tokens, from_me);
|
tokens = this.tokenize_emotes(from_user, undefined, tokens, from_me);
|
||||||
|
|
||||||
if ( this.settings.parse_emoji )
|
if ( this.settings.parse_emoji )
|
||||||
|
@ -456,11 +518,13 @@ FFZ.prototype.tokenize_vod_line = function(msgObject, delete_links) {
|
||||||
if ( user && user.login && helpers && helpers.mentionizeMessage )
|
if ( user && user.login && helpers && helpers.mentionizeMessage )
|
||||||
tokens = helpers.mentionizeMessage(tokens, user.login, from_me);
|
tokens = helpers.mentionizeMessage(tokens, user.login, from_me);
|
||||||
|
|
||||||
if ( helpers && helpers.emoticonizeMessage && emotes )
|
if ( helpers && helpers.emoticonizeMessage && emotes && this.settings.parse_emoticons )
|
||||||
tokens = helpers.emoticonizeMessage(tokens, emotes);
|
tokens = helpers.emoticonizeMessage(tokens, emotes);
|
||||||
|
|
||||||
// FrankerFaceZ Extras
|
// FrankerFaceZ Extras
|
||||||
tokens = this._remove_banned(tokens);
|
tokens = this._remove_banned(tokens);
|
||||||
|
|
||||||
|
if ( this.settings.parse_emoticons && this.settings.parse_emoticons !== 2 )
|
||||||
tokens = this.tokenize_emotes(from_user, room_id, tokens, from_me);
|
tokens = this.tokenize_emotes(from_user, room_id, tokens, from_me);
|
||||||
|
|
||||||
if ( this.settings.parse_emoji )
|
if ( this.settings.parse_emoji )
|
||||||
|
@ -486,7 +550,7 @@ FFZ.prototype.tokenize_vod_line = function(msgObject, delete_links) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, delete_links, use_bits) {
|
FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, delete_links) {
|
||||||
if ( msgObject.cachedTokens )
|
if ( msgObject.cachedTokens )
|
||||||
return msgObject.cachedTokens;
|
return msgObject.cachedTokens;
|
||||||
|
|
||||||
|
@ -495,12 +559,17 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, del
|
||||||
from_user = msgObject.from,
|
from_user = msgObject.from,
|
||||||
user = this.get_user(),
|
user = this.get_user(),
|
||||||
from_me = user && from_user === user.login,
|
from_me = user && from_user === user.login,
|
||||||
emotes = msgObject.tags && msgObject.tags.emotes,
|
tags = msgObject.tags || {},
|
||||||
|
emotes = tags.emotes,
|
||||||
tokens = [msg];
|
tokens = [msg];
|
||||||
|
|
||||||
// Standard tokenization
|
// Standard Tokenization
|
||||||
if ( use_bits && helpers && helpers.tokenizeBits )
|
if ( tags.bits && bits_helpers && bits_helpers.tokenizeBits )
|
||||||
tokens = helpers.tokenizeBits(tokens);
|
tokens = bits_helpers.tokenizeBits(tokens);
|
||||||
|
|
||||||
|
// For Later
|
||||||
|
//if ( helpers && helpers.tokenizeRichContent )
|
||||||
|
// tokens = helpers.tokenizeRichContent(tokens, tags.content, delete_links);
|
||||||
|
|
||||||
if ( helpers && helpers.linkifyMessage ) {
|
if ( helpers && helpers.linkifyMessage ) {
|
||||||
var labels = msgObject.labels || [],
|
var labels = msgObject.labels || [],
|
||||||
|
@ -518,18 +587,37 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, del
|
||||||
if ( user && user.login && helpers && helpers.mentionizeMessage )
|
if ( user && user.login && helpers && helpers.mentionizeMessage )
|
||||||
tokens = helpers.mentionizeMessage(tokens, user.login, from_me);
|
tokens = helpers.mentionizeMessage(tokens, user.login, from_me);
|
||||||
|
|
||||||
if ( helpers && helpers.emoticonizeMessage )
|
if ( helpers && helpers.emoticonizeMessage && this.settings.parse_emoticons )
|
||||||
tokens = helpers.emoticonizeMessage(tokens, emotes);
|
tokens = helpers.emoticonizeMessage(tokens, emotes);
|
||||||
|
|
||||||
// FrankerFaceZ Extras
|
// FrankerFaceZ Extras
|
||||||
tokens = this._remove_banned(tokens);
|
tokens = this._remove_banned(tokens);
|
||||||
|
|
||||||
|
if ( tags.bits && this.settings.collect_bits ) {
|
||||||
|
var total = 0, individuals = [];
|
||||||
|
for(var i=0; i < tokens.length; i++)
|
||||||
|
if ( tokens[i] && tokens[i].type === "bits" ) {
|
||||||
|
tokens[i].hidden = true;
|
||||||
|
total += tokens[i].amount || 0;
|
||||||
|
individuals.push(tokens[i].amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens.splice(0, 0, {
|
||||||
|
type: "bits",
|
||||||
|
amount: total,
|
||||||
|
individuals: individuals,
|
||||||
|
length: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( this.settings.parse_emoticons && this.settings.parse_emoticons !== 2 )
|
||||||
tokens = this.tokenize_emotes(from_user, room_id, tokens, from_me);
|
tokens = this.tokenize_emotes(from_user, room_id, tokens, from_me);
|
||||||
|
|
||||||
if ( this.settings.parse_emoji )
|
if ( this.settings.parse_emoji )
|
||||||
tokens = this.tokenize_emoji(tokens);
|
tokens = this.tokenize_emoji(tokens);
|
||||||
|
|
||||||
// Capitalization
|
// Capitalization
|
||||||
var display = msgObject.tags && msgObject.tags['display-name'];
|
var display = tags['display-name'];
|
||||||
if ( display && display.length )
|
if ( display && display.length )
|
||||||
FFZ.capitalization[from_user] = [display.trim(), Date.now()];
|
FFZ.capitalization[from_user] = [display.trim(), Date.now()];
|
||||||
|
|
||||||
|
@ -634,7 +722,7 @@ FFZ.prototype.tokenize_line = function(user, room, message, no_emotes, no_emoji)
|
||||||
message = helpers.mentionizeMessage(message, u.login, user === u.login);
|
message = helpers.mentionizeMessage(message, u.login, user === u.login);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! no_emotes )
|
if ( ! no_emotes && this.settings.parse_emoticons && this.settings.parse_emoticons !== 2 )
|
||||||
message = this.tokenize_emotes(user, room, message);
|
message = this.tokenize_emotes(user, room, message);
|
||||||
|
|
||||||
if ( this.settings.parse_emoji && ! no_emoji )
|
if ( this.settings.parse_emoji && ! no_emoji )
|
||||||
|
@ -653,7 +741,7 @@ FFZ.prototype.tokenize_feed_body = function(message, emotes, user_id, room_id) {
|
||||||
if ( helpers && helpers.linkifyMessage )
|
if ( helpers && helpers.linkifyMessage )
|
||||||
message = helpers.linkifyMessage(message);
|
message = helpers.linkifyMessage(message);
|
||||||
|
|
||||||
if ( helpers && helpers.emoticonizeMessage )
|
if ( helpers && helpers.emoticonizeMessage && this.settings.parse_emoticons )
|
||||||
message = helpers.emoticonizeMessage(message, emotes);
|
message = helpers.emoticonizeMessage(message, emotes);
|
||||||
|
|
||||||
// Tokenize Lines
|
// Tokenize Lines
|
||||||
|
@ -680,6 +768,7 @@ FFZ.prototype.tokenize_feed_body = function(message, emotes, user_id, room_id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( this.settings.parse_emoticons && this.settings.parse_emoticons !== 2 )
|
||||||
tokens = this.tokenize_emotes(user_id, room_id, tokens)
|
tokens = this.tokenize_emotes(user_id, room_id, tokens)
|
||||||
|
|
||||||
if ( this.settings.parse_emoji )
|
if ( this.settings.parse_emoji )
|
||||||
|
@ -689,7 +778,7 @@ FFZ.prototype.tokenize_feed_body = function(message, emotes, user_id, room_id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype.render_token = function(render_links, warn_links, token) {
|
FFZ.prototype.render_token = function(render_links, warn_links, render_bits, token) {
|
||||||
if ( ! token )
|
if ( ! token )
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
|
@ -764,7 +853,24 @@ FFZ.prototype.render_token = function(render_links, warn_links, token) {
|
||||||
if (!( this._link_data && this._link_data[href] )) {
|
if (!( this._link_data && this._link_data[href] )) {
|
||||||
this._link_data = this._link_data || {};
|
this._link_data = this._link_data || {};
|
||||||
this._link_data[href] = true;
|
this._link_data[href] = true;
|
||||||
this.ws_send("get_link", href, load_link_data.bind(this, href));
|
|
||||||
|
var success = load_link_data.bind(this, href),
|
||||||
|
clip_info = CLIP_URL.exec(href);
|
||||||
|
|
||||||
|
if ( clip_info ) {
|
||||||
|
var clips = utils.ember_lookup('service:clips');
|
||||||
|
clips && clips.getClipInfo(clip_info[1], clip_info[2]).then(function(data) {
|
||||||
|
success(true, {
|
||||||
|
image: data.previewImage,
|
||||||
|
image_iframe: false,
|
||||||
|
html: '<span class="ffz-clip-title">' + utils.sanitize(data.title) + '</span>' +
|
||||||
|
'Channel: ' + utils.sanitize(data.broadcasterDisplayName) +
|
||||||
|
'<br>Game: ' + utils.sanitize(data.game)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
} else
|
||||||
|
this.ws_send("get_link", href, success);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -784,6 +890,14 @@ FFZ.prototype.render_token = function(render_links, warn_links, token) {
|
||||||
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>';
|
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 === "bits" ) {
|
||||||
|
var tier = render_bits && bits_service.ffz_get_tier(token.amount) || [null, null];
|
||||||
|
if ( ! tier[1] )
|
||||||
|
return 'cheer' + token.amount;
|
||||||
|
|
||||||
|
return '<span class="emoticon ffz-bit ffz-tooltip bit-tier-' + tier[0] + '"' + (token.individuals ? ' data-individuals="' + utils.quote_attr(JSON.stringify(token.individuals)) + '"' : '') + ' data-amount="' + utils.number_commas(token.amount) + '" alt="cheer' + token.amount + '"></span>';
|
||||||
|
}
|
||||||
|
|
||||||
else if ( token.type === "deleted" )
|
else if ( token.type === "deleted" )
|
||||||
return '<span class="deleted-word html-tooltip" title="' + utils.quote_san(token.text) + '" data-text="' + utils.sanitize(token.text) + '">×××</span>';
|
return '<span class="deleted-word html-tooltip" title="' + utils.quote_san(token.text) + '" data-text="' + utils.sanitize(token.text) + '">×××</span>';
|
||||||
//return `<span class="deleted-word html-tooltip" title="${utils.quote_attr(token.text)}" data-text="${utils.sanitize(token.text)}">×××</span>`;
|
//return `<span class="deleted-word html-tooltip" title="${utils.quote_attr(token.text)}" data-text="${utils.sanitize(token.text)}">×××</span>`;
|
||||||
|
@ -796,15 +910,15 @@ FFZ.prototype.render_token = function(render_links, warn_links, token) {
|
||||||
return utils.sanitize(token.text);
|
return utils.sanitize(token.text);
|
||||||
|
|
||||||
else if ( typeof token !== "string" )
|
else if ( typeof token !== "string" )
|
||||||
return '<b class="html-tooltip" title="<div style="text-align:left">' + utils.quote_attr(JSON.stringify(token,null,2)) + '</div>">[invalid token]</b>';
|
return '<b class="html-tooltip" title="<div style="text-align:left">' + utils.quote_attr(JSON.stringify(token,null,2)) + '</div>">[unknown token]</b>';
|
||||||
//return `<b class="html-tooltip" title="<div style="text-align:left">${utils.quote_attr(JSON.stringify(token,null,2))}</div>">[invalid token]</b>`;
|
//return `<b class="html-tooltip" title="<div style="text-align:left">${utils.quote_attr(JSON.stringify(token,null,2))}</div>">[unknown token]</b>`;
|
||||||
|
|
||||||
return utils.sanitize(token);
|
return utils.sanitize(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype.render_tokens = function(tokens, render_links, warn_links) {
|
FFZ.prototype.render_tokens = function(tokens, render_links, warn_links, render_bits) {
|
||||||
return _.map(tokens, this.render_token.bind(this, render_links, warn_links)).join("");
|
return _.map(tokens, this.render_token.bind(this, render_links, warn_links, render_bits)).join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1100,13 +1214,15 @@ FFZ.prototype._deleted_link_click = function(e) {
|
||||||
// History Loading
|
// History Loading
|
||||||
// ---------------------
|
// ---------------------
|
||||||
|
|
||||||
FFZ.prototype.parse_history = function(history, purged, room_id, delete_links, tmiSession, per_line) {
|
FFZ.prototype.parse_history = function(history, purged, bad_ids, room_id, delete_links, tmiSession, per_line) {
|
||||||
var i = history.length, was_cleared = false;
|
var i = history.length, was_cleared = false;
|
||||||
purged = purged || {};
|
purged = purged || {};
|
||||||
|
bad_ids = bad_ids || {};
|
||||||
|
|
||||||
while(i--) {
|
while(i--) {
|
||||||
var msg = history[i],
|
var msg = history[i],
|
||||||
is_deleted = msg.ffz_deleted = purged[msg.from] || false;
|
msg_id = msg.tags && msg.tags.id,
|
||||||
|
is_deleted = msg.ffz_deleted = purged[msg.from] || (msg_id && bad_ids[msg_id]) || false;
|
||||||
|
|
||||||
if ( is_deleted && ! this.settings.prevent_clear )
|
if ( is_deleted && ! this.settings.prevent_clear )
|
||||||
msg.deleted = true;
|
msg.deleted = true;
|
||||||
|
@ -1159,8 +1275,17 @@ FFZ.prototype.parse_history = function(history, purged, room_id, delete_links, t
|
||||||
if ( msg.tags && msg.tags.target === '@@' )
|
if ( msg.tags && msg.tags.target === '@@' )
|
||||||
was_cleared = true;
|
was_cleared = true;
|
||||||
|
|
||||||
else if ( msg.tags && msg.tags.target )
|
else if ( msg.tags && msg.tags.target ) {
|
||||||
|
var ban_reason = msg.tags && msg.tags['ban-reason'],
|
||||||
|
ban_id = ban_reason && constants.UUID_TEST.exec(ban_reason);
|
||||||
|
|
||||||
|
if ( ban_id ) {
|
||||||
|
bad_ids[ban_id[1]] = true;
|
||||||
|
ban_reason = ban_reason.substr(0, ban_reason.length - ban_id[0].length);
|
||||||
|
msg.tags['ban-reason'] = ban_reason ? ban_reason : undefined;
|
||||||
|
} else
|
||||||
purged[msg.tags.target] = true;
|
purged[msg.tags.target] = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Per-line
|
// Per-line
|
||||||
if ( per_line && ! per_line(msg) )
|
if ( per_line && ! per_line(msg) )
|
||||||
|
|
|
@ -131,6 +131,10 @@ var update_player_stats = function(player, container) {
|
||||||
if ( ! player_data )
|
if ( ! player_data )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
player_data.backend = player.getBackend();
|
||||||
|
} catch(err) { player_data.backend = undefined }
|
||||||
|
|
||||||
var sorted_keys = Object.keys(player_data).sort();
|
var sorted_keys = Object.keys(player_data).sort();
|
||||||
for(var i=0; i < sorted_keys.length; i++) {
|
for(var i=0; i < sorted_keys.length; i++) {
|
||||||
var key = sorted_keys[i],
|
var key = sorted_keys[i],
|
||||||
|
@ -309,6 +313,9 @@ FFZ.menu_pages.about = {
|
||||||
['Deploy Flavor', SiteOptions.deploy_flavor]
|
['Deploy Flavor', SiteOptions.deploy_flavor]
|
||||||
],
|
],
|
||||||
|
|
||||||
|
exp_head = createElement('div'),
|
||||||
|
experiments = createElement('ul'),
|
||||||
|
|
||||||
has_memory = window.performance && performance.memory,
|
has_memory = window.performance && performance.memory,
|
||||||
mem_head = createElement('div'),
|
mem_head = createElement('div'),
|
||||||
mem_list = createElement('ul'),
|
mem_list = createElement('ul'),
|
||||||
|
@ -346,8 +353,8 @@ FFZ.menu_pages.about = {
|
||||||
heading.className = 'chat-menu-content center';
|
heading.className = 'chat-menu-content center';
|
||||||
heading.innerHTML = '<h1>FrankerFaceZ</h1><div class="ffz-about-subheading">woofs for nerds</div>';
|
heading.innerHTML = '<h1>FrankerFaceZ</h1><div class="ffz-about-subheading">woofs for nerds</div>';
|
||||||
|
|
||||||
info_head.className = mem_head.className = twitch_head.className = player_head.className = ver_head.className = log_head.className = 'list-header';
|
info_head.className = exp_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.className = mem_list.className = twitch.className = experiments.className = player_list.className = vers.className = 'chat-menu-content menu-side-padding version-list';
|
||||||
|
|
||||||
info_head.innerHTML = 'Client Status';
|
info_head.innerHTML = 'Client Status';
|
||||||
|
|
||||||
|
@ -394,6 +401,21 @@ FFZ.menu_pages.about = {
|
||||||
twitch.appendChild(line);
|
twitch.appendChild(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var exp_service = utils.ember_lookup('service:experiments');
|
||||||
|
if ( exp_service ) {
|
||||||
|
exp_head.innerHTML = 'Twitch Experiments';
|
||||||
|
for(var key in exp_service.values) {
|
||||||
|
if ( ! exp_service.values.hasOwnProperty(key) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var val = exp_service.values[key],
|
||||||
|
line = createElement('li');
|
||||||
|
|
||||||
|
line.innerHTML = key + '<span>' + utils.sanitize(val) + '</span>';
|
||||||
|
experiments.appendChild(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ver_head.innerHTML = 'Versions';
|
ver_head.innerHTML = 'Versions';
|
||||||
|
|
||||||
if ( this.has_bttv )
|
if ( this.has_bttv )
|
||||||
|
@ -431,6 +453,11 @@ FFZ.menu_pages.about = {
|
||||||
container.appendChild(twitch_head);
|
container.appendChild(twitch_head);
|
||||||
container.appendChild(twitch);
|
container.appendChild(twitch);
|
||||||
|
|
||||||
|
if ( exp_service ) {
|
||||||
|
container.appendChild(exp_head);
|
||||||
|
container.appendChild(experiments);
|
||||||
|
}
|
||||||
|
|
||||||
if ( has_memory ) {
|
if ( has_memory ) {
|
||||||
mem_head.innerHTML = 'Memory Statistics';
|
mem_head.innerHTML = 'Memory Statistics';
|
||||||
setTimeout(update_mem_stats.bind(this,mem_list),0);
|
setTimeout(update_mem_stats.bind(this,mem_list),0);
|
||||||
|
|
|
@ -73,7 +73,7 @@ FFZ.prototype.setup_following_count = function(has_ember) {
|
||||||
return this._following_get_me();
|
return this._following_get_me();
|
||||||
|
|
||||||
this.log("Connecting to Live Streams model.");
|
this.log("Connecting to Live Streams model.");
|
||||||
var Stream = utils.ember_resolve('model:stream');
|
var Stream = utils.ember_resolve('model:deprecated-stream');
|
||||||
if ( ! Stream )
|
if ( ! Stream )
|
||||||
return this.log("Unable to find Stream model.");
|
return this.log("Unable to find Stream model.");
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,15 @@ FFZ.prototype.fix_tooltips = function() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix tipsy invalidation
|
||||||
|
if ( window.jQuery && jQuery.fn && jQuery.fn.tipsy )
|
||||||
|
jQuery.fn.tipsy.revalidate = function() {
|
||||||
|
jQuery(".tipsy").each(function() {
|
||||||
|
var t = jQuery.data(this, "tipsy-pointee");
|
||||||
|
(!t || !t[0] || !document.contains(t[0])) && jQuery(this).remove();
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
// Iterate all existing tipsy stuff~!
|
// Iterate all existing tipsy stuff~!
|
||||||
this.log('Fixing already existing tooltips.');
|
this.log('Fixing already existing tooltips.');
|
||||||
if ( ! window.jQuery || ! jQuery.cache )
|
if ( ! window.jQuery || ! jQuery.cache )
|
||||||
|
|
130
src/utils.js
130
src/utils.js
|
@ -2,7 +2,20 @@ var FFZ = window.FrankerFaceZ,
|
||||||
constants = require('./constants');
|
constants = require('./constants');
|
||||||
|
|
||||||
|
|
||||||
var sanitize_el = document.createElement('span'),
|
var createElement = function(tag, className, content) {
|
||||||
|
var out = document.createElement(tag);
|
||||||
|
if ( className )
|
||||||
|
out.className = className;
|
||||||
|
if ( content )
|
||||||
|
if ( content.nodeType )
|
||||||
|
out.appendChild(content);
|
||||||
|
else
|
||||||
|
out.innerHTML = content;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
},
|
||||||
|
|
||||||
|
sanitize_el = createElement('span'),
|
||||||
|
|
||||||
sanitize = function(msg) {
|
sanitize = function(msg) {
|
||||||
sanitize_el.textContent = msg;
|
sanitize_el.textContent = msg;
|
||||||
|
@ -206,25 +219,18 @@ var sanitize_el = document.createElement('span'),
|
||||||
|
|
||||||
// Dialogs
|
// Dialogs
|
||||||
show_modal = function(contents, on_close, width) {
|
show_modal = function(contents, on_close, width) {
|
||||||
var container = document.createElement('div'),
|
var container = createElement('div', 'twitch_subwindow_container'),
|
||||||
subwindow = document.createElement('div'),
|
subwindow = createElement('div', 'twitch_subwindow ffz-subwindow'),
|
||||||
card = document.createElement('div'),
|
card = createElement('div', 'card'),
|
||||||
close_button = document.createElement('div'),
|
close_button = createElement('div', 'modal-close-button', constants.CLOSE),
|
||||||
|
|
||||||
closer = function() { container.parentElement.removeChild(container) };
|
closer = function() { container.parentElement.removeChild(container) };
|
||||||
|
|
||||||
container.className = 'twitch_subwindow_container';
|
|
||||||
container.id = 'ffz-modal-container';
|
container.id = 'ffz-modal-container';
|
||||||
|
|
||||||
subwindow.className = 'twitch_subwindow ffz-subwindow';
|
|
||||||
subwindow.style.width = '100%';
|
subwindow.style.width = '100%';
|
||||||
subwindow.style.maxWidth = (width||420) + 'px';
|
subwindow.style.maxWidth = (width||420) + 'px';
|
||||||
|
|
||||||
card.className = 'card';
|
|
||||||
|
|
||||||
close_button.className = 'modal-close-button';
|
|
||||||
close_button.innerHTML = constants.CLOSE;
|
|
||||||
|
|
||||||
close_button.addEventListener('click', function() {
|
close_button.addEventListener('click', function() {
|
||||||
closer();
|
closer();
|
||||||
if ( on_close )
|
if ( on_close )
|
||||||
|
@ -265,6 +271,7 @@ var sanitize_el = document.createElement('span'),
|
||||||
|
|
||||||
|
|
||||||
module.exports = FFZ.utils = {
|
module.exports = FFZ.utils = {
|
||||||
|
// Ember Manipulation
|
||||||
ember_views: function() {
|
ember_views: function() {
|
||||||
return ember_lookup('-view-registry:main') || {};
|
return ember_lookup('-view-registry:main') || {};
|
||||||
},
|
},
|
||||||
|
@ -281,6 +288,38 @@ module.exports = FFZ.utils = {
|
||||||
return App.__container__.resolve(thing);
|
return App.__container__.resolve(thing);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ember_reopen_view: function(component, data) {
|
||||||
|
if ( typeof component === 'string' )
|
||||||
|
component = ember_resolve(component);
|
||||||
|
|
||||||
|
data.ffz_modified = true;
|
||||||
|
|
||||||
|
if ( data.ffz_init && ! data.didInsertElement )
|
||||||
|
data.didInsertElement = function() {
|
||||||
|
this._super();
|
||||||
|
try {
|
||||||
|
this.ffz_init();
|
||||||
|
} catch(err) {
|
||||||
|
FFZ.get().error("An error occured running ffz_init on " + this.toString(), err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( data.ffz_destroy && ! data.willClearRender )
|
||||||
|
data.willClearRender = function() {
|
||||||
|
try {
|
||||||
|
this.ffz_destroy();
|
||||||
|
} catch(err) {
|
||||||
|
FFZ.get().error("An error occured running ffz_destroy on " + this.toString(), err);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._super();
|
||||||
|
};
|
||||||
|
|
||||||
|
return component.reopen(data);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Other Stuff
|
||||||
|
|
||||||
build_srcset: build_srcset,
|
build_srcset: build_srcset,
|
||||||
/*build_tooltip: build_tooltip,
|
/*build_tooltip: build_tooltip,
|
||||||
load_emote_data: load_emote_data,*/
|
load_emote_data: load_emote_data,*/
|
||||||
|
@ -294,18 +333,52 @@ module.exports = FFZ.utils = {
|
||||||
|
|
||||||
|
|
||||||
show_modal: show_modal,
|
show_modal: show_modal,
|
||||||
|
confirm: function(title, description, callback) {
|
||||||
|
var contents = createElement('div', 'text-content'),
|
||||||
|
heading = title ? createElement('div', 'content-header', '<h4>' + title + '</h4>') : null,
|
||||||
|
body = createElement('div', 'item'),
|
||||||
|
buttons = createElement('div', 'buttons', '<a class="js-subwindow-close button"><span>Cancel</span></a><button class="button primary" type="submit"><span>OK</span></button>'),
|
||||||
|
|
||||||
|
close_btn = buttons.querySelector('.js-subwindow-close'),
|
||||||
|
okay_btn = buttons.querySelector('.button.primary');
|
||||||
|
|
||||||
|
if ( heading )
|
||||||
|
contents.appendChild(heading);
|
||||||
|
|
||||||
|
if ( description ) {
|
||||||
|
if ( description.nodeType )
|
||||||
|
body.appendChild(description);
|
||||||
|
else
|
||||||
|
body.innerHTML = '<p>' + description + '</p>';
|
||||||
|
|
||||||
|
contents.appendChild(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
contents.appendChild(buttons);
|
||||||
|
|
||||||
|
var closer,
|
||||||
|
cb = function(success) {
|
||||||
|
closer();
|
||||||
|
if ( ! callback )
|
||||||
|
return;
|
||||||
|
|
||||||
|
callback(success);
|
||||||
|
};
|
||||||
|
|
||||||
|
closer = show_modal(contents, cb);
|
||||||
|
|
||||||
|
okay_btn.addEventListener('click', function(e) { e.preventDefault(); cb(true); return false });
|
||||||
|
close_btn.addEventListener('click', function(e) { e.preventDefault(); cb(false); return false });
|
||||||
|
},
|
||||||
|
|
||||||
prompt: function(title, description, old_value, callback, width, input) {
|
prompt: function(title, description, old_value, callback, width, input) {
|
||||||
var contents = document.createElement('div'),
|
var contents = createElement('div', 'text-content'),
|
||||||
heading = document.createElement('div'),
|
heading = createElement('div', 'content-header', '<h4>' + title + '</h4>'),
|
||||||
form = document.createElement('form'),
|
form = createElement('form'),
|
||||||
close_btn, okay_btn;
|
close_btn, okay_btn;
|
||||||
|
|
||||||
contents.className = 'text-content';
|
|
||||||
heading.className = 'content-header';
|
|
||||||
heading.innerHTML = '<h4>' + title + '</h4>';
|
|
||||||
|
|
||||||
if ( ! input ) {
|
if ( ! input ) {
|
||||||
input = document.createElement('input');
|
input = createElement('input');
|
||||||
input.type = 'text';
|
input.type = 'text';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,18 +613,19 @@ module.exports = FFZ.utils = {
|
||||||
|
|
||||||
escape_regex: escape_regex,
|
escape_regex: escape_regex,
|
||||||
|
|
||||||
createElement: function(tag, className, content) {
|
createElement: createElement,
|
||||||
var out = document.createElement(tag);
|
|
||||||
if ( className )
|
|
||||||
out.className = className;
|
|
||||||
if ( content )
|
|
||||||
out.innerHTML = content;
|
|
||||||
return out;
|
|
||||||
},
|
|
||||||
|
|
||||||
toggle_cls: function(cls) {
|
toggle_cls: function(cls) {
|
||||||
return function(val) {
|
return function(val) {
|
||||||
document.body.classList.toggle(cls, val);
|
document.body.classList.toggle(cls, val);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
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." + klass + ",.ffz-transparent-badges .badges ." + klass + ' { background-image: url("' + badge.alpha_image + '"); }';
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
}
|
}
|
197
style.css
197
style.css
|
@ -321,10 +321,6 @@ body.ffz-bttv-dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill:
|
||||||
background-color: #25252a;
|
background-color: #25252a;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ffz-theater-stats .app-main.theatre .button:not(.primary) {
|
|
||||||
color: #a68ed2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ffz-theater-stats .app-main.theatre .button.button--icon-only svg path {
|
.ffz-theater-stats .app-main.theatre .button.button--icon-only svg path {
|
||||||
fill: #a68ed2;
|
fill: #a68ed2;
|
||||||
}
|
}
|
||||||
|
@ -501,6 +497,11 @@ body.ffz-bttv-dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill:
|
||||||
border-top-color: rgba(255,255,255, 0.2);
|
border-top-color: rgba(255,255,255, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ffz-dark .ffz-ui-menu-page .ffz-filter-container,
|
||||||
|
.theatre .ffz-ui-menu-page .ffz-filter-container,
|
||||||
|
.dark .ffz-ui-menu-page .ffz-filter-container,
|
||||||
|
.force-dark .ffz-ui-menu-page .ffz-filter-container,
|
||||||
|
|
||||||
.ffz-dark .chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading,
|
.ffz-dark .chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading,
|
||||||
.theatre .chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading,
|
.theatre .chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading,
|
||||||
.dark .chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading,
|
.dark .chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content .heading,
|
||||||
|
@ -598,17 +599,18 @@ body.ffz-bttv-dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill:
|
||||||
|
|
||||||
.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content.menu-side-padding { padding-left: 20px; padding-right: 20px; }
|
.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content.menu-side-padding { padding-left: 20px; padding-right: 20px; }
|
||||||
|
|
||||||
.emoticon-grid.collapsed span,
|
.emoticon-grid.collapsable.collapsed span,
|
||||||
.chat-menu-content.collapsed p { display: none; }
|
.chat-menu-content.collapsable.collapsed p { display: none; }
|
||||||
|
|
||||||
.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content.collapsed .heading,
|
.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content.collapsable.collapsed .heading,
|
||||||
.chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid.collapsed .heading {
|
.chat-menu.ffz-ui-popup .ffz-ui-menu-page .emoticon-grid.collapsable.collapsed .heading {
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.emoticon-grid.collapsable .heading,
|
.emoticon-grid.collapsable .heading,
|
||||||
.emoticon-grid.collapsed,
|
.emoticon-grid.collapsable.collapsed,
|
||||||
.chat-menu-content.collapsed {
|
.chat-menu-content.collapsable.collapsed,
|
||||||
|
.chat-menu-content.collapsable .heading {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -617,6 +619,25 @@ body.ffz-bttv-dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill:
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pin-switch {
|
||||||
|
display: block;
|
||||||
|
height: 16px;
|
||||||
|
padding: 2px;
|
||||||
|
margin: 0 !important;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pin-switch:hover svg path,
|
||||||
|
.pin-switch.active svg path { fill: #14b866 !important }
|
||||||
|
.pin-switch.active:hover svg path { fill: #fc3636 !important }
|
||||||
|
|
||||||
|
.pin-switch svg path { fill: rgba(0,0,0,0.2); }
|
||||||
|
|
||||||
|
.dark .pin-switch svg path,
|
||||||
|
.force-dark .pin-switch svg path,
|
||||||
|
.theatre .dark .pin-switch svg path { fill: rgba(255,255,255,0.2) }
|
||||||
|
|
||||||
|
.pin-switch,
|
||||||
.list-header span.right { float: right; }
|
.list-header span.right { float: right; }
|
||||||
|
|
||||||
.ember-chat .chat-menu .list-header.sub-header {
|
.ember-chat .chat-menu .list-header.sub-header {
|
||||||
|
@ -1307,7 +1328,7 @@ img.channel_background[src="null"] { display: none; }
|
||||||
.ffz-moderation-card .right button:last-of-type,
|
.ffz-moderation-card .right button:last-of-type,
|
||||||
.ffz-moderation-card .mod-controls:last-of-type button:last-of-type { margin-right: 0 }
|
.ffz-moderation-card .mod-controls:last-of-type button:last-of-type { margin-right: 0 }
|
||||||
|
|
||||||
.ffz-moderation-card .follow-button a {
|
.ffz-moderation-card .follow-button {
|
||||||
font-size: 0 !important;
|
font-size: 0 !important;
|
||||||
padding-right: 0 !important;
|
padding-right: 0 !important;
|
||||||
}
|
}
|
||||||
|
@ -1413,6 +1434,8 @@ img.channel_background[src="null"] { display: none; }
|
||||||
|
|
||||||
/* Chat Rows */
|
/* Chat Rows */
|
||||||
|
|
||||||
|
.chat-line { overflow: hidden }
|
||||||
|
|
||||||
.theatre .conversation-window .conversation-chat-line,
|
.theatre .conversation-window .conversation-chat-line,
|
||||||
.dark .chat-line,
|
.dark .chat-line,
|
||||||
.force-dark .chat-line,
|
.force-dark .chat-line,
|
||||||
|
@ -1456,6 +1479,7 @@ body:not(.ffz-bttv) .chat-container:not(.chatReplay) .more-messages-indicator {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Emoticon Tooltips */
|
/* Emoticon Tooltips */
|
||||||
|
|
||||||
.ffz-wide-tip hr {
|
.ffz-wide-tip hr {
|
||||||
|
@ -2170,6 +2194,14 @@ body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-inter
|
||||||
.ffz-no-blue .theatre .conversation-system-message,
|
.ffz-no-blue .theatre .conversation-system-message,
|
||||||
.ffz-no-blue.ffz-dark .conversation-system-message,
|
.ffz-no-blue.ffz-dark .conversation-system-message,
|
||||||
|
|
||||||
|
.ffz-no-blue .theatre .bits-card,
|
||||||
|
.ffz-no-blue .dark .bits-card,
|
||||||
|
.ffz-no-blue .force-dark .bits-card,
|
||||||
|
|
||||||
|
.ffz-no-blue .theatre .bits-card--standard,
|
||||||
|
.ffz-no-blue .dark .bits-card--standard,
|
||||||
|
.ffz-no-blue .force-dark .bits-card--standard,
|
||||||
|
|
||||||
.ffz-no-blue .warp,
|
.ffz-no-blue .warp,
|
||||||
.ffz-no-blue #large_nav .content,
|
.ffz-no-blue #large_nav .content,
|
||||||
.ffz-no-blue #small_nav .content,
|
.ffz-no-blue #small_nav .content,
|
||||||
|
@ -2370,6 +2402,14 @@ li[data-name="following"] a {
|
||||||
|
|
||||||
/* Image Tooltips */
|
/* Image Tooltips */
|
||||||
|
|
||||||
|
.ffz-clip-title {
|
||||||
|
display: block;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.ffz-image-hover {
|
.ffz-image-hover {
|
||||||
border:none;
|
border:none;
|
||||||
max-width: 186px;
|
max-width: 186px;
|
||||||
|
@ -2802,14 +2842,17 @@ body:not(.ffz-top-conversations) .conversations-list-bottom-bar {
|
||||||
|
|
||||||
/* Creative Directory */
|
/* Creative Directory */
|
||||||
|
|
||||||
.ffz-top-conversations .ct-banner { margin-top: -50px }
|
/* Make sure the fancy banner art goes all the way up */
|
||||||
.ffz-top-conversations .ct-banner__feature { top: 40px; margin-bottom: 0 }
|
.ffz-top-conversations .ct-banner-container { margin-top: -50px }
|
||||||
|
|
||||||
body:not(.ffz-tags-on-channel) #broadcast-meta .ct-tags,
|
|
||||||
body:not(.ffz-creative-showcase) .ct-gallery { display: none; }
|
|
||||||
|
|
||||||
body:not(.ffz-tags-on-channel) .tw-title--tall { height: 60px }
|
body:not(.ffz-tags-on-channel) .tw-title--tall { height: 60px }
|
||||||
|
|
||||||
|
body:not(.ffz-tags-on-channel) #broadcast-meta .ct-tags,
|
||||||
|
/*body:not(.ffz-creative-showcase) .ct-banner-handler .tower > div:last-child,*/
|
||||||
|
body:not(.ffz-creative-showcase) .ct-spotlight-container { display: none; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Content-Box~! Down with Twitch randomly changing the box-sizing for everything! */
|
/* Content-Box~! Down with Twitch randomly changing the box-sizing for everything! */
|
||||||
|
|
||||||
#ffz-channel-table *,
|
#ffz-channel-table *,
|
||||||
|
@ -2874,33 +2917,42 @@ body:not([data-current-path^="directory.csgo"]):not([data-current-path^="directo
|
||||||
background-size: cover !important;
|
background-size: cover !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.follow-button.ffz-block-button {
|
.directory_header .ffz-block-button,
|
||||||
margin-left: 2px;
|
.directory_header .ffz-spoiler-button {
|
||||||
|
margin-left: 1rem;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.balloon .balloon__title button {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.balloon .balloon__title button:not(:last-of-type) {
|
||||||
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
body[data-current-path^="directory.creative"] .follow-button.ffz-block-button {
|
body[data-current-path^="directory.creative"] .follow-button.ffz-block-button {
|
||||||
margin: 0 1rem;
|
margin: 0 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.follow-button.ffz-spoiler-button .spoiler,
|
.button.ffz-spoiler-button,
|
||||||
.follow-button.ffz-block-button .block {
|
.button.ffz-block-button {
|
||||||
background: #555;
|
background: #555;
|
||||||
padding: 0 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.follow-button.ffz-spoiler-button .spoiler.active {
|
.button.ffz-spoiler-button.active {
|
||||||
background: #006700;
|
background: #006700;
|
||||||
}
|
}
|
||||||
|
|
||||||
.follow-button.ffz-spoiler-button .spoiler:not(.disabled):hover {
|
.button.ffz-spoiler-button:not(.disabled):hover {
|
||||||
background: #247324;
|
background: #247324;
|
||||||
}
|
}
|
||||||
|
|
||||||
.follow-button.ffz-block-button .block.active {
|
.button.ffz-block-button.active {
|
||||||
background: #973333;
|
background: #973333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.follow-button.ffz-block-button .block:not(.disabled):hover {
|
.button.ffz-block-button:not(.disabled):hover {
|
||||||
background: #a94444;
|
background: #a94444;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2946,6 +2998,8 @@ body.ffz-bttv #ffz-feed-tabs .tabs { margin-bottom: 0 }
|
||||||
|
|
||||||
/* Badges */
|
/* Badges */
|
||||||
|
|
||||||
|
.badges .badge { background-size: 18px 18px }
|
||||||
|
|
||||||
/*.badges .badge {
|
/*.badges .badge {
|
||||||
height: 18px;
|
height: 18px;
|
||||||
min-width: 18px;
|
min-width: 18px;
|
||||||
|
@ -3001,18 +3055,41 @@ body.ffz-bttv #ffz-feed-tabs .tabs { margin-bottom: 0 }
|
||||||
/* Odd Badges */
|
/* Odd Badges */
|
||||||
.badge.click_url { cursor: pointer }
|
.badge.click_url { cursor: pointer }
|
||||||
|
|
||||||
.badge.warcraft.version-alliance {
|
.badge.bits.version-1 {
|
||||||
background: url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/1.png") #004094;
|
background: url("https://cdn.frankerfacez.com/badges/twitch/bits/1/1.png") #cbc8d0;
|
||||||
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: -webkit-image-set(url("https://cdn.frankerfacez.com/badges/twitch/bits/1/1.png") 1x, url("https://cdn.frankerfacez.com/badges/twitch/bits/1/2.png") 2x, url("https://cdn.frankerfacez.com/badges/twitch/bits/1/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);
|
background-image: image-set(url("https://cdn.frankerfacez.com/badges/twitch/bits/1/1.png") 1x, url("https://cdn.frankerfacez.com/badges/twitch/bits/1/2.png") 2x, url("https://cdn.frankerfacez.com/badges/twitch/bits/1/4.png") 4x);
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge.warcraft.version-horde {
|
.badge.bits.version-100 {
|
||||||
background: url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/1.png") #ab0016;
|
background: url("https://cdn.frankerfacez.com/badges/twitch/bits/100/1.png") #ca7eff;
|
||||||
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: -webkit-image-set(url("https://cdn.frankerfacez.com/badges/twitch/bits/100/1.png") 1x, url("https://cdn.frankerfacez.com/badges/twitch/bits/100/2.png") 2x, url("https://cdn.frankerfacez.com/badges/twitch/bits/100/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);
|
background-image: image-set(url("https://cdn.frankerfacez.com/badges/twitch/bits/100/1.png") 1x, url("https://cdn.frankerfacez.com/badges/twitch/bits/100/2.png") 2x, url("https://cdn.frankerfacez.com/badges/twitch/bits/100/4.png") 4x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge.bits.version-1000 {
|
||||||
|
background: url("https://cdn.frankerfacez.com/badges/twitch/bits/1000/1.png") #3ed8b3;
|
||||||
|
background-image: -webkit-image-set(url("https://cdn.frankerfacez.com/badges/twitch/bits/1000/1.png") 1x, url("https://cdn.frankerfacez.com/badges/twitch/bits/1000/2.png") 2x, url("https://cdn.frankerfacez.com/badges/twitch/bits/1000/4.png") 4x);
|
||||||
|
background-image: image-set(url("https://cdn.frankerfacez.com/badges/twitch/bits/1000/1.png") 1x, url("https://cdn.frankerfacez.com/badges/twitch/bits/1000/2.png") 2x, url("https://cdn.frankerfacez.com/badges/twitch/bits/1000/4.png") 4x);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge.bits.version-5000 {
|
||||||
|
background: url("https://cdn.frankerfacez.com/badges/twitch/bits/5000/1.png") #49acff;
|
||||||
|
background-image: -webkit-image-set(url("https://cdn.frankerfacez.com/badges/twitch/bits/5000/1.png") 1x, url("https://cdn.frankerfacez.com/badges/twitch/bits/5000/2.png") 2x, url("https://cdn.frankerfacez.com/badges/twitch/bits/5000/4.png") 4x);
|
||||||
|
background-image: image-set(url("https://cdn.frankerfacez.com/badges/twitch/bits/5000/1.png") 1x, url("https://cdn.frankerfacez.com/badges/twitch/bits/5000/2.png") 2x, url("https://cdn.frankerfacez.com/badges/twitch/bits/5000/4.png") 4x);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge.bits.version-10000 {
|
||||||
|
background: url("https://cdn.frankerfacez.com/badges/twitch/bits/10000/1.png") #ff271e;
|
||||||
|
background-image: -webkit-image-set(url("https://cdn.frankerfacez.com/badges/twitch/bits/10000/1.png") 1x, url("https://cdn.frankerfacez.com/badges/twitch/bits/10000/2.png") 2x, url("https://cdn.frankerfacez.com/badges/twitch/bits/10000/4.png") 4x);
|
||||||
|
background-image: image-set(url("https://cdn.frankerfacez.com/badges/twitch/bits/10000/1.png") 1x, url("https://cdn.frankerfacez.com/badges/twitch/bits/10000/2.png") 2x, url("https://cdn.frankerfacez.com/badges/twitch/bits/10000/4.png") 4x);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge.bits.version-100000 {
|
||||||
|
background: url("https://cdn.frankerfacez.com/badges/twitch/bits/100000/1.png") #ffcb13;
|
||||||
|
background-image: -webkit-image-set(url("https://cdn.frankerfacez.com/badges/twitch/bits/100000/1.png") 1x, url("https://cdn.frankerfacez.com/badges/twitch/bits/100000/2.png") 2x, url("https://cdn.frankerfacez.com/badges/twitch/bits/100000/4.png") 4x);
|
||||||
|
background-image: image-set(url("https://cdn.frankerfacez.com/badges/twitch/bits/100000/1.png") 1x, url("https://cdn.frankerfacez.com/badges/twitch/bits/100000/2.png") 2x, url("https://cdn.frankerfacez.com/badges/twitch/bits/100000/4.png") 4x);
|
||||||
|
}
|
||||||
|
|
||||||
/* New Resub Banner */
|
/* New Resub Banner */
|
||||||
|
|
||||||
|
@ -3046,3 +3123,57 @@ body.ffz-bttv #ffz-feed-tabs .tabs { margin-bottom: 0 }
|
||||||
.force-dark .chat-room .show-mod-icons .chat-line:not(.admin) .mod-icons {
|
.force-dark .chat-room .show-mod-icons .chat-line:not(.admin) .mod-icons {
|
||||||
background-color: rgba(0,0,0,0.8);
|
background-color: rgba(0,0,0,0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Bits */
|
||||||
|
|
||||||
|
.bits-card { z-index: 10 }
|
||||||
|
|
||||||
|
.ffz-bit {
|
||||||
|
display: inline-block;
|
||||||
|
height: 28px;
|
||||||
|
line-height: 28px;
|
||||||
|
font-weight: bold;
|
||||||
|
padding-left: 30px;
|
||||||
|
margin: -5px 5px;
|
||||||
|
box-sizing: content-box;
|
||||||
|
background-position: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tipsy .ffz-bit {
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-bit:after {
|
||||||
|
content: attr(data-amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* New Chat Formatting */
|
||||||
|
|
||||||
|
.ember-chat .chat-messages .timestamp { margin-right: 0; }
|
||||||
|
.badges { display: inline-block }
|
||||||
|
.badges .badge {
|
||||||
|
float: none;
|
||||||
|
margin: -1px 3px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-baseline-emoticons .activity-body .emoticon,
|
||||||
|
.ffz-baseline-emoticons .chat-line .emoticon {
|
||||||
|
vertical-align: baseline;
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Settings Filtering */
|
||||||
|
|
||||||
|
.ffz-ui-menu-page .ffz-filter-container {
|
||||||
|
padding: 10px;
|
||||||
|
border-top: 1px solid rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-ui-menu-page input.js-filter-input { margin: 0 }
|
||||||
|
|
||||||
|
.bttv-incompatibility b + b:before {
|
||||||
|
content: ', ';
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue