mirror of
https://github.com/moparisthebest/kaiwa
synced 2024-11-12 04:25:05 -05:00
Add message grouping, and avatars
This commit is contained in:
parent
0aa116e6f6
commit
0f2b4b9ec1
107
clientapp/helpers/chatHelpers.js
Normal file
107
clientapp/helpers/chatHelpers.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/*global app, $*/
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var _ = require('underscore');
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
initializeScroll: function () {
|
||||||
|
$(this.$scrollContainer).scroll(_.bind(_.throttle(this.handleScroll, 300), this));
|
||||||
|
this.pinnedToBottom = true;
|
||||||
|
this.lastScrollTop = 0;
|
||||||
|
},
|
||||||
|
scrollPageLoad: function () {
|
||||||
|
if (typeof this.lastScrollPosition === 'number') {
|
||||||
|
this.scrollTo(this.lastScrollPosition);
|
||||||
|
} else {
|
||||||
|
this.scrollToBottom();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scrollPageUnload: function () {
|
||||||
|
this.savePosition();
|
||||||
|
this.trimOldChats();
|
||||||
|
},
|
||||||
|
savePosition: function () {
|
||||||
|
this.lastScrollPosition = this.pinnedToBottom ? '' : this.$scrollContainer.scrollTop();
|
||||||
|
},
|
||||||
|
trimOldChats: function () {
|
||||||
|
var self = this;
|
||||||
|
var removedIds;
|
||||||
|
if (this.pinnedToBottom) {
|
||||||
|
_.delay(function () {
|
||||||
|
removedIds = self.collection.trimOlderChats();
|
||||||
|
removedIds.forEach(function (id) {
|
||||||
|
self.$('#chat' + id).remove();
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleScroll: function (e) {
|
||||||
|
var scrollTop = this.$scrollContainer[0].scrollTop;
|
||||||
|
var direction = scrollTop > this.lastScrollTop ? 'down' : 'up';
|
||||||
|
if (direction === 'up' && !this.isBottom()) {
|
||||||
|
this.pinnedToBottom = false;
|
||||||
|
} else if (this.isBottom()) {
|
||||||
|
this.handleAtBottom();
|
||||||
|
}
|
||||||
|
this.lastScrollTop = scrollTop;
|
||||||
|
},
|
||||||
|
scrollIfPinned: function (animate) {
|
||||||
|
if (this.pinnedToBottom) this.scrollToBottom(animate);
|
||||||
|
},
|
||||||
|
handleAtBottom: function () {
|
||||||
|
if (this.isVisible()) {
|
||||||
|
this.pinnedToBottom = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isBottom: function () {
|
||||||
|
var scrollTop = this.$scrollContainer[0].scrollTop;
|
||||||
|
var scrollHeight = this.$scrollContainer[0].scrollHeight;
|
||||||
|
var height = this.$scrollContainer.height();
|
||||||
|
var fromBottom = scrollHeight - (scrollTop + height);
|
||||||
|
return fromBottom < 40 || $('body').is(':animated');
|
||||||
|
},
|
||||||
|
resizeInput: function () {
|
||||||
|
var height;
|
||||||
|
var scrollHeight;
|
||||||
|
var newHeight;
|
||||||
|
var newPadding;
|
||||||
|
var paddingDelta;
|
||||||
|
var maxHeight = 102;
|
||||||
|
|
||||||
|
this.$chatInput.removeAttr('style');
|
||||||
|
height = this.$chatInput.height() + 10,
|
||||||
|
scrollHeight = this.$chatInput.get(0).scrollHeight,
|
||||||
|
newHeight = scrollHeight + 2;
|
||||||
|
|
||||||
|
if (newHeight > maxHeight) newHeight = maxHeight;
|
||||||
|
if (newHeight > height) {
|
||||||
|
this.$chatInput.css('height', newHeight);
|
||||||
|
newPadding = newHeight + 21;
|
||||||
|
paddingDelta = newPadding - parseInt(this.$messageList.css('paddingBottom'), 10);
|
||||||
|
if (!!paddingDelta) {
|
||||||
|
this.$messageList.css('paddingBottom', newPadding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scrollTo: function (height, animate) {
|
||||||
|
if (animate) {
|
||||||
|
this.$scrollContainer.animate({
|
||||||
|
scrollTop: height
|
||||||
|
}, {
|
||||||
|
duration: 500,
|
||||||
|
queue: false
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.$scrollContainer.scrollTop(height);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scrollToBottom: function (animate) {
|
||||||
|
if (!this.isVisible()) return;
|
||||||
|
var height = this.$scrollContainer[0].scrollHeight;
|
||||||
|
this.scrollTo(height, animate);
|
||||||
|
},
|
||||||
|
isVisible: function () {
|
||||||
|
return app.currentPage === this;
|
||||||
|
}
|
||||||
|
};
|
@ -25,7 +25,8 @@ module.exports = HumanModel.define({
|
|||||||
connected: ['bool', true, false],
|
connected: ['bool', true, false],
|
||||||
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']
|
||||||
},
|
},
|
||||||
collections: {
|
collections: {
|
||||||
contacts: Contacts,
|
contacts: Contacts,
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var HumanModel = require('human-model');
|
var HumanModel = require('human-model');
|
||||||
|
var templates = require('../templates');
|
||||||
|
|
||||||
|
|
||||||
module.exports = HumanModel.define({
|
module.exports = HumanModel.define({
|
||||||
@ -26,6 +27,16 @@ module.exports = HumanModel.define({
|
|||||||
return me.isMe(this.from);
|
return me.isMe(this.from);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
sender: {
|
||||||
|
deps: ['from', 'mine'],
|
||||||
|
fn: function () {
|
||||||
|
if (this.mine) {
|
||||||
|
return me;
|
||||||
|
} else {
|
||||||
|
return me.getContact(this.from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
delayed: {
|
delayed: {
|
||||||
deps: ['delay'],
|
deps: ['delay'],
|
||||||
fn: function () {
|
fn: function () {
|
||||||
@ -81,6 +92,31 @@ module.exports = HumanModel.define({
|
|||||||
}
|
}
|
||||||
return me.getContact(this.from.bare).displayName;
|
return me.getContact(this.from.bare).displayName;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
partialTemplateHtml: {
|
||||||
|
deps: ['edited', 'pending', 'body'],
|
||||||
|
cache: false,
|
||||||
|
fn: function () {
|
||||||
|
return templates.includes.bareMessage({message: this});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
templateHtml: {
|
||||||
|
fn: function () {
|
||||||
|
return templates.includes.wrappedMessage({message: this});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
classList: {
|
||||||
|
cache: false,
|
||||||
|
fn: function () {
|
||||||
|
var res = [];
|
||||||
|
|
||||||
|
if (this.mine) res.push('mine');
|
||||||
|
if (this.pending) res.push('pending');
|
||||||
|
if (this.delayed) res.push('delayed');
|
||||||
|
if (this.edited) res.push('edited');
|
||||||
|
|
||||||
|
return res.join(' ');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
session: {
|
session: {
|
||||||
@ -115,5 +151,8 @@ module.exports = HumanModel.define({
|
|||||||
edited: this.edited
|
edited: this.edited
|
||||||
};
|
};
|
||||||
app.storage.archive.add(data);
|
app.storage.archive.add(data);
|
||||||
|
},
|
||||||
|
shouldGroupWith: function (previous) {
|
||||||
|
return previous && previous.from.bare === this.from.bare;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,17 +1,27 @@
|
|||||||
/*global $, app, me, client*/
|
/*global $, app, me, client*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var _ = require('underscore');
|
||||||
var BasePage = require('./base');
|
var BasePage = require('./base');
|
||||||
var templates = require('../templates');
|
var templates = require('../templates');
|
||||||
var Message = require('../views/message');
|
var Message = require('../views/message');
|
||||||
var MessageModel = require('../models/message');
|
var MessageModel = require('../models/message');
|
||||||
|
var chatHelpers = require('../helpers/chatHelpers');
|
||||||
|
|
||||||
|
|
||||||
module.exports = BasePage.extend({
|
module.exports = BasePage.extend(chatHelpers).extend({
|
||||||
template: templates.pages.chat,
|
template: templates.pages.chat,
|
||||||
initialize: function (spec) {
|
initialize: function (spec) {
|
||||||
this.editMode = false;
|
this.editMode = false;
|
||||||
this.model.fetchHistory();
|
this.model.fetchHistory();
|
||||||
|
|
||||||
|
this.listenTo(this, 'pageloaded', this.handlePageLoaded);
|
||||||
|
this.listenTo(this, 'pageunloaded', this.handlePageUnloaded);
|
||||||
|
|
||||||
|
this.listenTo(this.model.messages, 'change:body', this.refreshModel);
|
||||||
|
this.listenTo(this.model.messages, 'change:edited', this.refreshModel);
|
||||||
|
this.listenTo(this.model.messages, 'change:pending', this.refreshModel);
|
||||||
|
|
||||||
this.render();
|
this.render();
|
||||||
},
|
},
|
||||||
events: {
|
events: {
|
||||||
@ -40,14 +50,47 @@ module.exports = BasePage.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
|
if (this.rendered) return this;
|
||||||
|
this.rendered = true;
|
||||||
|
|
||||||
this.renderAndBind();
|
this.renderAndBind();
|
||||||
|
|
||||||
this.typingTimer = null;
|
this.typingTimer = null;
|
||||||
this.$chatInput = this.$('.chatBox textarea');
|
this.$chatInput = this.$('.chatBox textarea');
|
||||||
|
this.$chatBox = this.$('.chatBox');
|
||||||
this.$messageList = this.$('.messages');
|
this.$messageList = this.$('.messages');
|
||||||
this.renderCollection(this.model.messages, Message, this.$('.messages'));
|
this.$scrollContainer = this.$messageList;
|
||||||
this.registerBindings();
|
|
||||||
|
this.listenTo(this.model.messages, 'add', this.handleChatAdded);
|
||||||
|
|
||||||
|
this.renderCollection();
|
||||||
|
|
||||||
|
$(window).on('resize', _.bind(this.handleWindowResize, this));
|
||||||
|
|
||||||
|
this.initializeScroll();
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
handlePageLoaded: function () {
|
||||||
|
this.scrollPageLoad();
|
||||||
|
this.handleWindowResize();
|
||||||
|
},
|
||||||
|
handlePageUnloaded: function () {
|
||||||
|
this.scrollPageUnload();
|
||||||
|
},
|
||||||
|
renderCollection: function () {
|
||||||
|
var self = this;
|
||||||
|
var previous;
|
||||||
|
var bottom = this.isBottom() || this.$messageList.is(':empty');
|
||||||
|
this.model.messages.each(function (model, i) {
|
||||||
|
self.appendModel(model);
|
||||||
|
});
|
||||||
|
this.scrollIfPinned();
|
||||||
|
},
|
||||||
|
handleWindowResize: function () {
|
||||||
|
this.scrollIfPinned();
|
||||||
|
this.$chatInput.trigger('keyup');
|
||||||
|
},
|
||||||
handleKeyDown: function (e) {
|
handleKeyDown: function (e) {
|
||||||
clearTimeout(this.typingTimer);
|
clearTimeout(this.typingTimer);
|
||||||
if (e.which === 13 && !e.shiftKey) {
|
if (e.which === 13 && !e.shiftKey) {
|
||||||
@ -86,29 +129,6 @@ module.exports = BasePage.extend({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
resizeInput: function () {
|
|
||||||
var height;
|
|
||||||
var scrollHeight;
|
|
||||||
var newHeight;
|
|
||||||
var newPadding;
|
|
||||||
var paddingDelta;
|
|
||||||
var maxHeight = 102;
|
|
||||||
|
|
||||||
this.$chatInput.removeAttr('style');
|
|
||||||
height = this.$chatInput.height() + 10,
|
|
||||||
scrollHeight = this.$chatInput.get(0).scrollHeight,
|
|
||||||
newHeight = scrollHeight + 2;
|
|
||||||
|
|
||||||
if (newHeight > maxHeight) newHeight = maxHeight;
|
|
||||||
if (newHeight > height) {
|
|
||||||
this.$chatInput.css('height', newHeight);
|
|
||||||
newPadding = newHeight + 21;
|
|
||||||
paddingDelta = newPadding - parseInt(this.$messageList.css('paddingBottom'), 10);
|
|
||||||
if (!!paddingDelta) {
|
|
||||||
this.$messageList.css('paddingBottom', newPadding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
pausedTyping: function () {
|
pausedTyping: function () {
|
||||||
if (this.typing) {
|
if (this.typing) {
|
||||||
this.typing = false;
|
this.typing = false;
|
||||||
@ -130,7 +150,7 @@ module.exports = BasePage.extend({
|
|||||||
chatState: 'active'
|
chatState: 'active'
|
||||||
};
|
};
|
||||||
if (this.editMode) {
|
if (this.editMode) {
|
||||||
message.replace = this.model.lastSentMessage.id || this.model.lastSentMessage.cid;
|
message.replace = this.model.lastSentMessage.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
var id = client.sendMessage(message);
|
var id = client.sendMessage(message);
|
||||||
@ -141,7 +161,6 @@ module.exports = BasePage.extend({
|
|||||||
this.model.lastSentMessage.correct(message);
|
this.model.lastSentMessage.correct(message);
|
||||||
} else {
|
} else {
|
||||||
var msgModel = new MessageModel(message);
|
var msgModel = new MessageModel(message);
|
||||||
msgModel.cid = id;
|
|
||||||
this.model.messages.add(msgModel);
|
this.model.messages.add(msgModel);
|
||||||
this.model.lastSentMessage = msgModel;
|
this.model.lastSentMessage = msgModel;
|
||||||
}
|
}
|
||||||
@ -150,5 +169,32 @@ module.exports = BasePage.extend({
|
|||||||
this.typing = false;
|
this.typing = false;
|
||||||
this.$chatInput.removeClass('editing');
|
this.$chatInput.removeClass('editing');
|
||||||
this.$chatInput.val('');
|
this.$chatInput.val('');
|
||||||
|
},
|
||||||
|
handleChatAdded: function (model) {
|
||||||
|
this.appendModel(model, true);
|
||||||
|
},
|
||||||
|
refreshModel: function (model) {
|
||||||
|
var existing = this.$('#chat' + model.cid);
|
||||||
|
console.log(model);
|
||||||
|
console.log(model.classList);
|
||||||
|
existing.replaceWith(model.partialTemplateHtml);
|
||||||
|
},
|
||||||
|
appendModel: function (model, preload) {
|
||||||
|
var self = this;
|
||||||
|
var isGrouped = model.shouldGroupWith(this.lastModel);
|
||||||
|
var newEl, first, last;
|
||||||
|
|
||||||
|
if (isGrouped) {
|
||||||
|
newEl = $(model.partialTemplateHtml);
|
||||||
|
last = this.$messageList.find('li').last();
|
||||||
|
last.find('.messageWrapper').append(newEl);
|
||||||
|
last.addClass('chatGroup');
|
||||||
|
} else {
|
||||||
|
newEl = $(model.templateHtml);
|
||||||
|
this.$messageList.append(newEl);
|
||||||
|
}
|
||||||
|
this.lastModel = model;
|
||||||
|
|
||||||
|
this.scrollIfPinned();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -27,6 +27,21 @@ exports.head = function anonymous(locals) {
|
|||||||
return buf.join("");
|
return buf.join("");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// bareMessage.jade compiled template
|
||||||
|
exports.includes.bareMessage = function anonymous(locals) {
|
||||||
|
var buf = [];
|
||||||
|
with (locals || {}) {
|
||||||
|
buf.push("<div" + jade.attrs({
|
||||||
|
id: "chat" + message.cid,
|
||||||
|
"class": "message" + " " + message.classList
|
||||||
|
}, {
|
||||||
|
"class": true,
|
||||||
|
id: true
|
||||||
|
}) + '><span class="timestamp">' + jade.escape(null == (jade.interp = message.formattedTime) ? "" : jade.interp) + '</span><p class="body">' + jade.escape(null == (jade.interp = message.body) ? "" : jade.interp) + "</p></div>");
|
||||||
|
}
|
||||||
|
return buf.join("");
|
||||||
|
};
|
||||||
|
|
||||||
// contactListItem.jade compiled template
|
// contactListItem.jade compiled template
|
||||||
exports.includes.contactListItem = function anonymous(locals) {
|
exports.includes.contactListItem = function anonymous(locals) {
|
||||||
var buf = [];
|
var buf = [];
|
||||||
@ -59,6 +74,15 @@ exports.includes.message = function anonymous(locals) {
|
|||||||
return buf.join("");
|
return buf.join("");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// messageGroup.jade compiled template
|
||||||
|
exports.includes.messageGroup = function anonymous(locals) {
|
||||||
|
var buf = [];
|
||||||
|
with (locals || {}) {
|
||||||
|
buf.push("<li></li>");
|
||||||
|
}
|
||||||
|
return buf.join("");
|
||||||
|
};
|
||||||
|
|
||||||
// mucListItem.jade compiled template
|
// mucListItem.jade compiled template
|
||||||
exports.includes.mucListItem = function anonymous(locals) {
|
exports.includes.mucListItem = function anonymous(locals) {
|
||||||
var buf = [];
|
var buf = [];
|
||||||
@ -82,6 +106,29 @@ exports.includes.mucMessage = function anonymous(locals) {
|
|||||||
return buf.join("");
|
return buf.join("");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// wrappedMessage.jade compiled template
|
||||||
|
exports.includes.wrappedMessage = function anonymous(locals) {
|
||||||
|
var buf = [];
|
||||||
|
with (locals || {}) {
|
||||||
|
buf.push('<li><a href="#" class="messageAvatar"><img' + jade.attrs({
|
||||||
|
src: message.sender.avatar,
|
||||||
|
alt: message.sender.displayName,
|
||||||
|
"data-placement": "below"
|
||||||
|
}, {
|
||||||
|
src: true,
|
||||||
|
alt: true,
|
||||||
|
"data-placement": true
|
||||||
|
}) + '/><span class="name">' + jade.escape(null == (jade.interp = message.sender.displayName + ": ") ? "" : jade.interp) + '</span></a><div class="messageWrapper"><div' + jade.attrs({
|
||||||
|
id: "chat" + message.cid,
|
||||||
|
"class": "message" + " " + message.classList
|
||||||
|
}, {
|
||||||
|
"class": true,
|
||||||
|
id: true
|
||||||
|
}) + '><span class="timestamp">' + jade.escape(null == (jade.interp = message.formattedTime) ? "" : jade.interp) + '</span><p class="body">' + jade.escape(null == (jade.interp = message.body) ? "" : jade.interp) + "</p></div></div></li>");
|
||||||
|
}
|
||||||
|
return buf.join("");
|
||||||
|
};
|
||||||
|
|
||||||
// growlMessage.jade compiled template
|
// growlMessage.jade compiled template
|
||||||
exports.misc.growlMessage = function anonymous(locals) {
|
exports.misc.growlMessage = function anonymous(locals) {
|
||||||
var buf = [];
|
var buf = [];
|
||||||
|
3
clientapp/templates/includes/bareMessage.jade
Normal file
3
clientapp/templates/includes/bareMessage.jade
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.message(id='chat'+message.cid, class=message.classList)
|
||||||
|
span.timestamp=message.formattedTime
|
||||||
|
p.body=message.body
|
1
clientapp/templates/includes/messageGroup.jade
Normal file
1
clientapp/templates/includes/messageGroup.jade
Normal file
@ -0,0 +1 @@
|
|||||||
|
li
|
6
clientapp/templates/includes/wrappedMessage.jade
Normal file
6
clientapp/templates/includes/wrappedMessage.jade
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
li
|
||||||
|
a.messageAvatar(href='#')
|
||||||
|
img(src=message.sender.avatar, alt=message.sender.displayName, data-placement="below")
|
||||||
|
span.name=message.sender.displayName + ": "
|
||||||
|
.messageWrapper
|
||||||
|
include bareMessage
|
@ -72,15 +72,39 @@
|
|||||||
position: relative
|
position: relative
|
||||||
z-index: 1
|
z-index: 1
|
||||||
list-style: none
|
list-style: none
|
||||||
margin: 0px
|
|
||||||
padding: 0px
|
padding: 0px
|
||||||
width: 100%
|
width: 100%
|
||||||
|
min-height: 40px
|
||||||
display: block
|
display: block
|
||||||
borderbox()
|
borderbox()
|
||||||
|
border: 1px solid blue
|
||||||
|
|
||||||
&:last-child .message
|
&:last-child .message
|
||||||
border: none
|
border: none
|
||||||
|
|
||||||
|
&.chatGroup
|
||||||
|
border: 1px solid red
|
||||||
|
|
||||||
|
.messageAvatar
|
||||||
|
position: relative
|
||||||
|
display: inline-block
|
||||||
|
float: left
|
||||||
|
width: 30px
|
||||||
|
height: 30px
|
||||||
|
margin: 0px 8px 8px 8px
|
||||||
|
|
||||||
|
img
|
||||||
|
avatar()
|
||||||
|
border: 1px solid red
|
||||||
|
.name
|
||||||
|
text-indent: -9999em
|
||||||
|
position: absolute
|
||||||
|
width: 1px
|
||||||
|
|
||||||
|
.messageWrapper
|
||||||
|
margin-left: 50px
|
||||||
|
border-left: 1px solid red
|
||||||
|
|
||||||
.message
|
.message
|
||||||
font-size: 12px
|
font-size: 12px
|
||||||
margin: 0px
|
margin: 0px
|
||||||
|
@ -689,17 +689,49 @@ h3 {
|
|||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
min-height: 40px;
|
||||||
display: block;
|
display: block;
|
||||||
-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: 1px solid #00f;
|
||||||
}
|
}
|
||||||
.messages li:last-child .message {
|
.messages li:last-child .message {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
.messages li.chatGroup {
|
||||||
|
border: 1px solid #f00;
|
||||||
|
}
|
||||||
|
.messages li .messageAvatar {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
float: left;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
margin: 0px 8px 8px 8px;
|
||||||
|
}
|
||||||
|
.messages li .messageAvatar img {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
-moz-border-radius: 50px;
|
||||||
|
-webkit-border-radius: 50px;
|
||||||
|
-khtml-border-radius: 50px;
|
||||||
|
-o-border-radius: 50px;
|
||||||
|
-border-radius: 50px;
|
||||||
|
border-radius: 50px;
|
||||||
|
border: 1px solid #f00;
|
||||||
|
}
|
||||||
|
.messages li .messageAvatar .name {
|
||||||
|
text-indent: -9999em;
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
.messages .messageWrapper {
|
||||||
|
margin-left: 50px;
|
||||||
|
border-left: 1px solid #f00;
|
||||||
|
}
|
||||||
.messages .message {
|
.messages .message {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
|
Loading…
Reference in New Issue
Block a user