diff --git a/clientapp/models/me.js b/clientapp/models/me.js index 7cfeeca..f3f921c 100644 --- a/clientapp/models/me.js +++ b/clientapp/models/me.js @@ -31,9 +31,10 @@ module.exports = HumanModel.define({ }, props: { jid: ['object', true], - status: ['string', true, ''], - avatarID: ['string', true, ''], - rosterVer: ['string', true, ''] + status: 'string', + avatarID: 'string', + rosterVer: 'string', + nick: 'string' }, session: { avatar: ['string', true, ''], @@ -41,7 +42,6 @@ module.exports = HumanModel.define({ shouldAskForAlertsPermission: ['bool', true, false], hasFocus: ['bool', true, false], _activeContact: ['string', true, ''], - displayName: ['string', true, 'Me'], stream: 'object' }, collections: { @@ -51,9 +51,14 @@ module.exports = HumanModel.define({ calls: Calls }, derived: { + displayName: { + deps: ['nick', 'jid'], + fn: function () { + return this.nick || this.jid.bare; + } + }, streamUrl: { deps: ['stream'], - cache: true, fn: function () { if (!this.stream) return ''; return URL.createObjectURL(this.stream); diff --git a/clientapp/pages/chat.js b/clientapp/pages/chat.js index 45f5979..a4176be 100644 --- a/clientapp/pages/chat.js +++ b/clientapp/pages/chat.js @@ -132,6 +132,7 @@ module.exports = BasePage.extend(chatHelpers).extend({ if (!this.typing || this.paused) { this.typing = true; this.paused = false; + this.$chatInput.addClass('typing'); client.sendMessage({ to: this.model.lockedResource || this.model.jid, chatState: 'composing' @@ -143,6 +144,7 @@ module.exports = BasePage.extend(chatHelpers).extend({ this.resizeInput(); if (this.typing && this.$chatInput.val().length === 0) { this.typing = false; + this.$chatInput.removeClass('typing'); client.sendMessage({ to: this.model.lockedResource || this.model.jid, chatState: 'active' @@ -192,6 +194,7 @@ module.exports = BasePage.extend(chatHelpers).extend({ this.editMode = false; this.typing = false; this.paused = false; + this.$chatInput.removeClass('typing'); this.$chatInput.removeClass('editing'); this.$chatInput.val(''); }, diff --git a/clientapp/router.js b/clientapp/router.js index 0d0a630..aaa2e02 100644 --- a/clientapp/router.js +++ b/clientapp/router.js @@ -11,6 +11,7 @@ module.exports = Backbone.Router.extend({ routes: { '': 'main', 'chat/:jid': 'chat', + 'chat/:jid/:resource': 'chat', 'groupchat/:jid': 'groupchat', 'logout': 'logout' }, diff --git a/clientapp/templates.js b/clientapp/templates.js index c8ed69f..c3a58b9 100644 --- a/clientapp/templates.js +++ b/clientapp/templates.js @@ -13,7 +13,7 @@ exports.pages = {}; exports.body = function anonymous(locals) { var buf = []; with (locals || {}) { - buf.push('
'); + buf.push('

'); } return buf.join(""); }; diff --git a/clientapp/templates/body.jade b/clientapp/templates/body.jade index 1fb4df2..7edc118 100644 --- a/clientapp/templates/body.jade +++ b/clientapp/templates/body.jade @@ -5,7 +5,6 @@ body | You're currently strong disconnected button.primary.reconnect Reconnect - header#calls #wrapper aside#menu nav.main @@ -24,4 +23,9 @@ body section#bookmarks h1 Bookmarks nav - main#pages + header#me + h1 + img.avatar + span.name + span.status(contenteditable="true") + main#pages diff --git a/clientapp/views/main.js b/clientapp/views/main.js index e575748..61e5352 100644 --- a/clientapp/views/main.js +++ b/clientapp/views/main.js @@ -16,7 +16,8 @@ module.exports = HumanView.extend({ }, events: { 'click a[href]': 'handleLinkClick', - 'click .reconnect': 'handleReconnect' + 'click .reconnect': 'handleReconnect', + 'blur #me .status': 'handleStatusChange' }, classBindings: { connected: '#connectionOverlay', @@ -28,7 +29,16 @@ module.exports = HumanView.extend({ this.renderAndBind(); this.renderCollection(me.contacts, ContactListItem, this.$('#roster 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; }, handleReconnect: function (e) { @@ -49,5 +59,13 @@ module.exports = HumanView.extend({ handleTitle: function (e) { document.title = app.state.title; 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 + }); } }); diff --git a/public/css/otalk.css b/public/css/otalk.css index 1e3fae0..8fc458c 100644 --- a/public/css/otalk.css +++ b/public/css/otalk.css @@ -701,7 +701,7 @@ button.secondary:hover:not(:disabled) { } #roster li.paused:after, #bookmarks li.paused:after { - background: #878787; + background: #ababab; } #roster li.idle, #bookmarks li.idle { @@ -868,11 +868,8 @@ button.secondary:hover:not(:disabled) { overflow-x: hidden; } .conversation { - bottom: 0px; - left: 0px; - right: 0px; padding: 0px; - width: 100%; + overflow: hidden; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; @@ -880,8 +877,9 @@ button.secondary:hover:not(:disabled) { .conversation header { padding: 0px; padding-left: 6px; - border-bottom: 2px solid #eee; + border-bottom: 1px solid #d6d6d6; position: fixed; + top: 40px; right: 0px; left: 201px; z-index: 10; @@ -890,11 +888,7 @@ button.secondary:hover:not(:disabled) { box-sizing: border-box; background: #f7f7f7; } -.conversation header.online:not(.idle):before, -.conversation header.chat:before, -.conversation header.dnd:before, -.conversation header.away:before, -.conversation header.xa:before { +.conversation header:before { content: ''; position: absolute; top: 50%; @@ -920,29 +914,17 @@ button.secondary:hover:not(:disabled) { .conversation header.xa:before { background: #f18902; } -.conversation header.offline:not(:hover) .name { - color: #515151; -} -.conversation header.offline:not(:hover) .status { - color: #2f2f2f; -} -.conversation header.offline:not(:hover) .avatar { - opacity: 0.25; +.conversation header.offline:before { + background: #2d2d2d; } .conversation header.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; } -.conversation header.paused:before { - background: #878787; -} -.conversation header.idle { - padding-right: 15px; -} -.conversation header.idle .name { - color: #878787; - max-width: 60%; +.conversation header.paused:before, +.conversation header.idle:before { + background: #ababab; } .conversation header .controls { float: right; @@ -1070,11 +1052,10 @@ button.secondary:hover:not(:disabled) { padding: 0px; overflow-y: auto; overflow-x: hidden; - position: absolute; + position: fixed; top: 0px; bottom: 55px; - padding-top: 35px; - width: 100%; + padding-top: 75px; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; @@ -1208,7 +1189,6 @@ button.secondary:hover:not(:disabled) { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; - border-top: 1px solid #eee; bottom: 0px; position: fixed; right: 0px; @@ -1231,7 +1211,8 @@ button.secondary:hover:not(:disabled) { height: 30px; padding: 6px 10px; } -.chatBox textarea:focus { +.chatBox textarea.typing:focus, +.chatBox textarea.editing:focus { transition: none; -webkit-transition: none; } @@ -1476,3 +1457,65 @@ rgba(0,0,0,0.7) right: 40px; 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; +} diff --git a/public/css/otalk.styl b/public/css/otalk.styl index c32dd5e..595edd6 100644 --- a/public/css/otalk.styl +++ b/public/css/otalk.styl @@ -12,3 +12,4 @@ @import 'pages/settings' @import 'pages/aux' @import 'pages/callbar' +@import 'pages/header' diff --git a/public/css/pages/chat.styl b/public/css/pages/chat.styl index 4c9d038..c103d38 100644 --- a/public/css/pages/chat.styl +++ b/public/css/pages/chat.styl @@ -8,74 +8,55 @@ overflow-x: hidden .conversation - bottom: 0px - left: 0px - right: 0px padding: 0px - width: 100% + overflow: hidden borderbox() header padding: 0px padding-left: 6px - border-bottom: 2px solid $gray-lighter + border-bottom: 1px solid darken($gray-lighter, 10%) position: fixed + top: 40px right: 0px left: 201px z-index: 10 borderbox() background: lighten($gray-light, 93%) - &.online:not(.idle), &.chat, &.dnd, &.away, &.xa - &:before - content: '' - position: absolute - top: 50% - left: 5px - height: 6px - width: 6px - margin-top: -3px - roundall(10px) + &:before + content: '' + position: absolute + top: 50% + left: 5px + height: 6px + width: 6px + margin-top: -3px + roundall(10px) &.online, &.chat &:before background: $green - &.dnd - &:before - background: $red + &.dnd:before + background: $red - &.away, - &.xa - &:before - background: $orange + &.away:before, + &.xa:before + background: $orange - &.offline:not(:hover) - .name - color: darken($gray-light, 40%) + &.offline:before + background: $gray-dark - .status - color: darken($gray-light, 65%) + &.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 - .avatar - opacity: .25 - - &.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% + &.paused:before, + &.idle:before + background: lighten($gray-light, 30%) .controls float: right @@ -192,11 +173,10 @@ padding: 0px overflow-y: auto overflow-x: hidden - position: absolute + position: fixed top: 0px bottom: 55px - padding-top: 35px - width: 100% + padding-top: 75px borderbox() -webkit-overflow-scrolling: touch @@ -317,7 +297,6 @@ .chatBox borderbox() - border-top: 1px solid $gray-lighter bottom: 0px position: fixed right: 0px @@ -338,7 +317,8 @@ height: 30px padding: 6px 10px - &:focus + &.typing:focus, + &.editing:focus transition: none -webkit-transition: none diff --git a/public/css/pages/header.css b/public/css/pages/header.css new file mode 100644 index 0000000..681f394 --- /dev/null +++ b/public/css/pages/header.css @@ -0,0 +1,9 @@ +#me { + position: fixed; + left: 0px; + right: 0px; + top: 0px; + height: 40px; + background-color: #fff; + border-bottom: 1px solid #d6d6d6; +} diff --git a/public/css/pages/header.styl b/public/css/pages/header.styl new file mode 100644 index 0000000..4d1a9d5 --- /dev/null +++ b/public/css/pages/header.styl @@ -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 diff --git a/public/css/pages/roster.styl b/public/css/pages/roster.styl index 96230b8..a2200ba 100644 --- a/public/css/pages/roster.styl +++ b/public/css/pages/roster.styl @@ -121,7 +121,7 @@ &.paused &:after - background: $gray-light + background: lighten($gray-light, 30%) &.idle padding-right: 15px diff --git a/public/x-manifest.cache b/public/x-manifest.cache index cd87e53..076020e 100644 --- a/public/x-manifest.cache +++ b/public/x-manifest.cache @@ -1,5 +1,5 @@ CACHE MANIFEST -# 0.0.1 1387527074335 +# 0.0.1 1387539451203 CACHE: /app.js