Options menu, sound menu, and registration

This commit is contained in:
Guangcong Luo
2013-05-07 00:47:47 -07:00
parent 40d3b9901d
commit e404f520f6
4 changed files with 346 additions and 42 deletions

View File

@@ -75,7 +75,7 @@ function BattleSoundLibrary() {
this.stopBgm();
}
this.bgm = this.loadBgm(url, loopstart, loopstop).setVolume(this.bgmVolume);
if (!this.mute) {
if (!this.muted) {
if (this.bgm.paused) {
this.bgm.resume();
} else {
@@ -97,9 +97,11 @@ function BattleSoundLibrary() {
// setting
this.setMute = function(muted) {
muted = !!muted;
if (this.muted == muted) return;
this.muted = muted;
if (muted) {
if (this.bgm) this.bgm.stop();
if (this.bgm) this.bgm.pause();
} else {
if (this.bgm) this.bgm.play();
}
@@ -4625,7 +4627,7 @@ function Battle(frame, logFrame, noPreload) {
} else if (message.substr(0,11).toLowerCase() === '/data-move ') {
self.log('<div class="chat"><ul class=\"utilichart\">'+Chart.moveRow(Tools.getMove(message.substr(11)),'',{})+'<li style=\"clear:both\"></li></ul></div>', preempt);
} else {
self.log('<div class="chat"><strong style="' + hashColor(toUserid(name)) + '">' + Tools.escapeHTML(name) + ':</strong> <em>' + messageSanitize(message) + '</em></div>', preempt);
self.log('<div class="chat"><strong style="' + hashColor(toUserid(name)) + '" class="username" data-name="'+Tools.escapeHTML(name)+'">' + Tools.escapeHTML(name) + ':</strong> <em>' + messageSanitize(message) + '</em></div>', preempt);
}
break;
case 'chatmsg':
@@ -4643,7 +4645,7 @@ function Battle(frame, logFrame, noPreload) {
self.log('<div class="chat"><strong>' + Tools.escapeHTML(args[1]) + ':</strong> <span class="message-pm"><i style="cursor:pointer" onclick="selectTab(\'lobby\');rooms.lobby.popupOpen(\'' + Tools.escapeHTML(args[2], true) + '\')">(Private to ' + Tools.escapeHTML(args[3]) + ')</i> ' + messageSanitize(args[4]) + '</span>');
break;
case 'askreg':
self.log('<div class="message-register-account"><b>Register an account to protect your ladder rating!</b><br /><button onclick="overlay(\'register\',{ifuserid:\''+Tools.escapeHTML(args[1], true)+'\'});return false"><b>Register</b></button></div>');
self.log('<div class="broadcast-blue"><b>Register an account to protect your ladder rating!</b><br /><button name="register" value="'+Tools.escapeHTML(args[1])+'"><b>Register</b></button></div>');
break;
case 'inactive':
self.kickingInactive = true;
@@ -4787,6 +4789,7 @@ function Battle(frame, logFrame, noPreload) {
return;
}
str = $.trim(str);
if (!str) return;
if (str.substr(0,1) === '|') {
var args = ['done'], kwargs = {};
str = $.trim(str.substr(1));

View File

@@ -15,7 +15,7 @@
this.$join = null;
this.$foeHint = this.$el.find('.foehint');
// BattleSound.setMute(me.isMuted());
BattleSound.setMute(Tools.prefs('mute'));
this.battle = new Battle(this.$battle, this.$chatFrame);
this.$chat = this.$chatFrame.find('.inner');
@@ -601,6 +601,13 @@
skipTurn: function() {
this.battle.skipTurn();
},
register: function(userid) {
var registered = app.user.get('registered');
if (registered && registered.userid !== userid) registered = false;
if (!registered && userid === app.user.get('userid')) {
app.addPopup('register', RegisterPopup);
}
},
// choice buttons
chooseMove: function(move) {
@@ -818,4 +825,57 @@
}
});
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 an account:</p>';
}
buf += '<p><label class="label">Username:</label> ' + (data.name || app.user.get('name')) + '<input type="hidden" name="name" value="' + Tools.escapeHTML(data.name || app.user.get('name')) + '" /></p>';
buf += '<p><label class="label">Password:</label> <input class="textbox" type="password" name="password" autofocus /></p>';
buf += '<p><label class="label">Password (confirm):</label> <input class="textbox" type="password" name="cpassword" /></p>';
buf += '<p><img src="' + Tools.resourcePrefix + 'sprites/bwani/pikachu.gif" /></p>';
buf += '<p><label class="label">What is this pokemon?</label> <input class="textbox" type="text" name="captcha" value="' + Tools.escapeHTML(data.captcha) + '" /></p>';
buf += '<p class="buttonbar"><button type="submit"><strong>Register</strong></button> <button name="close">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,
challengekeyid: app.user.challengekeyid,
challenge: app.user.challenge
}, Tools.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;
if (!app.socket) {
document.location.reload();
return;
}
app.send('/trn '+name+',1,'+token);
app.addPopupMessage("You have been successfully registered.");
} else {
app.addPopup('register', RegisterPopup, {
name: name,
captcha: captcha,
error: data.actionerror
});
}
}), 'text');
}
});
}).call(this, jQuery);

View File

@@ -28,6 +28,13 @@
named: false,
avatar: 0
},
initialize: function() {
app.on('response:userdetails', function(data) {
if (data.userid === this.get('userid')) {
this.set('avatar', data.avatar);
}
}, this);
},
/**
* Return the path to the login server `action.php` file. AJAX requests
* to this file will always be made on the `play.pokemonshowdown.com`
@@ -873,7 +880,7 @@
while (this.popups.length) {
var prevPopup = this.popups[this.popups.length-1];
if (prevPopup.id === id) {
var sourceEl = prevPopup.sourceEl[0];
var sourceEl = prevPopup.sourceEl ? prevPopup.sourceEl[0] : null;
this.popups.pop().remove();
if ($(data.sourceEl)[0] === sourceEl) return;
} else if (prevPopup.id !== id.substr(0,prevPopup.id.length)) {
@@ -901,9 +908,15 @@
}
}
if (popup.domInitialize) popup.domInitialize(data);
this.popups.push(popup);
return popup;
},
addPopupMessage: function(message) {
// shorthand for adding a popup message
// this is the equivalent of alert(message)
app.addPopup('message', Popup, {message: message});
},
closePopup: function(id) {
if (this.popups.length) {
var popup = this.popups.pop();
@@ -933,7 +946,7 @@
'click button': 'dispatchClickButton'
},
initialize: function() {
this.$el.html('<img class="logo" src="//dev.pokemonshowdown.com/pokemonshowdownbeta.png" alt="Pokemon Showdown! (beta)" /><div class="tabbar maintabbar"></div><!-- div class="tabbar sidetabbar" style="display:none"></div--><div class="userbar"></div>');
this.$el.html('<img class="logo" src="//dev.pokemonshowdown.com/pokemonshowdownbeta.png" alt="Pokemon Showdown! (beta)" /><div class="tabbar maintabbar"></div><div class="userbar"></div>');
this.$tabbar = this.$('.maintabbar');
// this.$sidetabbar = this.$('.sidetabbar');
this.$userbar = this.$('.userbar');
@@ -942,24 +955,35 @@
app.user.on('change', this.updateUserbar, this);
this.updateUserbar();
},
'$tabbar': null,
// userbar
updateUserbar: function() {
var buf = '';
var name = ' '+app.user.get('name');
var color = hashColor(app.user.get('userid'));
if (app.user.get('named')) {
buf = '<span class="username" data-name="'+Tools.escapeHTML(name)+'" style="'+color+'"><i class="icon-user" style="color:#779EC5"></i> '+Tools.escapeHTML(name)+'</span> <button name="logout">Log out</button>';
buf = '<span class="username" data-name="'+Tools.escapeHTML(name)+'" style="'+color+'"><i class="icon-user" style="color:#779EC5"></i> '+Tools.escapeHTML(name)+'</span> <button class="icon" name="openSounds"><i class="'+(Tools.prefs('mute')?'icon-volume-off':'icon-volume-up')+'"></i></button> <button class="icon" name="openOptions"><i class="icon-cog"></i></button>';
} else {
buf = '<button name="login">Choose name</button>';
buf = '<button name="login">Choose name</button> <button class="icon" name="openSounds"><i class="'+(Tools.prefs('mute')?'icon-volume-off':'icon-volume-up')+'"></i></button> <button class="icon" name="openOptions"><i class="icon-cog"></i></button>';
}
this.$userbar.html(buf);
},
login: function() {
app.addPopup('login', LoginPopup);
},
logout: function() {
app.user.logout();
openSounds: function() {
app.addPopup('sounds', SoundsPopup);
},
openOptions: function() {
app.addPopup('options', OptionsPopup);
},
clickUsername: function(e) {
e.stopPropagation();
var name = $(e.currentTarget).data('name');
app.addPopup('user', UserPopup, {name: name, sourceEl: e.currentTarget});
},
// tabbar
updateTabbar: function() {
var curId = (app.curRoom ? app.curRoom.id : '');
var curSideId = (app.curSideRoom ? app.curSideRoom.id : '');
@@ -1021,11 +1045,6 @@
delete app.dispatchingButton;
}
},
clickUsername: function(e) {
e.stopPropagation();
var name = $(e.currentTarget).data('name');
app.addPopup('user', UserPopup, {name: name, sourceEl: e.currentTarget});
},
click: function(e) {
e.preventDefault();
var $target = $(e.currentTarget);
@@ -1153,6 +1172,9 @@
Backbone.View.apply(this, arguments);
// if we have no source, we can't attach to anything
if (this.type === 'normal' && !this.sourceEl) this.type = 'semimodal';
if (this.type === 'normal') {
// nonmodal popup: should be positioned near source element
var $el = this.$el;
@@ -1186,6 +1208,10 @@
$measurer.remove();
}
},
initialize: function(data) {
this.type = 'semimodal';
this.$el.html('<p style="white-space:pre-wrap">'+Tools.escapeHTML(data.message)+'</p><p class="buttonbar"><button name="close" autofocus><strong>OK</strong></button></p>').css('max-width', 480);
},
dispatchClickButton: function(e) {
var target = e.currentTarget;
@@ -1237,7 +1263,8 @@
this.update();
},
events: {
'click .ilink': 'clickLink'
'click .ilink': 'clickLink',
'click .yours': 'avatars'
},
update: function(data) {
if (data && data.userid === this.data.userid) {
@@ -1261,7 +1288,7 @@
if (group || name.charAt(0) === ' ') name = name.substr(1);
var buf = '<div class="userdetails">';
if (avatar) buf += '<img class="trainersprite" src="'+Tools.resolveAvatar(avatar)+'" />';
if (avatar) buf += '<img class="trainersprite'+(userid===app.user.get('userid')?' yours':'')+'" src="'+Tools.resolveAvatar(avatar)+'" />';
buf += '<strong>' + Tools.escapeHTML(name) + '</strong><br />';
buf += '<small>' + (group || '&nbsp;') + '</small>';
if (data.rooms) {
@@ -1287,9 +1314,9 @@
buf += '</div>';
if (userid === app.user.get('userid') || !app.user.get('named')) {
buf += '<div class="buttonbar"><button disabled>Challenge</button> <button disabled>PM</button> <button name="close">Close</close></div>';
buf += '<p class="buttonbar"><button disabled>Challenge</button> <button disabled>PM</button> <button name="close">Close</button></p>';
} else {
buf += '<div class="buttonbar"><button name="challenge">Challenge</button> <button name="pm">PM</button> <button name="close">Close</close></div>';
buf += '<p class="buttonbar"><button name="challenge">Challenge</button> <button name="pm">PM</button> <button name="close">Close</button></p>';
}
this.$el.html(buf);
@@ -1301,6 +1328,9 @@
var roomid = $(e.currentTarget).attr('href').substr(app.root.length);
app.tryJoinRoom(roomid);
},
avatars: function() {
app.addPopup('user:avatars', AvatarsPopup);
},
challenge: function() {
this.close();
app.focusRoom('');
@@ -1347,6 +1377,7 @@
this.close();
}
});
var LoginPasswordPopup = this.LoginPasswordPopup = Popup.extend({
type: 'semimodal',
initialize: function(data) {
@@ -1389,4 +1420,151 @@
}
});
var SoundsPopup = this.SoundsPopup = Popup.extend({
initialize: function(data) {
var buf = '';
var muted = !!Tools.prefs('mute');
buf += '<p class="effect-volume"><label class="optlabel">Effect volume:</label>'+(muted?'<em>(muted)</em>':'<input type="slider" name="effectvolume" value="'+(Tools.prefs('effectvolume')||50)+'" />')+'</p>';
buf += '<p class="music-volume"><label class="optlabel">Music volume:</label>'+(muted?'<em>(muted)</em>':'<input type="slider" name="musicvolume" value="'+(Tools.prefs('musicvolume')||50)+'" />')+'</p>'
buf += '<p><label class="optlabel"><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'
},
domInitialize: function() {
var self = this;
this.$('.effect-volume input').slider({
from: 0,
to: 100,
step: 1,
dimension: '%',
skin: 'round_plastic',
onstatechange: function(val) {
self.setEffectVolume(val);
}
});
this.$('.music-volume input').slider({
from: 0,
to: 100,
step: 1,
dimension: '%',
skin: 'round_plastic',
onstatechange: function(val) {
self.setMusicVolume(val);
}
});
},
setMute: function(e) {
var muted = !!e.currentTarget.checked;
Tools.prefs('mute', muted);
BattleSound.setMute(muted);
if (!muted) {
this.$('.effect-volume').html('<label class="optlabel">Effect volume:</label><input type="slider" name="effectvolume" value="'+(Tools.prefs('effectvolume')||50)+'" />');
this.$('.music-volume').html('<label class="optlabel">Music volume:</label><input type="slider" name="musicvolume" value="'+(Tools.prefs('musicvolume')||50)+'" />');
this.domInitialize();
} 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>');
}
app.topbar.$('button[name=openSounds]').html('<i class="'+(muted?'icon-volume-off':'icon-volume-up')+'"></i>');
},
setEffectVolume: function(volume) {
BattleSound.setEffectVolume(volume);
Tools.prefs('effectvolume', volume);
},
setMusicVolume: function(volume) {
BattleSound.setBgmVolume(volume);
Tools.prefs('musicvolume', volume);
}
});
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=ignorespects]': 'setIgnoreSpects',
'change select[name=timestamps-lobby]': 'setTimestampsLobby',
'change select[name=timestamps-pms]': 'setTimestampsPMs',
'click img': 'avatars'
},
update: function() {
var name = app.user.get('name');
var avatar = app.user.get('avatar');
var buf = '';
buf += '<p>'+(avatar?'<img class="trainersprite" src="'+Tools.resolveAvatar(avatar)+'" width="40" height="40" style="vertical-align:middle" />':'')+'<strong>'+Tools.escapeHTML(name)+'</strong></p>';
buf += '<p><button name="avatars">Change avatar</button></p>';
buf += '<hr />';
buf += '<p><label class="optlabel"><input type="checkbox" name="noanim"'+(Tools.prefs('noanim')?' checked':'')+' /> Disable animations</label></p>';
var timestamps = this.timestamps = (Tools.prefs('timestamps') || {});
buf += '<p><label class="optlabel">Timestamps in lobby chat: <select name="timestamps-lobby"><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 PM\'s: <select name="timestamps-pms"><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>';
if (app.curRoom.battle) {
buf += '<hr />';
buf += '<h3>Current room</h3>';
buf += '<p><label class="optlabel"><input type="checkbox" name="ignorespects"'+(app.curRoom.battle.ignoreSpects?' checked':'')+'> Ignore spectators</label></p>';
}
buf += '<hr />';
buf += '<p class="buttonbar" style="text-align:right"><button name="logout"><strong>Log out</strong></button></p>';
this.$el.html(buf).css('min-width', 160);
},
setNoanim: function(e) {
var noanim = !!e.currentTarget.checked;
Tools.prefs('noanim', noanim);
},
setIgnoreSpects: function(e) {
if (app.curRoom.battle) {
app.curRoom.battle.ignoreSpects = !!e.currentTarget.checked;
}
},
setTimestampsLobby: function(e) {
this.timestamps.lobby = e.currentTarget.value;
},
setTimestampsPMs: function(e) {
this.timestamps.pms = e.currentTarget.value;
},
avatars: function() {
app.addPopup('options:avatars', AvatarsPopup);
},
logout: function() {
app.user.logout();
this.close();
}
});
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">Cancel</button></p>';
buf += '<div class="avatarlist">';
for (var i=1; i<=293; i++) {
var offset = '-'+(((i-1)%16)*80)+'px -'+(Math.floor((i-1)/16)*80)+'px'
buf += '<button name="setAvatar" value="'+i+'" style="background-position:'+offset+'"'+(i===cur?' class="cur"':'')+'></button>';
}
buf += '</div><div style="clear:left"></div>';
buf += '<p><button name="close">Cancel</button></p>';
this.$el.html(buf).css('max-width', 780);
},
setAvatar: function(i) {
app.send('/avatar '+i);
app.send('/cmd userdetails '+app.user.get('userid'));
this.close();
}
});
}).call(this, jQuery);

View File

@@ -88,6 +88,15 @@ body {
.username {
cursor: pointer;
}
.userbar button {
cursor: pointer;
}
.userbar button.icon {
height: 21px;
width: 23px;
font-size: 14px;
padding: 0;
}
.tabbar {
position: absolute;
@@ -313,7 +322,7 @@ body {
background: #E1E8E8;
color: black;
border: 1px solid #999999;
padding: 5px 10px;
padding: 2px 10px;
border-radius: 6px;
box-shadow: inset 1px 1px 0 #ffffff, inset -1px -1px 0 #DDDDDD, 2px 2px 3px rgba(0,0,0,.2);
@@ -321,12 +330,16 @@ body {
}
.ps-overlay .ps-popup {
position: static;
margin: 100px auto 0 auto;
margin: 100px auto 20px auto;
max-width: 320px;
}
.ps-popup p {
.ps-popup p,
.ps-popup h3 {
margin: 7px 0;
}
.ps-popup h3 {
font-size: 12pt;
}
p.or {
font-size: 12pt;
font-style: italic;
@@ -758,24 +771,6 @@ p.or:after {
* Chat
*********************************************************/
.userdetails {
min-height: 80px;
width: 191px;
padding: 1px 1px 1px 86px;
}
.userdetails img {
float: left;
margin-left: -85px;
}
.userdetails .rooms {
font-size: 8pt;
}
.userdetails .offline {
color: red;
}
.buttonbar {
clear: both;
}
.chat-log {
position: absolute;
top: 0;
@@ -1845,3 +1840,71 @@ a.ilink:hover {
width: 95px;
text-align: right;
}
/*********************************************************
* Popups
*********************************************************/
.userdetails {
min-height: 80px;
width: 191px;
padding: 1px 1px 1px 86px;
margin: 5px 0;
}
.userdetails img {
float: left;
margin-left: -85px;
}
.userdetails .rooms {
font-size: 8pt;
}
.userdetails .offline {
color: red;
}
.trainersprite.yours {
cursor: pointer;
}
.buttonbar {
clear: both;
}
.avatarlist button {
display: block;
float: left;
margin: 2px;
width: 80px;
height: 80px;
border: 1px solid #E1E8E8;
background: transparent url(//play.pokemonshowdown.com/sprites/trainers-sheet.png) no-repeat scroll 0px 0px;
border-radius: 4px;
box-shadow: none;
cursor: pointer;
}
.avatarlist button.cur {
border-color: #999999;
}
.avatarlist button:hover,
.avatarlist button.cur:hover {
border: 1px solid #8899AA;
background-color: #F1F4F9;
box-shadow: 1px 1px 1px #D5D5D5;
}
.effect-volume,
.music-volume {
height: 39px;
}
.effect-volume label,
.music-volume label {
padding-bottom: 12px;
font-size: 8pt;
}
.effect-volume em,
.music-volume em {
display: block;
margin-top: -6px;
font-size: 9pt;
padding-left: 5px;
color: #555555;
}