diff --git a/js/battle.js b/js/battle.js index b9a627583..fbeab73eb 100644 --- a/js/battle.js +++ b/js/battle.js @@ -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('
', preempt); } else { - self.log('
' + Tools.escapeHTML(name) + ': ' + messageSanitize(message) + '
', preempt); + self.log('
' + Tools.escapeHTML(name) + ': ' + messageSanitize(message) + '
', preempt); } break; case 'chatmsg': @@ -4643,7 +4645,7 @@ function Battle(frame, logFrame, noPreload) { self.log('
' + Tools.escapeHTML(args[1]) + ': (Private to ' + Tools.escapeHTML(args[3]) + ') ' + messageSanitize(args[4]) + ''); break; case 'askreg': - self.log('
Register an account to protect your ladder rating!
'); + self.log('
Register an account to protect your ladder rating!
'); 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)); diff --git a/js/client-battle.js b/js/client-battle.js index b7a8cd0f0..4fc9655df 100644 --- a/js/client-battle.js +++ b/js/client-battle.js @@ -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 = '
'; + if (data.error) { + buf += '

' + data.error + '

'; + } else if (data.reason) { + buf += '

' + data.reason + '

'; + } else { + buf += '

Register an account:

'; + } + buf += '

' + (data.name || app.user.get('name')) + '

'; + buf += '

'; + buf += '

'; + buf += '

'; + buf += '

'; + buf += '

'; + 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); diff --git a/js/client.js b/js/client.js index 909258d9f..23c3ef6b3 100644 --- a/js/client.js +++ b/js/client.js @@ -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('
'); + this.$el.html('
'); 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 = ' '+Tools.escapeHTML(name)+' '; + buf = ' '+Tools.escapeHTML(name)+' '; } else { - buf = ''; + buf = ' '; } 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('

'+Tools.escapeHTML(data.message)+'

').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 = '
'; - if (avatar) buf += ''; + if (avatar) buf += ''; buf += '' + Tools.escapeHTML(name) + '
'; buf += '' + (group || ' ') + ''; if (data.rooms) { @@ -1287,9 +1314,9 @@ buf += '
'; if (userid === app.user.get('userid') || !app.user.get('named')) { - buf += '
'; + buf += '

'; } else { - buf += '
'; + buf += '

'; } 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 += '

'+(muted?'(muted)':'')+'

'; + buf += '

'+(muted?'(muted)':'')+'

' + buf += '

'; + 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(''); + this.$('.music-volume').html(''); + this.domInitialize(); + } else { + this.$('.effect-volume').html('(muted)'); + this.$('.music-volume').html('(muted)'); + } + + app.topbar.$('button[name=openSounds]').html(''); + }, + 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 += '

'+(avatar?'':'')+''+Tools.escapeHTML(name)+'

'; + buf += '

'; + + buf += '
'; + buf += '

'; + + var timestamps = this.timestamps = (Tools.prefs('timestamps') || {}); + buf += '

'; + buf += '

'; + + if (app.curRoom.battle) { + buf += '
'; + buf += '

Current room

'; + buf += '

'; + } + + buf += '
'; + buf += '

'; + 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 += '

Choose an avatar or

'; + + buf += '
'; + for (var i=1; i<=293; i++) { + var offset = '-'+(((i-1)%16)*80)+'px -'+(Math.floor((i-1)/16)*80)+'px' + buf += ''; + } + buf += '
'; + + buf += '

'; + 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); diff --git a/style/client.css b/style/client.css index a9921bed6..716420d10 100644 --- a/style/client.css +++ b/style/client.css @@ -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; +}