Implement notifications

This commit is contained in:
Guangcong Luo
2013-05-08 21:21:19 -07:00
parent 880ca21e24
commit 63bbbb4ab5
5 changed files with 166 additions and 58 deletions

View File

@@ -106,9 +106,9 @@
this.$controls.html('');
return;
} else if (this.battle.playbackState === 2) {
} else if (this.battle.playbackState === 2 || this.battle.playbackState === 3) {
// battle is playing
// battle is playing or paused
this.$controls.html('<p><button name="skipTurn">Skip turn <i class="icon-step-forward"></i></button></p>');
return;
@@ -169,7 +169,6 @@
}
var battle = this.battle;
// this.notifying = false;
if (!this.choice) {
this.updateSide(this.request.side);
@@ -375,7 +374,6 @@
controls += '</div></div></div>';
this.$controls.html(controls);
}
this.notifying = true;
break;
case 'switch':
@@ -408,7 +406,6 @@
controls += '</div></div></div>';
this.$controls.html(controls);
this.selectSwitch();
this.notifying = true;
break;
case 'team':
@@ -455,7 +452,6 @@
controls += '</div></div>';
this.$controls.html(controls);
this.selectSwitch();
this.notifying = true;
break;
default:
@@ -484,23 +480,10 @@
var notifyObject = null;
if (request.forceSwitch) {
request.requestType = 'switch';
notifyObject = {
type: 'yourSwitch',
room: this.id
};
} else if (request.teamPreview) {
request.requestType = 'team';
notifyObject = {
type: 'yourSwitch',
room: this.id
};
} else if (request.wait) {
request.requestType = 'wait';
} else {
notifyObject = {
type: 'yourMove',
room: this.id
};
}
this.choice = null;
@@ -508,30 +491,22 @@
if (request.side) {
this.updateSideLocation(request.side, true);
}
// if (notifyObject) {
// var doNotify = function() {
// notify(notifyObject);
// this.notifying = true;
// updateRoomList();
// };
// if (this.battle.yourSide.initialized) {
// // The opponent's name is already known.
// notifyObject.user = this.battle.yourSide.name;
// doNotify();
// } else {
// // The opponent's name isn't known yet, so wait until it is
// // known before sending the notification, so that it can include
// // the opponent's name.
// var callback = this.battle.stagnateCallback;
// this.battle.stagnateCallback = function(battle) {
// notifyObject.user = battle.yourSide.name;
// doNotify();
// battle.stagnateCallback = callback;
// if (callback) callback(battle);
// };
// }
// }
this.notifyRequest();
},
notifyRequest: function() {
var oName = this.battle.yourSide.name;
if (oName) oName = " against "+oName;
switch (this.request.requestType) {
case 'move':
this.notify("Your move!", "Move in your battle"+oName, 'choice');
break;
case 'switch':
this.notify("Your switch!", "Switch in your battle"+oName, 'choice');
break;
case 'team':
this.notify("Team preview!", "Choose your team order in your battle"+oName, 'choice');
break;
}
},
updateSideLocation: function(sideData, midBattle) {
if (!sideData.id) return;
@@ -634,7 +609,7 @@
}
this.sendDecision('/choose '+this.choice.choices.join(','));
this.notifying = false;
this.closeNotification('choice');
this.finalDecision = false;
this.choice = {waiting: true};
@@ -665,7 +640,7 @@
}
this.sendDecision('/choose '+this.choice.choices.join(','));
this.notifying = false;
this.closeNotification('choice');
this.choice = {waiting: true};
this.updateControlsForPlayer();
@@ -691,14 +666,14 @@
}
this.sendDecision('/team '+(pos));
this.notifying = false;
this.closeNotification('choice');
this.choice = {waiting: true};
this.updateControlsForPlayer();
},
undoChoice: function(pos) {
this.send('/undo');
this.notifying = true;
this.notifyRequest();
this.choice = null;
this.updateControlsForPlayer();
@@ -706,7 +681,7 @@
leaveBattle: function() {
this.hideTooltip();
this.send('/leavebattle');
this.notifying = false;
this.closeNotification('choice');
},
selectSwitch: function() {
this.hideTooltip();

View File

@@ -482,10 +482,7 @@
var clickableName = '<span class="username" data-name="' + Tools.escapeHTML(name) + '">' + Tools.escapeHTML(name.substr(1)) + '</span>';
var isHighlighted = this.getHighlight(message);
if (isHighlighted) {
// notify({
// type: 'highlight',
// user: name
// });
this.notifyOnce("Mentioned by "+name, "\""+message+"\"", 'highlight');
}
var highlight = isHighlighted ? ' style="background-color:#FDA;"' : '';
var chatDiv = '<div class="chat"' + highlight + '>';

View File

@@ -53,6 +53,8 @@
var oName = name;
if (toId(name) === app.user.get('userid')) {
oName = target;
} else {
this.notifyOnce("PM from "+oName, "\""+message+"\"", 'pm');
}
var $pmWindow = this.openPM(oName, true);
@@ -228,6 +230,9 @@
var name = $pmWindow.data('name');
if (data.challengesFrom[userid]) {
var challenge = data.challengesFrom[userid];
if (!$pmWindow.find('.challenge').length) {
self.notifyOnce("Challenge from "+name, "Format: "+Tools.escapeFormat(challenge.format), 'challenge:'+userid);
}
var $challenge = self.openChallenge(name, $pmWindow);
var buf = '<form class="battleform"><p>'+Tools.escapeHTML(name)+' wants to battle!</p>';
buf += '<p><label class="label">Format:</label>'+self.renderFormats(challenge.format, true)+'</p>';
@@ -245,6 +250,7 @@
// or rejected it
$challenge.remove();
}
self.closeNotification('challenge:'+userid);
}
}
});
@@ -321,6 +327,7 @@
$challenge.html(buf);
},
acceptChallenge: function(i, target) {
this.requestNotifications();
var $pmWindow = $(target).closest('.pm-window');
var userid = $pmWindow.data('userid');
@@ -338,6 +345,7 @@
app.send('/reject '+userid);
},
makeChallenge: function(i, target) {
this.requestNotifications();
var $pmWindow = $(target).closest('.pm-window');
var userid = $pmWindow.data('userid');
var name = $pmWindow.data('name');
@@ -433,6 +441,7 @@
// buttons
search: function(i, button) {
this.requestNotifications();
var $searchForm = $(button).closest('form');
if ($searchForm.find('.cancel').length) {
return;

View File

@@ -20,6 +20,14 @@
return roomid.replace(/[^a-zA-Z0-9-]+/g, '');
}
// support Safari 6 notifications
// trying to use new-spec notifications on old versions of Chrome will crash
// certain older versions of Chrome and there doesn't appear to be a way to
// feature-detect them
if (!window.Notification && window.webkitNotification && navigator.userAgent.indexOf('Chrome') <= 0) {
window.Notification = window.webkitNotification;
}
var User = this.User = Backbone.Model.extend({
defaults: {
name: '',
@@ -204,6 +212,7 @@
routes: {
'*path': 'dispatchFragment'
},
focused: true,
initialize: function() {
window.app = this;
$('#main').html('');
@@ -229,6 +238,17 @@
self.addPopup('password', LoginPasswordPopup, {username: name});
});
$(window).on('focus click', function() {
if (!self.focused) {
self.focused = true;
self.curRoom.dismissNotification();
if (self.curSideRoom) self.curSideRoom.dismissNotification();
}
});
$(window).on('blur', function() {
self.focused = false;
});
this.initializeConnection();
Backbone.history.start({pushState: true});
},
@@ -988,9 +1008,9 @@
var curId = (app.curRoom ? app.curRoom.id : '');
var curSideId = (app.curSideRoom ? app.curSideRoom.id : '');
var buf = '<ul><li><a class="button'+(curId===''?' cur':'')+'" href="'+app.root+'"><i class="icon-home"></i> <span>Home</span></a></li>';
if (app.rooms.teambuilder) buf += '<li><a class="button'+(curId==='teambuilder'?' cur':'')+' closable" href="'+app.root+'teambuilder"><i class="icon-edit"></i> <span>Teambuilder</span></a><a class="closebutton" href="'+app.root+'teambuilder"><i class="icon-remove-sign"></i></a></li>';
if (app.rooms.ladder) buf += '<li><a class="button'+(curId==='ladder'?' cur':'')+' closable" href="'+app.root+'ladder"><i class="icon-list-ol"></i> <span>Ladder</span></a><a class="closebutton" href="'+app.root+'ladder"><i class="icon-remove-sign"></i></a></li>';
var buf = '<ul><li><a class="button'+(curId===''?' cur':'')+(app.rooms['']&&app.rooms[''].notifications?' notifying':'')+'" href="'+app.root+'"><i class="icon-home"></i> <span>Home</span></a></li>';
if (app.rooms['teambuilder']) buf += '<li><a class="button'+(curId==='teambuilder'?' cur':'')+' closable" href="'+app.root+'teambuilder"><i class="icon-edit"></i> <span>Teambuilder</span></a><a class="closebutton" href="'+app.root+'teambuilder"><i class="icon-remove-sign"></i></a></li>';
if (app.rooms['ladder']) buf += '<li><a class="button'+(curId==='ladder'?' cur':'')+' closable" href="'+app.root+'ladder"><i class="icon-list-ol"></i> <span>Ladder</span></a><a class="closebutton" href="'+app.root+'ladder"><i class="icon-remove-sign"></i></a></li>';
buf += '</ul>';
var atLeastOne = false;
var sideBuf = '';
@@ -1013,14 +1033,14 @@
name = '<i class="text">'+parts[0]+'</i><span>'+name+'</span>';
}
if (room.isSideRoom) {
sideBuf += '<li><a class="button'+(curId===id||curSideId===id?' cur':'')+' closable" href="'+app.root+id+'">'+name+'</a><a class="closebutton" href="'+app.root+id+'"><i class="icon-remove-sign"></i></a></li>';
sideBuf += '<li><a class="button'+(curId===id||curSideId===id?' cur':'')+(room.notifications?' notifying':'')+' closable" href="'+app.root+id+'">'+name+'</a><a class="closebutton" href="'+app.root+id+'"><i class="icon-remove-sign"></i></a></li>';
continue;
}
if (!atLeastOne) {
buf += '<ul>';
atLeastOne = true;
}
buf += '<li><a class="button'+(curId===id?' cur':'')+' closable" href="'+app.root+id+'">'+name+'</a><a class="closebutton" href="'+app.root+id+'"><i class="icon-remove-sign"></i></a></li>';
buf += '<li><a class="button'+(curId===id?' cur':'')+(room.notifications?' notifying':'')+' closable" href="'+app.root+id+'">'+name+'</a><a class="closebutton" href="'+app.root+id+'"><i class="icon-remove-sign"></i></a></li>';
}
if (atLeastOne) buf += '</ul>';
if (app.curSideRoom) {
@@ -1113,7 +1133,7 @@
//
},
// graphical
// layout
bestWidth: 659,
show: function(position, leftWidth) {
@@ -1130,6 +1150,7 @@
break;
}
this.$el.show();
this.dismissNotification();
this.focus();
},
hide: function() {
@@ -1141,9 +1162,105 @@
join: function() {},
leave: function() {},
// notifications
requestNotifications: function() {
if (window.Notification && Notification.requestPermission) {
Notification.requestPermission(function(permission) {});
}
},
notifications: null,
notify: function(title, body, tag, once) {
if (once && app.focused && (this === app.curRoom || this == app.curSideRoom)) return;
if (!tag) tag = 'message';
if (!this.notifications) this.notifications = {};
if (app.focused && (this === app.curRoom || this == app.curSideRoom)) {
this.notifications[tag] = {};
} else if (window.Notification) {
// old one doesn't need to be closed; sending the tag should
// automatically replace the old notification
var notification = this.notifications[tag] = new Notification(title, {
lang: 'en',
body: body,
tag: this.id+':'+tag,
});
var self = this;
notification.onclose = function() {
self.dismissNotification(tag);
};
notification.onclick = function() {
self.clickNotification(tag);
};
if (once) notification.psAutoclose = true;
} else if (window.macgap) {
macgap.growl.notify({
title: title,
content: body
});
this.notifications[tag] = {};
if (once) notification.psAutoclose = true;
} else {
this.notifications[tag] = {};
if (once) notification.psAutoclose = true;
}
app.topbar.updateTabbar();
},
notifyOnce: function(title, body, tag) {
return this.notify(title, body, tag, true);
},
closeNotification: function(tag, alreadyClosed) {
if (!this.notifications) return;
if (!tag) {
for (tag in this.notifications) {
if (this.notifications[tag].close) this.notifications[tag].close();
}
this.notifications = null;
app.topbar.updateTabbar();
return;
}
if (!this.notifications[tag]) return;
if (!alreadyClosed && this.notifications[tag].close) this.notifications[tag].close();
delete this.notifications[tag];
if (_.isEmpty(this.notifications)) {
this.notifications = null;
app.topbar.updateTabbar();
}
},
dismissNotification: function(tag) {
if (!this.notifications) return;
if (!tag) {
for (tag in this.notifications) {
if (!this.notifications[tag].psAutoclose) continue;
if (this.notifications[tag].close) this.notifications[tag].close();
delete this.notifications[tag];
}
if (_.isEmpty(this.notifications)) {
this.notifications = null;
app.topbar.updateTabbar();
}
return;
}
if (!this.notifications[tag]) return;
if (this.notifications[tag].close) this.notifications[tag].close();
if (this.notifications[tag].psAutoclose) {
delete this.notifications[tag];
if (_.isEmpty(this.notifications)) {
this.notifications = null;
app.topbar.updateTabbar();
}
} else {
this.notifications[tag] = {};
}
},
clickNotification: function(tag) {
this.dismissNotification(tag);
app.focusRoom(this.id);
},
// allocation
destroy: function() {
this.closeNotification();
this.leave();
this.remove();
delete this.app;
@@ -1332,11 +1449,13 @@
app.addPopup('user:avatars', AvatarsPopup);
},
challenge: function() {
app.rooms[''].requestNotifications();
this.close();
app.focusRoom('');
app.rooms[''].challenge(this.data.name);
},
pm: function() {
app.rooms[''].requestNotifications();
this.close();
app.focusRoom('');
app.rooms[''].focusPM(this.data.name);

View File

@@ -222,6 +222,14 @@ body {
background: linear-gradient(top, #cfcfcf, #f2f2f2);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#cfcfcf', endColorstr='#f2f2f2');
}
.tabbar a.button.notifying {
border-color: #AA8866;
background: #e3c3a3;
}
.tabbar a.button.notifying:hover {
border-color: #604020;
background: #cfaf8f;
}
.tabbar a.button.cur,
.tabbar a.button.cur:hover {
color: #777777;