pokemon-showdown-client/play.pokemonshowdown.com/js/client-topbar.js
Mia b698a6ef53
Some checks failed
Node.js CI / build (22.x) (push) Has been cancelled
Remove waterfall background
2025-12-17 22:30:06 -06:00

1147 lines
51 KiB
JavaScript

(function ($) {
this.Topbar = Backbone.View.extend({
events: {
'click a': 'click',
'click .username': 'clickUsername',
'click button': 'dispatchClickButton',
'dblclick button[name=openSounds]': 'toggleMute',
'dragstart .roomtab': 'dragStartRoom',
'dragend .roomtab': 'dragEndRoom',
'dragenter .roomtab': 'dragEnterRoom',
'dragover .roomtab': 'dragEnterRoom'
},
initialize: function () {
// April Fool's 2016 - Digimon Showdown
// this.$el.html('<img class="logo" src="' + Dex.resourcePrefix + 'sprites/afd/digimonshowdown.png" alt="Digimon Showdown! (beta)" width="146" height="44" /><div class="maintabbarbottom"></div><div class="tabbar maintabbar"><div class="inner"></div></div><div class="userbar"></div>');
this.$el.html('<img class="logo" src="' + Dex.resourcePrefix + 'pokemonshowdownbeta.png" srcset="' + Dex.resourcePrefix + 'pokemonshowdownbeta@2x.png 2x" alt="Pok&eacute;mon Showdown! (beta)" width="146" height="44" /><div class="maintabbarbottom"></div><div class="tabbar maintabbar"><div class="inner"></div></div><div class="userbar"></div>');
this.$tabbar = this.$('.maintabbar .inner');
// this.$sidetabbar = this.$('.sidetabbar');
this.$userbar = this.$('.userbar');
this.dragging = false;
this.updateTabbar();
app.user.on('change', this.updateUserbar, this);
this.updateUserbar();
},
// userbar
updateUserbar: function () {
var buf = '';
var name = ' ' + app.user.get('name');
var away = app.user.get('away');
var status = app.user.get('status');
var color = away ? 'color:#888;' : BattleLog.hashColor(app.user.get('userid'));
if (!app.user.loaded) {
buf = '<button disabled class="button">Loading...</button>';
} else if (app.user.get('named')) {
buf = '<span class="username" data-name="' + BattleLog.escapeHTML(name) + '"' + (away ? ' data-away="true"' : '') + (status ? 'data-status="' + BattleLog.escapeHTML(status) + '"' : '') + ' style="' + color + '"><i class="fa fa-user" style="color:' + (away ? '#888;' : '#779EC5') + '"></i> <span class="usernametext">' + BattleLog.escapeHTML(name) + '</span></span>';
} else {
buf = '<button name="login" class="button">Choose name</button>';
}
buf += ' <button class="icon button" name="openSounds" title="Sound" aria-label="Sound"><i class="' + (Dex.prefs('mute') ? 'fa fa-volume-off' : 'fa fa-volume-up') + '"></i></button> <button class="icon button" name="openOptions" title="Options" aria-label="Options"><i class="fa fa-cog"></i></button>';
this.$userbar.html(buf);
},
login: function () {
app.addPopup(LoginPopup);
},
openSounds: function () {
app.addPopup(SoundsPopup);
},
openOptions: function () {
app.addPopup(OptionsPopup);
},
clickUsername: function (e) {
e.preventDefault();
e.stopPropagation();
var name = $(e.currentTarget).data('name');
app.addPopup(UserPopup, { name: name, sourceEl: e.currentTarget });
},
toggleMute: function () {
var muted = !Dex.prefs('mute');
Storage.prefs('mute', muted);
BattleSound.setMute(muted);
app.topbar.$('button[name=openSounds]').html('<i class="' + (muted ? 'fa fa-volume-off' : 'fa fa-volume-up') + '"></i>');
},
// tabbar
renderRoomTab: function (room, id) {
if (!room && id !== 'rooms') return '';
if (!id) id = room.id;
var buf = '<li><a class="roomtab button' + (app.curRoom === room || app.curSideRoom === room ? ' cur' : '') + (room && room.notificationClass || '') + (id === '' || id === 'rooms' ? '' : ' closable') + '" href="' + app.root + id + '"';
if (room && room.notifications) {
var title = '';
for (var tag in room.notifications) {
if (room.notifications[tag].title) title += room.notifications[tag].title + '\n';
if (room.notifications[tag].body) title += room.notifications[tag].body + '\n';
}
if (title) buf += ' title="' + BattleLog.escapeHTML(title) + '"';
}
switch (room ? room.type : id) {
case '':
case 'mainmenu':
return buf + '><i class="fa fa-home"></i> <span>Home</span></a></li>';
case 'teambuilder':
return buf + '><i class="fa fa-pencil-square-o"></i> <span>Teambuilder</span></a><button class="closebutton" name="closeRoom" value="' + 'teambuilder" aria-label="Close"><i class="fa fa-times-circle"></i></button></li>';
case 'ladder':
return buf + '><i class="fa fa-list-ol"></i> <span>Ladder</span></a><button class="closebutton" name="closeRoom" value="' + 'ladder" aria-label="Close"><i class="fa fa-times-circle"></i></button></li>';
case 'resources':
return buf + '><i class="fa fa-question-circle"></i> <span>Resources</span></a><button class="closebutton" name="closeRoom" value="' + 'resources" aria-label="Close"><i class="fa fa-times-circle"></i></button></li>';
case 'battles':
return buf + '><i class="fa fa-caret-square-o-right"></i> <span>Battles</span></a><button class="closebutton" name="closeRoom" value="' + 'battles" aria-label="Close"><i class="fa fa-times-circle"></i></button></li>';
case 'rooms':
return buf + ' aria-label="Join chatroom"><i class="fa fa-plus" style="margin:7px auto -6px auto"></i> <span>&nbsp;</span></a></li>';
case 'battle':
var name = BattleLog.escapeHTML(room.title);
var offset = id.startsWith('game-') ? 5 : 7;
var idChunks = id.substr(offset).split('-');
var formatid;
if (idChunks.length <= 1) {
if (idChunks[0] === 'uploadedreplay') formatid = 'Uploaded Replay';
} else {
formatid = idChunks[0];
}
if (!name) {
var p1 = (room.battle && room.battle.p1 && room.battle.p1.name) || '';
var p2 = (room.battle && room.battle.p2 && room.battle.p2.name) || '';
if (p1 && p2) {
name = '' + BattleLog.escapeHTML(p1) + ' v. ' + BattleLog.escapeHTML(p2);
} else if (p1 || p2) {
name = '' + BattleLog.escapeHTML(p1) + BattleLog.escapeHTML(p2);
} else {
name = '(empty room)';
}
}
return buf + ' draggable="true"><i class="text">' + BattleLog.escapeFormat(formatid) + '</i><span>' + name + '</span></a><button class="closebutton" name="closeRoom" value="' + id + '" aria-label="Close"><i class="fa fa-times-circle"></i></a></li>';
case 'chat':
return buf + ' draggable="true"><i class="fa fa-comment-o"></i> <span>' + (BattleLog.escapeHTML(room.title) || (id === 'lobby' ? 'Lobby' : id)) + '</span></a><button class="closebutton" name="closeRoom" value="' + id + '" aria-label="Close"><i class="fa fa-times-circle"></i></a></li>';
case 'html':
default:
if (room.title && room.title.charAt(0) === '[') {
var closeBracketIndex = room.title.indexOf(']');
if (closeBracketIndex > 0) {
return buf + ' draggable="true"><i class="text">' + BattleLog.escapeHTML(room.title.slice(1, closeBracketIndex)) + '</i><span>' + BattleLog.escapeHTML(room.title.slice(closeBracketIndex + 1)) + '</span></a><button class="closebutton" name="closeRoom" value="' + id + '" aria-label="Close"><i class="fa fa-times-circle"></i></a></li>';
}
}
return buf + ' draggable="true"><i class="fa fa-file-text-o"></i> <span>' + (BattleLog.escapeHTML(room.title) || id) + '</span></a><button class="closebutton" name="closeRoom" value="' + id + '" aria-label="Close"><i class="fa fa-times-circle"></i></a></li>';
}
},
updateTabbar: function () {
if ($(window).width() < 420) return this.updateTabbarMini();
this.$('.logo').show();
this.$('.maintabbar').removeClass('minitabbar');
var buf = '<ul>' + (
this.renderRoomTab(app.rooms['']) +
this.renderRoomTab(app.rooms['teambuilder']) +
this.renderRoomTab(app.rooms['ladder']) +
this.renderRoomTab(app.rooms['resources'])
) + '</ul>';
var sideBuf = '';
var notificationCount = app.rooms[''].notifications ? 1 : 0;
if (app.roomList.length) {
buf += '<ul>';
for (var i = 0; i < app.roomList.length; i++) {
var room = app.roomList[i];
if (room.notifications) notificationCount++;
buf += this.renderRoomTab(room);
}
buf += '</ul>';
}
for (var i = 0; i < app.sideRoomList.length; i++) {
var room = app.sideRoomList[i];
if (room.notifications) notificationCount++;
sideBuf += this.renderRoomTab(room);
}
if (window.nodewebkit) {
if (nwWindow.setBadgeLabel) nwWindow.setBadgeLabel(notificationCount ? '' + notificationCount : '');
} else {
var $favicon = $('#dynamic-favicon');
if (!!$favicon.data('on') !== !!notificationCount) {
if (notificationCount) {
$favicon.attr('href', Dex.resourcePrefix + '/favicon-notify.ico');
$favicon.data('on', '1');
} else {
$favicon.attr('href', Dex.resourcePrefix + '/favicon.ico');
$favicon.data('on', '');
}
}
}
sideBuf += this.renderRoomTab(app.rooms['rooms'], 'rooms');
var margin = 0;
if (sideBuf) {
if (app.curSideRoom) {
margin = app.curSideRoom.leftWidth - 144;
buf += '<ul class="siderooms" style="float:none;margin-left:' + margin + 'px">' + sideBuf + '</ul>';
} else {
buf += '<ul>' + sideBuf + '</ul>';
}
}
this.$tabbar.html(buf);
var $lastUl = this.$tabbar.children().last();
var $lastLi = $lastUl.children().last();
var offset = $lastLi.offset();
var width = $lastLi.outerWidth();
// 166 here is the difference between the .maintabbar's right margin and the a.button's right margin.
var overflow = offset.left + width + 166 - $(window).width();
if (app.curSideRoom && overflow > 0) {
margin -= overflow;
$lastUl.css('margin-left', margin + 'px');
offset = $lastLi.offset();
overflow = offset.left + width + 166 - $(window).width();
}
if (offset.top >= 37 || overflow > 0) {
this.$tabbar.append('<div class="overflow" aria-hidden="true"><button name="tablist" class="button" aria-label="More"><i class="fa fa-caret-down"></i></button></div>');
}
if (app.rooms['']) app.rooms[''].updateRightMenu();
},
updateTabbarMini: function () {
this.$('.logo').hide();
this.$('.maintabbar').addClass('minitabbar');
var notificationClass = '';
for (var i in app.rooms) {
if (app.rooms[i] !== app.curRoom && app.rooms[i].notificationClass === ' notifying') notificationClass = ' notifying';
}
var buf = '<ul><li><a class="button minilogo' + notificationClass + '" href="' + app.root + '"><img src="' + Dex.resourcePrefix + 'favicon-256.png" width="32" height="32" alt="Pok&eacute;mon Showdown! (beta)" /><i class="fa fa-caret-down" style="display:inline-block"></i></a></li></ul>';
buf += '<ul>' + this.renderRoomTab(app.curRoom) + '</ul>';
this.$tabbar.html(buf);
if (app.rooms['']) app.rooms[''].updateRightMenu();
},
dispatchClickButton: function (e) {
var target = e.currentTarget;
if (target.name) {
app.dismissingSource = app.dismissPopups();
app.dispatchingButton = target;
e.preventDefault();
e.stopImmediatePropagation();
this[target.name](target.value, target, e);
delete app.dismissingSource;
delete app.dispatchingButton;
}
},
click: function (e) {
if (e.cmdKey || e.metaKey || e.ctrlKey) return;
e.preventDefault();
var $target = $(e.currentTarget);
if ($target.hasClass('minilogo')) {
app.addPopup(TabListPopup, { sourceEl: e.currentTarget });
return;
}
var id = $target.attr('href');
if (id.substr(0, app.root.length) === app.root) {
id = id.substr(app.root.length);
}
if ($target.hasClass('closebutton')) {
app.leaveRoom(id, e);
} else {
app.joinRoom(id);
}
},
closeRoom: function (roomid, button, e) {
app.leaveRoom(roomid, e);
},
tablist: function () {
app.addPopup(TabListPopup);
},
// drag and drop
roomidOf: function (room) {
return room.id;
},
dragStartRoom: function (e) {
var target = e.currentTarget;
var dataTransfer = e.originalEvent.dataTransfer;
var elWidth = $(e.currentTarget).outerWidth();
dataTransfer.effectAllowed = 'all';
// by default, Chrome displays links as a URL when dragging
// this uses a hack to force it to drag the tab
app.draggingOffsetX = Math.floor(elWidth / 2);
app.draggingOffsetY = 18;
dataTransfer.setDragImage(target, app.draggingOffsetX, app.draggingOffsetY);
var roomRef = $(target).attr('href');
app.draggingRoomList = app.roomList.map(this.roomidOf).concat('|').concat(app.sideRoomList.map(this.roomidOf));
app.draggingLoc = app.draggingRoomList.indexOf(roomRef.slice(1));
if (app.draggingLoc < 0) {
// can't drag
return;
}
app.dragging = roomRef;
app.draggingRoom = null;
app.$dragging = null;
var iPipe = app.draggingRoomList.indexOf('|');
app.draggingSideRoom = (app.draggingLoc > iPipe);
setTimeout(function () {
$(target).css('opacity', 0.5);
}, 0);
// console.log('dragstart: ' + app.dragging);
},
dragEnterRoom: function (e) {
if (!app.dragging || typeof app.dragging !== 'string') return;
var roomid = $(e.currentTarget).attr('href').slice(1);
if (app.dragging.slice(1) === roomid) return;
var i = app.draggingRoomList.indexOf(roomid);
var iPipe = app.draggingRoomList.indexOf('|');
if (iPipe < 0) return; // bug?
if (!app.$dragging) {
// the dragging element needs to stay in the DOM, or the dragEnd
// event won't fire (at least when I tested in Chrome)
app.$dragging = this.$('a.roomtab[href="' + app.dragging + '"]');
this.$el.append(app.$dragging);
app.$dragging.hide();
} else if (app.draggingLastRoom === roomid) {
if (app.draggingOffsetX > 0) {
// dragged right, don't drag back if we're still going right
if (e.originalEvent.pageX - app.draggingOffsetX >= -5) return;
} else {
// dragged left, don't drag back if we're still going left
if (e.originalEvent.pageX + app.draggingOffsetX <= 5) return;
}
}
if (roomid === 'rooms') i = app.draggingRoomList.length;
if (i < 0) i = 0;
var draggingRight = (i > app.draggingLoc);
if (iPipe > app.draggingLoc && i > iPipe) draggingRight = false;
app.draggingOffsetX = e.originalEvent.pageX * (draggingRight ? 1 : -1);
app.draggingLastRoom = roomid;
// remove tab from old position
var room;
if (app.draggingLoc < iPipe) {
// old position is in left list
room = app.roomList.splice(app.draggingLoc, 1)[0];
iPipe--;
} else {
// old position is in right list
room = app.sideRoomList.splice(app.draggingLoc - iPipe - 1, 1)[0];
}
if (app.draggingLoc < i) i--;
// add tab to new position
if (draggingRight) i++; // add after when dragging right
if (i <= iPipe) {
// insert into left list
app.roomList.splice(i, 0, room);
} else {
// insert into right list
app.sideRoomList.splice(i - iPipe - 1, 0, room);
}
app.draggingRoomList = app.roomList.map(this.roomidOf).concat('|').concat(app.sideRoomList.map(this.roomidOf));
app.draggingLoc = app.draggingRoomList.indexOf(app.dragging.slice(1));
this.updateTabbar();
this.$('a.roomtab[href="' + app.dragging + '"]').css('opacity', 0.5);
// console.log('dragenter: /' + roomid);
},
dragEndRoom: function (e) {
if (!app.dragging) return;
// console.log('dragend: ' + app.dragging);
var room = app.rooms[app.dragging.slice(1)];
var iPipe = app.draggingRoomList.indexOf('|');
if (app.draggingLoc < iPipe && app.draggingSideRoom) {
app.focusRoomLeft(room.id);
} else if (app.draggingLoc > iPipe && !app.draggingSideRoom) {
app.focusRoomRight(room.id);
} else {
this.updateTabbar();
}
if (room.type === 'chat') app.updateAutojoin();
app.dragging = null;
if (app.$dragging) app.$dragging.remove();
app.draggingRoomList = null;
}
});
var SoundsPopup = this.SoundsPopup = Popup.extend({
initialize: function (data) {
var buf = '';
var muted = !!Dex.prefs('mute');
buf += '<p class="effect-volume"><label class="optlabel">Effect volume:</label>' + (muted ? '<em>(muted)</em>' : '<input type="range" min="0" max="100" step="1" name="effectvolume" value="' + this.getEffectVolume() + '" />') + '</p>';
buf += '<p class="music-volume"><label class="optlabel">Music volume:</label>' + (muted ? '<em>(muted)</em>' : '<input type="range" min="0" max="100" step="1" name="musicvolume" value="' + this.getMusicVolume() + '" />') + '</p>';
buf += '<p class="notif-volume"><label class="optlabel">Notification volume:</label>' + (muted ? '<em>(muted)</em>' : '<input type="range" min="0" max="100" step="1" name="notifvolume" value="' + this.getNotifVolume() + '" />') + '</p>';
buf += '<p><label class="checkbox"><input type="checkbox" name="muted"' + (muted ? ' checked' : '') + ' /> Mute sounds</label></p>';
this.$el.html(buf).css('min-width', 160);
},
events: {
'change input[name=muted]': 'setMute',
'change input[type=range]': 'updateVolume',
'keyup input[type=range]': 'updateVolume',
'input input[type=range]': 'updateVolume'
},
updateVolume: function (e) {
var val = Number(e.currentTarget.value);
switch (e.currentTarget.name) {
case 'effectvolume':
this.setEffectVolume(val);
break;
case 'musicvolume':
this.setMusicVolume(val);
break;
case 'notifvolume':
this.setNotifVolume(val);
break;
}
},
setMute: function (e) {
var muted = !!e.currentTarget.checked;
Storage.prefs('mute', muted);
BattleSound.setMute(muted);
if (!muted) {
this.$('.effect-volume').html('<label class="optlabel">Effect volume:</label><input type="range" min="0" max="100" step="1" name="effectvolume" value="' + this.getEffectVolume() + '" />');
this.$('.music-volume').html('<label class="optlabel">Music volume:</label><input type="range" min="0" max="100" step="1" name="musicvolume" value="' + this.getMusicVolume() + '" />');
this.$('.notif-volume').html('<label class="optlabel">Notification volume:</label><input type="range" min="0" max="100" step="1" name="notifvolume" value="' + this.getNotifVolume() + '" />');
} else {
this.$('.effect-volume').html('<label class="optlabel">Effect volume:</label><em>(muted)</em>');
this.$('.music-volume').html('<label class="optlabel">Music volume:</label><em>(muted)</em>');
this.$('.notif-volume').html('<label class="optlabel">Notification volume:</label><em>(muted)</em>');
}
app.topbar.$('button[name=openSounds]').html('<i class="' + (muted ? 'fa fa-volume-off' : 'fa fa-volume-up') + '"></i>');
},
setEffectVolume: function (volume) {
BattleSound.setEffectVolume(volume);
Storage.prefs('effectvolume', volume);
},
getEffectVolume: function () {
var volume = Dex.prefs('effectvolume');
return typeof volume === 'number' ? volume : 50;
},
setMusicVolume: function (volume) {
BattleSound.setBgmVolume(volume);
Storage.prefs('musicvolume', volume);
},
getMusicVolume: function () {
var volume = Dex.prefs('musicvolume');
return typeof volume === 'number' ? volume : 50;
},
setNotifVolume: function (volume) {
Storage.prefs('notifvolume', volume);
},
getNotifVolume: function () {
var volume = Dex.prefs('notifvolume');
return typeof volume === 'number' ? volume : 50;
}
});
var OptionsPopup = this.OptionsPopup = Popup.extend({
initialize: function (data) {
app.user.on('change', this.update, this);
app.send('/cmd userdetails ' + app.user.get('userid'));
this.update();
},
events: {
'change input[name=noanim]': 'setNoanim',
'change input[name=nogif]': 'setNogif',
'change input[name=bwgfx]': 'setBwgfx',
'change input[name=nopastgens]': 'setNopastgens',
'change select[name=tournaments]': 'setTournaments',
'change select[name=language]': 'setLanguage',
'change input[name=blockchallenges]': 'setBlockchallenges',
'change input[name=blockpms]': 'setBlockpms',
'change input[name=inchatpm]': 'setInchatpm',
'change input[name=leavePopupRoom]': 'setLeavePopupRoom',
'change input[name=temporarynotifications]': 'setTemporaryNotifications',
'change input[name=refreshprompt]': 'setRefreshprompt',
'change select[name=bg]': 'setBg',
'change select[name=timestamps-lobby]': 'setTimestampsLobby',
'change select[name=timestamps-pms]': 'setTimestampsPMs',
'change select[name=onepanel]': 'setOnePanel',
'change select[name=theme]': 'setTheme',
'change input[name=logchat]': 'setLogChat',
'change input[name=selfhighlight]': 'setSelfHighlight',
'click img': 'avatars',
'keydown input[name=statustext]': 'editstatus'
},
update: function () {
var name = app.user.get('name');
var avatar = app.user.get('avatar');
var settings = app.user.get('settings');
var buf = '';
buf += '<p>' + (avatar ? '<img class="trainersprite" src="' + Dex.resolveAvatar(avatar) + '" width="40" height="40" style="vertical-align:middle;cursor:pointer" />' : '') + '<strong>' + BattleLog.escapeHTML(name) + '</strong></p>';
buf += '<p><button class="button" name="avatars">Avatar...</button></p>';
if (!this.editingStatus) {
buf += '<p><button class="button" name="editstatus">Status...</button></p>';
} else {
buf += '<p><input name="statustext" />';
buf += '<button class="button" name="editstatus"><i class="fa fa-pencil"></i></button></p>';
}
if (app.user.get('named')) {
var registered = app.user.get('registered');
if (registered && (registered.userid === app.user.get('userid'))) {
buf += '<p><button class="button" name="changepassword">Password...</button></p>';
} else {
buf += '<p><button class="button" name="register">Register</button></p>';
}
}
buf += '<hr />';
buf += '<p><strong>Graphics</strong></p>';
var theme = Dex.prefs('theme');
var colorSchemeQuerySupported = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').media !== 'not all';
buf += '<p><label class="optlabel">Theme: <select name="theme" class="button"><option value="light"' + (!theme || theme === 'light' ? ' selected="selected"' : '') + '>Light</option><option value="dark"' + (theme === 'dark' ? ' selected="selected"' : '') + '>Dark</option>';
if (colorSchemeQuerySupported) {
buf += '<option value="system"' + (theme === 'system' ? ' selected="selected"' : '') + '>Match system theme</option>';
}
buf += '</select></label></p>';
var onePanel = !!Dex.prefs('onepanel');
if ($(window).width() >= 660) {
buf += '<p><label class="optlabel">Layout: <select name="onepanel" class="button"><option value=""' + (!onePanel ? ' selected="selected"' : '') + '>&#x25EB; Left and right panels</option><option value="1"' + (onePanel ? ' selected="selected"' : '') + '>&#x25FB; Single panel</option></select></label></p>';
}
buf += '<p><label class="optlabel">Background: <button class="button" name="background">Change background</button></label></p>';
buf += '<p><label class="checkbox"><input type="checkbox" name="noanim"' + (Dex.prefs('noanim') ? ' checked' : '') + ' /> Disable animations</label></p>';
if (navigator.userAgent.includes(' Chrome/64.')) {
buf += '<p><label class="checkbox"><input type="checkbox" name="nogif"' + (Dex.prefs('nogif') ? ' checked' : '') + ' /> Disable GIFs for Chrome 64 bug</label></p>';
}
buf += '<p><label class="checkbox"><input type="checkbox" name="bwgfx"' + (Dex.prefs('bwgfx') ? ' checked' : '') + ' /> Use 2D sprites instead of 3D models</label></p>';
buf += '<p><label class="checkbox"><input type="checkbox" name="nopastgens"' + (Dex.prefs('nopastgens') ? ' checked' : '') + ' /> Use modern sprites for past generations</label></p>';
buf += '<hr />';
buf += '<p><strong>Chat</strong></p>';
if (Object.keys(settings).length) {
buf += '<p><label class="checkbox"><input type="checkbox" name="blockpms"' + (settings.blockPMs ? ' checked' : '') + ' /> Block PMs</label></p>';
buf += '<p><label class="checkbox"><input type="checkbox" name="blockchallenges"' + (settings.blockChallenges ? ' checked' : '') + ' /> Block Challenges</label></p>';
}
buf += '<p><label class="checkbox"><input type="checkbox" name="inchatpm"' + (Dex.prefs('inchatpm') ? ' checked' : '') + ' /> Show PMs in chat rooms</label></p>';
buf += '<p><label class="checkbox"><input type="checkbox" name="selfhighlight"' + (!Dex.prefs('noselfhighlight') ? ' checked' : '') + '> Highlight when your name is said in chat</label></p>';
if (window.Notification) {
buf += '<p><label class="checkbox"><input type="checkbox" name="temporarynotifications"' + (Dex.prefs('temporarynotifications') ? ' checked' : '') + ' /> Notifications disappear automatically</label></p>';
}
buf += '<p><label class="checkbox"><input type="checkbox" name="leavePopupRoom"' + (Dex.prefs('leavePopupRoom') ? ' checked' : '') + ' /> Confirm before leaving a room</label></p>';
buf += '<p><label class="checkbox"><input type="checkbox" name="refreshprompt"' + (Dex.prefs('refreshprompt') ? ' checked' : '') + '> Confirm before refreshing</label></p>';
var curLang = toID(Dex.prefs('serversettings').language) || 'english';
var possibleLanguages = {
"Deutsch": 'german',
"English": 'english',
"Español": 'spanish',
"Français": 'french',
"Italiano": 'italian',
"Nederlands": 'dutch',
"Português": 'portuguese',
"Türkçe": 'turkish',
"हिंदी": 'hindi',
"日本語": 'japanese',
"简体中文": 'simplifiedchinese',
"中文": 'traditionalchinese'
};
buf += '<p><label class="optlabel">Language: <select name="language" class="button">';
for (var name in possibleLanguages) {
buf += '<option value="' + possibleLanguages[name] + '"' + (possibleLanguages[name] === curLang ? ' selected="selected"' : '') + '>' + name + '</option>';
}
buf += '</select></label></p>';
var tours = Dex.prefs('tournaments') || 'notify';
buf += '<p><label class="optlabel">Tournaments: <select name="tournaments" class="button"><option value="notify"' + (tours === 'notify' ? ' selected="selected"' : '') + '>Notifications</option><option value="nonotify"' + (tours === 'nonotify' ? ' selected="selected"' : '') + '>No Notifications</option><option value="hide"' + (tours === 'hide' ? ' selected="selected"' : '') + '>Hide</option></select></label></p>';
var timestamps = this.timestamps = (Dex.prefs('timestamps') || {});
buf += '<p><label class="optlabel">Timestamps in chat rooms: <select name="timestamps-lobby" class="button"><option value="off">Off</option><option value="minutes"' + (timestamps.lobby === 'minutes' ? ' selected="selected"' : '') + '>[HH:MM]</option><option value="seconds"' + (timestamps.lobby === 'seconds' ? ' selected="selected"' : '') + '>[HH:MM:SS]</option></select></label></p>';
buf += '<p><label class="optlabel">Timestamps in PMs: <select name="timestamps-pms" class="button"><option value="off">Off</option><option value="minutes"' + (timestamps.pms === 'minutes' ? ' selected="selected"' : '') + '>[HH:MM]</option><option value="seconds"' + (timestamps.pms === 'seconds' ? ' selected="selected"' : '') + '>[HH:MM:SS]</option></select></label></p>';
buf += '<p><label class="optlabel">Chat preferences: <button name="formatting" class="button">Text formatting</button></label></p>';
if (window.nodewebkit) {
buf += '<hr />';
buf += '<p><strong>Desktop app</strong></p>';
buf += '<p><label class="optlabel"><input type="checkbox" name="logchat"' + (Dex.prefs('logchat') ? ' checked' : '') + '> Log chat</label></p>';
buf += '<p id="openLogFolderButton"' + (Storage.dir ? '' : ' style="display:none"') + '><button name="openLogFolder">Open log folder</button></p>';
}
buf += '<hr />';
if (app.user.get('named')) {
buf += '<p class="buttonbar" style="text-align:right"><button name="login" class="button"><i class="fa fa-pencil"></i> Change name</button> <button name="logout" class="button"><i class="fa fa-power-off"></i> Log out</button></p>';
} else {
buf += '<p class="buttonbar" style="text-align:right"><button name="login" class="button">Choose name</button></p>';
}
this.$el.html(buf).css('min-width', 160);
},
openLogFolder: function () {
Storage.revealFolder();
},
setLogChat: function (e) {
var logchat = !!e.currentTarget.checked;
if (logchat) {
Storage.startLoggingChat();
$('#openLogFolderButton').show();
} else {
Storage.stopLoggingChat();
}
Storage.prefs('logchat', logchat);
},
setNoanim: function (e) {
var noanim = !!e.currentTarget.checked;
Storage.prefs('noanim', noanim);
Dex.loadSpriteData(noanim || Dex.prefs('bwgfx') ? 'bw' : 'xy');
},
setNogif: function (e) {
var nogif = !!e.currentTarget.checked;
Storage.prefs('nogif', nogif);
Dex.loadSpriteData(nogif || Dex.prefs('bwgfx') ? 'bw' : 'xy');
},
setTheme: function (e) {
var theme = e.currentTarget.value;
Storage.prefs('theme', theme);
if (theme === 'system') {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
theme = 'dark';
} else {
theme = 'light';
}
}
$('html').toggleClass('dark', theme === 'dark');
},
setBwgfx: function (e) {
var bwgfx = !!e.currentTarget.checked;
Storage.prefs('bwgfx', bwgfx);
Dex.loadSpriteData(bwgfx || Dex.prefs('noanim') ? 'bw' : 'xy');
},
setNopastgens: function (e) {
var nopastgens = !!e.currentTarget.checked;
Storage.prefs('nopastgens', nopastgens);
},
setTournaments: function (e) {
var tournaments = e.currentTarget.value;
Storage.prefs('tournaments', tournaments);
},
setLanguage: function (e) {
app.user.updateSetting('language', e.currentTarget.value);
},
setBlockpms: function (e) {
app.user.updateSetting('blockPMs', !!e.currentTarget.checked);
},
setBlockchallenges: function (e) {
app.user.updateSetting('blockChallenges', !!e.currentTarget.checked);
},
setSelfHighlight: function (e) {
var noselfhighlight = !e.currentTarget.checked;
Storage.prefs('noselfhighlight', noselfhighlight);
},
setInchatpm: function (e) {
var inchatpm = !!e.currentTarget.checked;
Storage.prefs('inchatpm', inchatpm);
},
setTemporaryNotifications: function (e) {
var temporarynotifications = !!e.currentTarget.checked;
Storage.prefs('temporarynotifications', temporarynotifications);
},
setRefreshprompt: function (e) {
var refreshprompt = !!e.currentTarget.checked;
Storage.prefs('refreshprompt', refreshprompt);
},
setLeavePopupRoom: function (e) {
var leavePopupRoom = !!e.currentTarget.checked;
Storage.prefs('leavePopupRoom', leavePopupRoom);
},
background: function (e) {
app.addPopup(CustomBackgroundPopup);
},
setOnePanel: function (e) {
app.singlePanelMode = !!e.currentTarget.value;
Storage.prefs('onepanel', !!e.currentTarget.value);
app.updateLayout();
},
setTimestampsLobby: function (e) {
this.timestamps.lobby = e.currentTarget.value;
Storage.prefs('timestamps', this.timestamps);
},
setTimestampsPMs: function (e) {
this.timestamps.pms = e.currentTarget.value;
Storage.prefs('timestamps', this.timestamps);
},
avatars: function () {
app.addPopup(AvatarsPopup);
},
editstatus: function (ev) {
// from an input, key isn't enter
// there's no event if it's a click fsr
if (ev && ev.keyCode !== 13) return;
if (!this.editingStatus) {
this.editingStatus = true;
this.update();
} else {
var $input = $('input[name=statustext]');
var statusText = $input.val();
if (!toID(statusText).length) {
return;
}
app.send('/status ' + statusText);
var $editButton = $('button[name=editstatus]');
$editButton.text('Status updated!');
$editButton.attr('disabled', true);
$input.remove();
this.editingStatus = false;
}
},
formatting: function () {
app.addPopup(FormattingPopup);
},
login: function () {
app.addPopup(LoginPopup);
},
register: function () {
app.addPopup(RegisterPopup);
},
changepassword: function () {
app.addPopup(ChangePasswordPopup);
},
logout: function () {
app.user.logout();
this.close();
}
});
var FormattingPopup = this.FormattingPopup = Popup.extend({
events: {
'change input': 'setOption'
},
initialize: function () {
var cur = this.chatformatting = Dex.prefs('chatformatting') || {};
var buf = '<p>Usable formatting:</p>';
var ctrlPlus = '<kbd>' + (navigator.platform === 'MacIntel' ? 'Cmd' : 'Ctrl') + '</kbd> + ';
buf += '<p>**<strong>bold</strong>** (' + ctrlPlus + '<kbd>B</kbd>)</p>';
buf += '<p>__<em>italics</em>__ (' + ctrlPlus + '<kbd>I</kbd>)</p>';
buf += '<p>``<code>code formatting</code>`` (<kbd>Ctrl</kbd> + <kbd>`</kbd>)</p>';
buf += '<p>~~<s>strikethrough</s>~~</p>';
buf += '<p>^^<sup>superscript</sup>^^</p>';
buf += '<p>\\\\<sub>subscript</sub>\\\\</p>';
buf += '<p><label class="checkbox"><input type="checkbox" name="greentext" ' + (cur.hidegreentext ? 'checked' : '') + ' /> Suppress <span class="greentext">&gt;' + ['meme arrows', 'greentext', 'quote formatting'][Math.floor(Math.random() * 3)] + '</span></label></p>';
buf += '<p><label class="checkbox"><input type="checkbox" name="me" ' + (cur.hideme ? 'checked' : '') + ' /> Suppress <code>/me</code> <em>action formatting</em></label></p>';
buf += '<p><label class="checkbox"><input type="checkbox" name="spoiler" ' + (cur.hidespoiler ? 'checked' : '') + ' /> Auto-show spoilers: <span class="spoiler">these things</span></label></p>';
buf += '<p><label class="checkbox"><input type="checkbox" name="links" ' + (cur.hidelinks ? 'checked' : '') + ' /> Make [[clickable links]] unclickable</label></p>';
buf += '<p><label class="checkbox"><input type="checkbox" name="interstice"' + (cur.hideinterstice ? 'checked' : '') + ' /> Don\'t warn for untrusted links</label></p>';
buf += '<p><button name="close" class="button">Done</button></p>';
this.$el.html(buf);
},
setOption: function (e) {
var name = $(e.currentTarget).prop('name');
this.chatformatting['hide' + name] = !!e.currentTarget.checked;
Storage.prefs('chatformatting', this.chatformatting);
}
});
var AvatarsPopup = this.AvatarsPopup = Popup.extend({
type: 'semimodal',
initialize: function () {
var cur = +app.user.get('avatar');
var buf = '';
buf += '<p>Choose an avatar or <button name="close" class="button">Cancel</button></p>';
buf += '<div class="avatarlist">';
for (var i = 1; i <= 293; i++) {
if (i === 162 || i === 168) continue;
var offset = '-' + (((i - 1) % 16) * 80 + 1) + 'px -' + (Math.floor((i - 1) / 16) * 80 + 1) + 'px';
buf += '<button name="setAvatar" value="' + i + '" style="background-position:' + offset + '" class="option pixelated' + (i === cur ? ' cur' : '') + '" title="/avatar ' + i + '"></button>';
}
buf += '</div><div style="clear:left"></div>';
buf += '<p><button name="close" class="button">Cancel</button></p>';
this.$el.html(buf).css('max-width', 780);
},
setAvatar: function (avatar) {
// Replace avatar number with name before sending it to the server, only the client knows what to do with the numbers
if (window.BattleAvatarNumbers && Object.prototype.hasOwnProperty.call(window.BattleAvatarNumbers, avatar)) {
avatar = window.BattleAvatarNumbers[avatar];
}
app.send('/avatar ' + avatar);
app.send('/cmd userdetails ' + app.user.get('userid'));
Storage.prefs('avatar', avatar);
this.close();
}
});
var TabListPopup = this.TabListPopup = Popup.extend({
type: 'semimodal',
renderRooms: function (rooms) {
var buf = '';
for (var i = 0; i < rooms.length; i++) buf += app.topbar.renderRoomTab(rooms[i]);
return buf;
},
initialize: function () {
var curId = (app.curRoom ? app.curRoom.id : '');
var curSideId = (app.curSideRoom ? app.curSideRoom.id : '');
var buf = '<ul>' + this.renderRooms([app.rooms[''], app.rooms['teambuilder'], app.rooms['ladder']]) + '</ul>';
if (app.roomList.length) buf += this.renderRooms(app.roomList);
var sideBuf = this.renderRooms(app.sideRoomList);
sideBuf += '<li><a class="button' + (curId === 'rooms' || curSideId === 'rooms' ? ' cur' : '') + '" href="' + app.root + 'rooms"><i class="fa fa-plus"></i> <span>&nbsp;</span></a></li>';
if (sideBuf) {
buf += '<ul>' + sideBuf + '</ul>';
}
this.$el.addClass('tablist').html(buf);
},
events: {
'click a': 'click'
},
closeRoom: function (roomid, button, e) {
app.leaveRoom(roomid);
this.initialize();
},
click: function (e) {
if (e.cmdKey || e.metaKey || e.ctrlKey) return;
e.preventDefault();
var $target = $(e.currentTarget);
var id = $target.attr('href');
if (id.substr(0, app.root.length) === app.root) {
id = id.substr(app.root.length);
}
if ($target.hasClass('closebutton')) {
app.leaveRoom(id);
this.initialize();
} else {
this.close();
app.focusRoom(id);
}
}
});
var CustomBackgroundPopup = this.CustomBackgroundPopup = Popup.extend({
events: {
'change input[name=bgfile]': 'setBgFile'
},
initialize: function () {
var buf = '';
var cur = Storage.bg.id;
buf += '<p><strong>Default</strong></p>';
buf += '<div class="bglist">';
buf += '<button name="setBg" value="" class="option' + (!cur ? ' cur' : '') + '"><strong style="background:#888888;color:white;padding:16px 18px;display:block;font-size:12pt">' + (location.host === Config.routes.client ? 'Random' : 'Default') + '</strong></button>';
buf += '</div><div style="clear:left"></div>';
buf += '<p><strong>Official</strong></p>';
buf += '<div class="bglist">';
buf += '<button name="setBg" value="charizards" class="option' + (cur === 'charizards' ? ' cur' : '') + '"><span class="bg" style="background-position:0 -' + (90 * 0) + 'px"></span>Charizards</button>';
buf += '<button name="setBg" value="horizon" class="option' + (cur === 'horizon' ? ' cur' : '') + '"><span class="bg" style="background-position:0 -' + (90 * 1) + 'px"></span>Horizon</button>';
buf += '<button name="setBg" value="ocean" class="option' + (cur === 'ocean' ? ' cur' : '') + '"><span class="bg" style="background-position:0 -' + (90 * 3) + 'px"></span>Ocean</button>';
buf += '<button name="setBg" value="shaymin" class="option' + (cur === 'shaymin' ? ' cur' : '') + '"><span class="bg" style="background-position:0 -' + (90 * 4) + 'px"></span>Shaymin</button>';
buf += '<button name="setBg" value="solidblue" class="option' + (cur === 'solidblue' ? ' cur' : '') + '"><span class="bg" style="background: #344b6c"></span>Solid blue</button>';
buf += '</div><div style="clear:left"></div>';
buf += '<p><strong>Custom</strong></p>';
buf += '<p>Drag and drop an image to PS (the background settings don\'t need to be open), or upload:</p>';
buf += '<p><input type="file" accept="image/*" name="bgfile"></p>';
buf += '<p class="bgstatus"></p>';
buf += '<p><button name="close" class="button"><strong>Done</strong></button></p>';
// April Fool's 2016 - background change disabling
// buf = '<p>Sorry, the background chooser is experiencing technical difficulties. Please try again tomorrow!</p><p><button name="close"><strong>Done</strong></button></p>';
this.$el.css('max-width', 448).html(buf);
this.$el.html(buf);
},
setBg: function (bgid) {
var bgUrl = (bgid === 'solidblue' ? '#344b6c' : Dex.resourcePrefix + 'fx/client-bg-' + bgid + '.jpg');
Storage.bg.set(bgUrl, bgid);
this.$('.cur').removeClass('cur');
this.$('button[value="' + bgid + '"]').addClass('cur');
},
setBgFile: function (e) {
$('.bgstatus').text('Changing background image...');
var file = e.currentTarget.files[0];
CustomBackgroundPopup.readFile(file, this);
}
});
CustomBackgroundPopup.readFile = function (file, popup) {
var reader = new FileReader();
reader.onload = function (e) {
if (String(e.target.result).length > 4200000) {
if (popup) {
$('.bgstatus').html('<strong style="background:red;color:white;padding:1px 4px;border-radius:4px;display:block">Image is too large and can\'t be saved. It should be under 3.5MB or so.</strong>');
} else {
app.addPopupMessage("Image is too large and can't be saved. It should be under 3.5MB or so.");
}
} else if (popup) {
$('.bgstatus').html('Saved');
popup.$('.cur').removeClass('cur');
Storage.bg.set(e.target.result, 'custom');
} else {
app.addPopup(ConfirmBackgroundPopup, { bgUrl: e.target.result });
}
};
reader.readAsDataURL(file);
};
var ConfirmBackgroundPopup = this.ConfirmBackgroundPopup = Popup.extend({
initialize: function (data) {
var buf = '<br>';
buf += '<p><img src="' + data.bgUrl + '" style="display:block;margin:auto;max-width:90%;max-height:500px"></p>';
buf += '<p class="buttonbar"><button name="setBg" value="' + data.bgUrl + '" class="button"><strong>Change background</strong></button> ';
buf += '<button name="close" class="button">Cancel</button></p>';
this.$el.css('max-width', 485).html(buf);
this.$el.html(buf);
},
setBg: function (bgUrl) {
this.close();
Storage.bg.set(bgUrl, 'custom');
}
});
var LoginPopup = this.LoginPopup = Popup.extend({
type: 'semimodal',
initialize: function (data) {
var buf = '<form>';
if (data.error) {
buf += '<p class="error">' + BattleLog.escapeHTML(data.error) + '</p>';
if (data.error.indexOf('inappropriate') >= 0) {
// log out so we don't autologin to a bad name if we refresh
$.post(app.user.getActionPHP(), {
act: 'logout',
userid: app.user.get('userid')
});
buf += '<p>Keep in mind these rules:</p>';
buf += '<ol>';
buf += '<li>Usernames may not impersonate a recognized user (a user with %, @, #, or & next to their name).</li>';
buf += '<li>Usernames may not be derogatory or insulting in nature, to an individual or group (insulting yourself is okay as long as it\'s not too serious).</li>';
buf += '<li>Usernames may not directly reference sexual activity, or be excessively disgusting.</li>';
buf += '</ol>';
}
} else if (data.reason) {
buf += '<p>' + BattleLog.parseMessage(data.reason) + '</p>';
} else if (!data.force) {
var noRenameGames = '';
if (app.rooms[''].games) {
for (var roomid in app.rooms[''].games) {
var title = app.rooms[''].games[roomid];
if (title.slice(-1) === '*') {
noRenameGames += '<li>' + BattleLog.escapeHTML(title.slice(0, -1)) + '</li>';
}
}
}
if (noRenameGames) {
buf += '<p>You can\'t change name in the middle of these games:</p>';
buf += '<ul>' + noRenameGames + '</ul>';
buf += '<p class="buttonbar"><button type="button" name="force" class="button"><small style="color:red">Forfeit and change name</small></button></p>';
buf += '<p class="buttonbar"><button type="submit" autofocus class="button"><strong>Cancel</strong></button></p>';
buf += '</form>';
this.$el.html(buf);
return;
}
}
var name = (data.name || '');
if (!name && app.user.get('named')) name = app.user.get('name');
buf += '<p><label class="label">Username: <small class="preview" style="' + BattleLog.hashColor(toUserid(name)) + '">(color)</small><input class="textbox autofocus" type="text" name="username" value="' + BattleLog.escapeHTML(name) + '" autocomplete="username"></label></p>';
if (name) {
buf += '<p><small>(Others will be able to see your name change. To change name privately, use "Log out")</small></p>';
}
buf += '<p class="buttonbar"><button type="submit" class="button"><strong>Choose name</strong></button> <button type="button" name="close" class="button">Cancel</button></p>';
buf += '</form>';
this.$el.html(buf);
},
events: {
'input .textbox': 'updateColor'
},
updateColor: function (e) {
var name = e.currentTarget.value;
var preview = this.$('.preview');
var css = BattleLog.hashColor(toUserid(name)).slice(6, -1);
preview.css('color', css);
},
force: function () {
var sourceEl = this.sourceEl;
this.close();
app.addPopup(LoginPopup, {
force: true,
sourceEl: sourceEl,
sourcePopup: app.popups[app.popups.length - 1]
});
},
submit: function (data) {
this.close();
if (!$.trim(data.username)) return;
app.user.rename(data.username);
}
});
var ChangePasswordPopup = this.ChangePasswordPopup = Popup.extend({
type: 'semimodal',
initialize: function (data) {
var buf = '<form>';
if (data.error) {
buf += '<p class="error">' + data.error + '</p>';
} else {
buf += '<p>Change your password:</p>';
}
buf += '<p><label class="label">Username: <strong><input type="text" name="username" value="' + BattleLog.escapeHTML(app.user.get('name')) + '" style="color:inherit;background:transparent;border:0;font:inherit;font-size:inherit;display:block" readonly autocomplete="username" /></strong></label></p>';
buf += '<p><label class="label">Old password: <input class="textbox autofocus" type="password" name="oldpassword" autocomplete="current-password" /></label></p>';
buf += '<p><label class="label">New password: <input class="textbox" type="password" name="password" autocomplete="new-password" /></label></p>';
buf += '<p><label class="label">New password (confirm): <input class="textbox" type="password" name="cpassword" autocomplete="new-password" /></label></p>';
buf += '<p class="buttonbar"><button type="submit" class="button"><strong>Change password</strong></button> <button type="button" name="close" class="button">Cancel</button></p></form>';
this.$el.html(buf);
},
submit: function (data) {
$.post(app.user.getActionPHP(), {
act: 'changepassword',
oldpassword: data.oldpassword,
password: data.password,
cpassword: data.cpassword
}, Storage.safeJSON(function (data) {
if (!data) data = {};
if (data.actionsuccess) {
app.addPopupMessage("Your password was successfully changed.");
} else {
app.addPopup(ChangePasswordPopup, {
error: data.actionerror
});
}
}), 'text');
}
});
var RegisterPopup = this.RegisterPopup = Popup.extend({
type: 'semimodal',
initialize: function (data) {
var buf = '<form>';
if (data.error) {
buf += '<p class="error">' + data.error + '</p>';
} else if (data.reason) {
buf += '<p>' + data.reason + '</p>';
} else {
buf += '<p>Register your account:</p>';
}
buf += '<p><label class="label">Username: <strong><input type="text" name="name" value="' + BattleLog.escapeHTML(data.name || app.user.get('name')) + '" style="color:inherit;background:transparent;border:0;font:inherit;font-size:inherit;display:block" readonly autocomplete="username" /></strong></label></p>';
buf += '<p><label class="label">Password: <input class="textbox autofocus" type="password" name="password" autocomplete="new-password" /></label></p>';
buf += '<p><label class="label">Password (confirm): <input class="textbox" type="password" name="cpassword" autocomplete="new-password" /></label></p>';
buf += '<p><label class="label"><img src="' + Dex.resourcePrefix + 'sprites/gen5ani/pikachu.gif" alt="An Electric-type mouse that is the mascot of the Pok\u00E9mon franchise." /></label></p>';
buf += '<p><label class="label">What is this pokemon? <input class="textbox" type="text" name="captcha" value="' + BattleLog.escapeHTML(data.captcha) + '" /></label></p>';
buf += '<p class="buttonbar"><button type="submit" class="button"><strong>Register</strong></button> <button type="button" name="close" class="button">Cancel</button></p></form>';
this.$el.html(buf);
},
submit: function (data) {
var name = data.name;
var captcha = data.captcha;
$.post(app.user.getActionPHP(), {
act: 'register',
username: name,
password: data.password,
cpassword: data.cpassword,
captcha: captcha,
challstr: app.user.challstr
}, Storage.safeJSON(function (data) {
if (!data) data = {};
var token = data.assertion;
if (data.curuser && data.curuser.loggedin) {
app.user.set('registered', data.curuser);
var name = data.curuser.username;
app.send('/trn ' + name + ',1,' + token);
app.addPopupMessage("You have been successfully registered.");
} else {
app.addPopup(RegisterPopup, {
name: name,
captcha: captcha,
error: data.actionerror
});
}
}), 'text');
}
});
this.LoginPasswordPopup = Popup.extend({
type: 'semimodal',
showPassword: function () {
var $button = this.$('button[name=showPassword]');
var $password = this.$('input[name=password]');
if ($password.attr('type') === "password") {
$password.attr('type', 'text');
$button.attr('aria-label', "Hide password");
$button.html('<i class="fa fa-eye-slash"></i>');
} else {
$password.attr('type', 'password');
$button.attr('aria-label', "Show password");
$button.html('<i class="fa fa-eye"></i>');
}
},
initialize: function (data) {
var buf = '<form>';
if (data.error) {
buf += '<p class="error">' + BattleLog.escapeHTML(data.error) + '</p>';
if (data.error.indexOf(' forced you to change ') >= 0) {
buf += '<p>Keep in mind these rules:</p>';
buf += '<ol>';
buf += '<li>Usernames may not be derogatory or insulting in nature, to an individual or group (insulting yourself is okay as long as it\'s not too serious).</li>';
buf += '<li>Usernames may not reference sexual activity, directly or indirectly.</li>';
buf += '<li>Usernames may not impersonate a recognized user (a user with %, @, #, or & next to their name).</li>';
buf += '</ol>';
}
} else if (data.reason) {
buf += '<p>' + BattleLog.escapeHTML(data.reason) + '</p>';
} else {
buf += '<p class="error">The name you chose is registered.</p>';
}
buf += '<p>If this is your account:</p>';
buf += '<p><label class="label">Username: <strong><input type="text" name="username" value="' + BattleLog.escapeHTML(data.username) + '" style="color:inherit;background:transparent;border:0;font:inherit;font-size:inherit;display:block" readonly autocomplete="username" /></strong></label></p>';
if (data.special === '@gmail') {
buf += '<div id="g_id_onload" data-client_id="912270888098-jjnre816lsuhc5clj3vbcn4o2q7p4qvk.apps.googleusercontent.com" data-context="signin" data-ux_mode="popup" data-callback="gapiCallback" data-auto_prompt="false"></div>';
buf += '<div class="g_id_signin" data-type="standard" data-shape="pill" data-theme="filled_blue" data-text="continue_with" data-size="large" data-logo_alignment="left" data-auto_select="true" data-itp_support="true" style="width:fit-content;margin:0 auto">[loading Google log-in button]</div>';
buf += '<p class="buttonbar"><button name="close" class="button">Cancel</button></p>';
} else {
buf += '<p><label class="label">Password: <input class="textbox autofocus" type="password" name="password" autocomplete="current-password" style="width:173px"><button type="button" name="showPassword" aria-label="Show password" style="float:right;margin:-21px 0 10px;padding: 2px 6px" class="button"><i class="fa fa-eye"></i></button></label></p>';
buf += '<p class="buttonbar"><button type="submit" class="button"><strong>Log in</strong></button> <button type="button" name="close" class="button">Cancel</button></p>';
}
buf += '<p class="or">or</p>';
buf += '<p>If this is someone else\'s account:</p>';
buf += '<p class="buttonbar"><button type="button" name="login" class="button">Choose another name</button></p>';
buf += '</form>';
this.$el.html(buf);
if (data.special === '@gmail') {
var self = this;
window.gapiCallback = function (response) {
app.user.passwordRename(data.username, response.credential, data.special);
self.close();
};
var script = document.createElement('script');
script.async = true;
script.src = 'https://accounts.google.com/gsi/client';
document.getElementsByTagName('head')[0].appendChild(script);
}
},
login: function () {
this.close();
app.addPopup(LoginPopup);
},
submit: function (data) {
this.close();
app.user.passwordRename(data.username, data.password);
}
});
}).call(this, jQuery);