This commit is contained in:
Lance Stout 2013-12-20 03:39:06 -08:00
parent 840f99608b
commit d88edee066
13 changed files with 215 additions and 95 deletions

View File

@ -31,9 +31,10 @@ module.exports = HumanModel.define({
}, },
props: { props: {
jid: ['object', true], jid: ['object', true],
status: ['string', true, ''], status: 'string',
avatarID: ['string', true, ''], avatarID: 'string',
rosterVer: ['string', true, ''] rosterVer: 'string',
nick: 'string'
}, },
session: { session: {
avatar: ['string', true, ''], avatar: ['string', true, ''],
@ -41,7 +42,6 @@ module.exports = HumanModel.define({
shouldAskForAlertsPermission: ['bool', true, false], shouldAskForAlertsPermission: ['bool', true, false],
hasFocus: ['bool', true, false], hasFocus: ['bool', true, false],
_activeContact: ['string', true, ''], _activeContact: ['string', true, ''],
displayName: ['string', true, 'Me'],
stream: 'object' stream: 'object'
}, },
collections: { collections: {
@ -51,9 +51,14 @@ module.exports = HumanModel.define({
calls: Calls calls: Calls
}, },
derived: { derived: {
displayName: {
deps: ['nick', 'jid'],
fn: function () {
return this.nick || this.jid.bare;
}
},
streamUrl: { streamUrl: {
deps: ['stream'], deps: ['stream'],
cache: true,
fn: function () { fn: function () {
if (!this.stream) return ''; if (!this.stream) return '';
return URL.createObjectURL(this.stream); return URL.createObjectURL(this.stream);

View File

@ -132,6 +132,7 @@ module.exports = BasePage.extend(chatHelpers).extend({
if (!this.typing || this.paused) { if (!this.typing || this.paused) {
this.typing = true; this.typing = true;
this.paused = false; this.paused = false;
this.$chatInput.addClass('typing');
client.sendMessage({ client.sendMessage({
to: this.model.lockedResource || this.model.jid, to: this.model.lockedResource || this.model.jid,
chatState: 'composing' chatState: 'composing'
@ -143,6 +144,7 @@ module.exports = BasePage.extend(chatHelpers).extend({
this.resizeInput(); this.resizeInput();
if (this.typing && this.$chatInput.val().length === 0) { if (this.typing && this.$chatInput.val().length === 0) {
this.typing = false; this.typing = false;
this.$chatInput.removeClass('typing');
client.sendMessage({ client.sendMessage({
to: this.model.lockedResource || this.model.jid, to: this.model.lockedResource || this.model.jid,
chatState: 'active' chatState: 'active'
@ -192,6 +194,7 @@ module.exports = BasePage.extend(chatHelpers).extend({
this.editMode = false; this.editMode = false;
this.typing = false; this.typing = false;
this.paused = false; this.paused = false;
this.$chatInput.removeClass('typing');
this.$chatInput.removeClass('editing'); this.$chatInput.removeClass('editing');
this.$chatInput.val(''); this.$chatInput.val('');
}, },

View File

@ -11,6 +11,7 @@ module.exports = Backbone.Router.extend({
routes: { routes: {
'': 'main', '': 'main',
'chat/:jid': 'chat', 'chat/:jid': 'chat',
'chat/:jid/:resource': 'chat',
'groupchat/:jid': 'groupchat', 'groupchat/:jid': 'groupchat',
'logout': 'logout' 'logout': 'logout'
}, },

View File

@ -13,7 +13,7 @@ exports.pages = {};
exports.body = function anonymous(locals) { exports.body = function anonymous(locals) {
var buf = []; var buf = [];
with (locals || {}) { with (locals || {}) {
buf.push('<body><div id="connectionOverlay"><aside id="connectionStatus" class="box"><p> \nYou\'re currently <strong>disconnected</strong></p><button class="primary reconnect">Reconnect</button></aside></div><header id="calls"></header><div id="wrapper"><aside id="menu"><nav class="main"><li><a href="/logout" class="button secondary">Logout</a></li><li><a href="/" class="button secondary"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewbox="0 0 25 25" height="25" width="25"><g transform="scale(0.4)"><path d="M37.418,34.3c-2.1-2.721-2.622-6.352-1.292-9.604c0.452-1.107,1.104-2.1,1.902-2.951 c-0.753-0.877-1.573-1.697-2.507-2.387l-2.609,1.408c-1.05-0.629-2.194-1.112-3.414-1.421l-0.845-2.833 c-0.75-0.112-1.512-0.188-2.287-0.188c-0.783,0-1.54,0.075-2.288,0.188l-0.851,2.833c-1.215,0.309-2.355,0.792-3.41,1.421 l-2.614-1.408c-1.229,0.912-2.318,2-3.228,3.231l1.404,2.612c-0.628,1.053-1.11,2.193-1.419,3.411l-2.832,0.849 c-0.114,0.75-0.187,1.508-0.187,2.287c0,0.778,0.073,1.537,0.187,2.286l2.832,0.848c0.309,1.22,0.791,2.36,1.419,3.413l-1.404,2.61 c0.909,1.231,1.999,2.321,3.228,3.231l2.614-1.406c1.055,0.628,2.195,1.11,3.41,1.42l0.851,2.832 c0.748,0.114,1.505,0.188,2.288,0.188c0.775,0,1.537-0.074,2.287-0.188l0.845-2.832c1.224-0.31,2.364-0.792,3.414-1.42l0.062,0.033 l2.045-3.02L37.418,34.3z M26.367,36.776c-2.777,0-5.027-2.253-5.027-5.027c0-2.775,2.25-5.028,5.027-5.028 c2.774,0,5.024,2.253,5.024,5.028C31.391,34.523,29.141,36.776,26.367,36.776z"></path><path d="M51.762,24.505l-1.125-0.459l-1.451,3.55c-0.814,1.993-2.832,3.054-4.505,2.37l-0.355-0.144 c-1.673-0.686-2.37-2.856-1.558-4.849l1.451-3.551l-1.125-0.46c-2.225,0.608-4.153,2.2-5.092,4.501 c-1.225,2.997-0.422,6.312,1.771,8.436l-2.958,6.812l-2.204,3.249l-0.007,2.281l5.275,2.154l1.593-1.633l0.7-3.861l2.901-6.836 c3.049,0.018,5.947-1.785,7.174-4.779C53.186,28.983,52.924,26.499,51.762,24.505z"></path></g></svg>Settings</a></li></nav><section id="roster"><h1>Roster</h1><nav></nav></section><section id="bookmarks"><h1>Bookmarks</h1><nav></nav></section></aside><main id="pages"></main></div></body>'); buf.push('<body><div id="connectionOverlay"><aside id="connectionStatus" class="box"><p> \nYou\'re currently <strong>disconnected</strong></p><button class="primary reconnect">Reconnect</button></aside></div><div id="wrapper"><aside id="menu"><nav class="main"><li><a href="/logout" class="button secondary">Logout</a></li><li><a href="/" class="button secondary"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewbox="0 0 25 25" height="25" width="25"><g transform="scale(0.4)"><path d="M37.418,34.3c-2.1-2.721-2.622-6.352-1.292-9.604c0.452-1.107,1.104-2.1,1.902-2.951 c-0.753-0.877-1.573-1.697-2.507-2.387l-2.609,1.408c-1.05-0.629-2.194-1.112-3.414-1.421l-0.845-2.833 c-0.75-0.112-1.512-0.188-2.287-0.188c-0.783,0-1.54,0.075-2.288,0.188l-0.851,2.833c-1.215,0.309-2.355,0.792-3.41,1.421 l-2.614-1.408c-1.229,0.912-2.318,2-3.228,3.231l1.404,2.612c-0.628,1.053-1.11,2.193-1.419,3.411l-2.832,0.849 c-0.114,0.75-0.187,1.508-0.187,2.287c0,0.778,0.073,1.537,0.187,2.286l2.832,0.848c0.309,1.22,0.791,2.36,1.419,3.413l-1.404,2.61 c0.909,1.231,1.999,2.321,3.228,3.231l2.614-1.406c1.055,0.628,2.195,1.11,3.41,1.42l0.851,2.832 c0.748,0.114,1.505,0.188,2.288,0.188c0.775,0,1.537-0.074,2.287-0.188l0.845-2.832c1.224-0.31,2.364-0.792,3.414-1.42l0.062,0.033 l2.045-3.02L37.418,34.3z M26.367,36.776c-2.777,0-5.027-2.253-5.027-5.027c0-2.775,2.25-5.028,5.027-5.028 c2.774,0,5.024,2.253,5.024,5.028C31.391,34.523,29.141,36.776,26.367,36.776z"></path><path d="M51.762,24.505l-1.125-0.459l-1.451,3.55c-0.814,1.993-2.832,3.054-4.505,2.37l-0.355-0.144 c-1.673-0.686-2.37-2.856-1.558-4.849l1.451-3.551l-1.125-0.46c-2.225,0.608-4.153,2.2-5.092,4.501 c-1.225,2.997-0.422,6.312,1.771,8.436l-2.958,6.812l-2.204,3.249l-0.007,2.281l5.275,2.154l1.593-1.633l0.7-3.861l2.901-6.836 c3.049,0.018,5.947-1.785,7.174-4.779C53.186,28.983,52.924,26.499,51.762,24.505z"></path></g></svg>Settings</a></li></nav><section id="roster"><h1>Roster</h1><nav></nav></section><section id="bookmarks"><h1>Bookmarks</h1><nav></nav></section></aside><header id="me"><h1><img class="avatar"/><span class="name"></span><span contenteditable="true" class="status"></span></h1></header></div><main id="pages"></main></body>');
} }
return buf.join(""); return buf.join("");
}; };

View File

@ -5,7 +5,6 @@ body
| You're currently | You're currently
strong disconnected strong disconnected
button.primary.reconnect Reconnect button.primary.reconnect Reconnect
header#calls
#wrapper #wrapper
aside#menu aside#menu
nav.main nav.main
@ -24,4 +23,9 @@ body
section#bookmarks section#bookmarks
h1 Bookmarks h1 Bookmarks
nav nav
main#pages header#me
h1
img.avatar
span.name
span.status(contenteditable="true")
main#pages

View File

@ -16,7 +16,8 @@ module.exports = HumanView.extend({
}, },
events: { events: {
'click a[href]': 'handleLinkClick', 'click a[href]': 'handleLinkClick',
'click .reconnect': 'handleReconnect' 'click .reconnect': 'handleReconnect',
'blur #me .status': 'handleStatusChange'
}, },
classBindings: { classBindings: {
connected: '#connectionOverlay', connected: '#connectionOverlay',
@ -28,7 +29,16 @@ module.exports = HumanView.extend({
this.renderAndBind(); this.renderAndBind();
this.renderCollection(me.contacts, ContactListItem, this.$('#roster nav')); this.renderCollection(me.contacts, ContactListItem, this.$('#roster nav'));
this.renderCollection(me.mucs, MUCListItem, this.$('#bookmarks nav')); this.renderCollection(me.mucs, MUCListItem, this.$('#bookmarks nav'));
//this.renderCollection(me.calls, CallView, this.$('#calls'));
this.registerBindings(me, {
textBindings: {
displayName: '#me .name',
status: '#me .status'
},
srcBindings: {
avatar: '#me .avatar'
}
});
return this; return this;
}, },
handleReconnect: function (e) { handleReconnect: function (e) {
@ -49,5 +59,13 @@ module.exports = HumanView.extend({
handleTitle: function (e) { handleTitle: function (e) {
document.title = app.state.title; document.title = app.state.title;
app.desktop.updateBadge(app.state.badge); app.desktop.updateBadge(app.state.badge);
},
handleStatusChange: function (e) {
var text = e.target.textContent;
me.status = text;
client.sendPresence({
status: text,
caps: client.disco.caps
});
} }
}); });

View File

@ -701,7 +701,7 @@ button.secondary:hover:not(:disabled) {
} }
#roster li.paused:after, #roster li.paused:after,
#bookmarks li.paused:after { #bookmarks li.paused:after {
background: #878787; background: #ababab;
} }
#roster li.idle, #roster li.idle,
#bookmarks li.idle { #bookmarks li.idle {
@ -868,11 +868,8 @@ button.secondary:hover:not(:disabled) {
overflow-x: hidden; overflow-x: hidden;
} }
.conversation { .conversation {
bottom: 0px;
left: 0px;
right: 0px;
padding: 0px; padding: 0px;
width: 100%; overflow: hidden;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
@ -880,8 +877,9 @@ button.secondary:hover:not(:disabled) {
.conversation header { .conversation header {
padding: 0px; padding: 0px;
padding-left: 6px; padding-left: 6px;
border-bottom: 2px solid #eee; border-bottom: 1px solid #d6d6d6;
position: fixed; position: fixed;
top: 40px;
right: 0px; right: 0px;
left: 201px; left: 201px;
z-index: 10; z-index: 10;
@ -890,11 +888,7 @@ button.secondary:hover:not(:disabled) {
box-sizing: border-box; box-sizing: border-box;
background: #f7f7f7; background: #f7f7f7;
} }
.conversation header.online:not(.idle):before, .conversation header:before {
.conversation header.chat:before,
.conversation header.dnd:before,
.conversation header.away:before,
.conversation header.xa:before {
content: ''; content: '';
position: absolute; position: absolute;
top: 50%; top: 50%;
@ -920,29 +914,17 @@ button.secondary:hover:not(:disabled) {
.conversation header.xa:before { .conversation header.xa:before {
background: #f18902; background: #f18902;
} }
.conversation header.offline:not(:hover) .name { .conversation header.offline:before {
color: #515151; background: #2d2d2d;
}
.conversation header.offline:not(:hover) .status {
color: #2f2f2f;
}
.conversation header.offline:not(:hover) .avatar {
opacity: 0.25;
} }
.conversation header.composing:before { .conversation header.composing:before {
animation: pulsate 1.5s infinite ease-in; animation: pulsate 1.5s infinite ease-in;
-webkit-animation: pulsate 1.5s infinite ease-in; -webkit-animation: pulsate 1.5s infinite ease-in;
-moz-animation: pulsate 1.5s infinite ease-in; -moz-animation: pulsate 1.5s infinite ease-in;
} }
.conversation header.paused:before { .conversation header.paused:before,
background: #878787; .conversation header.idle:before {
} background: #ababab;
.conversation header.idle {
padding-right: 15px;
}
.conversation header.idle .name {
color: #878787;
max-width: 60%;
} }
.conversation header .controls { .conversation header .controls {
float: right; float: right;
@ -1070,11 +1052,10 @@ button.secondary:hover:not(:disabled) {
padding: 0px; padding: 0px;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
position: absolute; position: fixed;
top: 0px; top: 0px;
bottom: 55px; bottom: 55px;
padding-top: 35px; padding-top: 75px;
width: 100%;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
@ -1208,7 +1189,6 @@ button.secondary:hover:not(:disabled) {
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
border-top: 1px solid #eee;
bottom: 0px; bottom: 0px;
position: fixed; position: fixed;
right: 0px; right: 0px;
@ -1231,7 +1211,8 @@ button.secondary:hover:not(:disabled) {
height: 30px; height: 30px;
padding: 6px 10px; padding: 6px 10px;
} }
.chatBox textarea:focus { .chatBox textarea.typing:focus,
.chatBox textarea.editing:focus {
transition: none; transition: none;
-webkit-transition: none; -webkit-transition: none;
} }
@ -1476,3 +1457,65 @@ rgba(0,0,0,0.7)
right: 40px; right: 40px;
margin: 0; margin: 0;
} }
#me {
position: fixed;
left: 200px;
top: 0px;
height: 40px;
width: 100%;
background-color: #fff;
border-bottom: 1px solid #d6d6d6;
z-index: 100;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
color: #fff;
}
#me .avatar {
width: 30px;
height: 30px;
vertical-align: middle;
margin-right: 5px;
-moz-border-radius: 15px;
-webkit-border-radius: 15px;
-khtml-border-radius: 15px;
-o-border-radius: 15px;
-border-radius: 15px;
border-radius: 15px;
}
#me h1 {
font-size: 13px;
line-height: 12px;
margin: 5px;
padding: 0px;
white-space: nowrap;
max-width: 75%;
}
#me .status {
font-weight: normal;
font-size: 12px;
line-height: 12px;
border-width: 0px;
margin: 0px;
padding: 0px;
line-height: 20px;
height: 20px;
max-width: 75%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#me .status:before {
content: '-';
padding-left: 5px;
padding-right: 5px;
}
#me .name:focus,
#me .status:focus {
background-color: #fffcea;
border: 1px solid #efe391;
color: #d2bd2d;
}

View File

@ -12,3 +12,4 @@
@import 'pages/settings' @import 'pages/settings'
@import 'pages/aux' @import 'pages/aux'
@import 'pages/callbar' @import 'pages/callbar'
@import 'pages/header'

View File

@ -8,74 +8,55 @@
overflow-x: hidden overflow-x: hidden
.conversation .conversation
bottom: 0px
left: 0px
right: 0px
padding: 0px padding: 0px
width: 100% overflow: hidden
borderbox() borderbox()
header header
padding: 0px padding: 0px
padding-left: 6px padding-left: 6px
border-bottom: 2px solid $gray-lighter border-bottom: 1px solid darken($gray-lighter, 10%)
position: fixed position: fixed
top: 40px
right: 0px right: 0px
left: 201px left: 201px
z-index: 10 z-index: 10
borderbox() borderbox()
background: lighten($gray-light, 93%) background: lighten($gray-light, 93%)
&.online:not(.idle), &.chat, &.dnd, &.away, &.xa &:before
&:before content: ''
content: '' position: absolute
position: absolute top: 50%
top: 50% left: 5px
left: 5px height: 6px
height: 6px width: 6px
width: 6px margin-top: -3px
margin-top: -3px roundall(10px)
roundall(10px)
&.online, &.online,
&.chat &.chat
&:before &:before
background: $green background: $green
&.dnd &.dnd:before
&:before background: $red
background: $red
&.away, &.away:before,
&.xa &.xa:before
&:before background: $orange
background: $orange
&.offline:not(:hover) &.offline:before
.name background: $gray-dark
color: darken($gray-light, 40%)
.status &.composing:before
color: darken($gray-light, 65%) animation: pulsate 1.5s infinite ease-in
-webkit-animation: pulsate 1.5s infinite ease-in
-moz-animation: pulsate 1.5s infinite ease-in
.avatar &.paused:before,
opacity: .25 &.idle:before
background: lighten($gray-light, 30%)
&.composing
&:before
animation: pulsate 1.5s infinite ease-in
-webkit-animation: pulsate 1.5s infinite ease-in
-moz-animation: pulsate 1.5s infinite ease-in
&.paused
&:before
background: $gray-light
&.idle
padding-right: 15px
.name
color: $gray-light
max-width: 60%
.controls .controls
float: right float: right
@ -192,11 +173,10 @@
padding: 0px padding: 0px
overflow-y: auto overflow-y: auto
overflow-x: hidden overflow-x: hidden
position: absolute position: fixed
top: 0px top: 0px
bottom: 55px bottom: 55px
padding-top: 35px padding-top: 75px
width: 100%
borderbox() borderbox()
-webkit-overflow-scrolling: touch -webkit-overflow-scrolling: touch
@ -317,7 +297,6 @@
.chatBox .chatBox
borderbox() borderbox()
border-top: 1px solid $gray-lighter
bottom: 0px bottom: 0px
position: fixed position: fixed
right: 0px right: 0px
@ -338,7 +317,8 @@
height: 30px height: 30px
padding: 6px 10px padding: 6px 10px
&:focus &.typing:focus,
&.editing:focus
transition: none transition: none
-webkit-transition: none -webkit-transition: none

View File

@ -0,0 +1,9 @@
#me {
position: fixed;
left: 0px;
right: 0px;
top: 0px;
height: 40px;
background-color: #fff;
border-bottom: 1px solid #d6d6d6;
}

View File

@ -0,0 +1,56 @@
@import '../_variables'
@import '../_mixins'
#me
position: fixed
left: 200px
top: 0px
height: 40px
width: 100%
background-color: #fff
border-bottom: 1px solid darken($gray-lighter, 10%)
z-index: 100
noselect()
color: #fff
.avatar
width: 30px
height: 30px
vertical-align: middle
margin-right: 5px
roundall(15px)
h1
font-size: 13px
line-height: 12px
margin: 5px
padding: 0px
white-space: nowrap
max-width: 75%
.status
font-weight: normal
font-size: 12px
line-height: 12px
border-width: 0px
margin: 0px
padding: 0px
line-height: 20px
height: 20px
max-width: 75%
white-space: nowrap
overflow: hidden
text-overflow: ellipsis
&:before
content: '-'
padding-left: 5px
padding-right: 5px
.name,
.status
&:focus
background-color: #fffcea
border: 1px solid #efe391
color: #d2bd2d

View File

@ -121,7 +121,7 @@
&.paused &.paused
&:after &:after
background: $gray-light background: lighten($gray-light, 30%)
&.idle &.idle
padding-right: 15px padding-right: 15px

View File

@ -1,5 +1,5 @@
CACHE MANIFEST CACHE MANIFEST
# 0.0.1 1387527074335 # 0.0.1 1387539451203
CACHE: CACHE:
/app.js /app.js