Skip to content

Commit

Permalink
Merge pull request #64 from gdpelican/chat-switching
Browse files Browse the repository at this point in the history
Allow for switching between multiple chat topics
  • Loading branch information
gdpelican committed Sep 23, 2015
2 parents a022232 + 3796dd5 commit 3d07748
Show file tree
Hide file tree
Showing 10 changed files with 366 additions and 148 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ export default Ember.Component.extend({
}

self.set('processing', true)
Discourse.ajax("/babble/topic/post", {
Discourse.ajax("/babble/topics/" + self.get('topic.id') + "/post", {
type: 'POST',
data: { raw: self.get('text').trim() }
})
.then(Discourse.Babble.refresh)
.then(Discourse.Babble.handleNewPost)
.finally(function() {
self.set('text', '')
self.set('processing', false)
Expand Down
59 changes: 24 additions & 35 deletions assets/javascripts/discourse/components/babble-icon.js.es6
Original file line number Diff line number Diff line change
@@ -1,48 +1,37 @@
import { observes } from 'ember-addons/ember-computed-decorators';
import initializeBabble from "../lib/babble"

export default Ember.Component.extend({

classNames: ['babble-icon'],
tagName: 'li',

_init: function() {
const self = this
const messageBus = Discourse.__container__.lookup('message-bus:main')
self.set('babbleIcon', Discourse.SiteSettings.babble_icon)

if (!Discourse.Babble) {
Discourse.Babble = {}
Discourse.Babble.refresh = function(data) {
self.set('babbleEnabled', Discourse.SiteSettings.babble_enabled && data.id)
if (!self.get('babbleEnabled')) { return }

var resetTopicField = function(topic, field) {
topic[field] = data[field]
if (!topic[field] && Discourse.Babble.topic) { topic[field] = Discourse.Babble.topic[field] }
}

var humanizeGroupName = function(group) {
if (!group.name) { return '' }
return group.name.charAt(0).toUpperCase() + group.name.slice(1).replace(/_/g, ' ')
}
currentTopicId: function() {
return Discourse.Babble.currentTopicId
}.property('Discourse.Babble.currentTopicId'),

var topic = Discourse.Topic.create(data)
resetTopicField(topic, 'last_read_post_number')
resetTopicField(topic, 'highest_post_number')
currentTopic: function() {
return Discourse.Babble.currentTopic
}.property('Discourse.Babble.currentTopic'),

topic.details.group_names = _.map(topic.details.allowed_groups, humanizeGroupName).join(', ')
@observes('currentTopicId')
babbleEnabled: function() {
return Discourse.SiteSettings.babble_enabled && this.get('currentTopicId')
},

var postStream = Discourse.PostStream.create(topic.post_stream)
postStream.posts = topic.post_stream.posts
postStream.topic = topic

Discourse.Babble.topic = topic
Discourse.Babble.postStream = postStream

self.set('unreadCount', topic.highest_post_number - topic.last_read_post_number)
}
unreadCount: function() {
if (Discourse.Babble.unreadCount > 0) {
return Discourse.Babble.unreadCount
} else {
return null
}
}.property('Discourse.Babble.unreadCount'),

_init: function() {
if (!Discourse.Babble) { Discourse.Babble = initializeBabble }

Discourse.ajax('/babble/topic.json').then(Discourse.Babble.refresh)
messageBus.subscribe('/babble/topic', Discourse.Babble.refresh)
this.set('babbleIcon', Discourse.SiteSettings.babble_icon)
Discourse.ajax('/babble/topics/default.json').then(Discourse.Babble.setCurrentTopic)
Discourse.ajax('/babble/topics.json').then(Discourse.Babble.setAvailableTopics)
}.on('init')
});
83 changes: 44 additions & 39 deletions assets/javascripts/discourse/components/babble-menu.js.es6
Original file line number Diff line number Diff line change
Expand Up @@ -9,66 +9,65 @@ export default Ember.Component.extend({
lastVisiblePostInScrollableDiv: lastVisiblePostInScrollableDiv,

ready: function() {
return this.get('visible') && Discourse.Babble && Discourse.Babble.topic
return this.get('visible') && Discourse.Babble && Discourse.Babble.currentTopic
},

currentTopicId: function() {
return Discourse.Babble.currentTopicId
}.property('Discourse.Babble.currentTopicId'),

currentTopic: function() {
return Discourse.Babble.currentTopic
}.property('Discourse.Babble.currentTopic'),

availableTopics: function() {
var currentTopicId = this.get('currentTopicId')
return _.filter(Discourse.Babble.availableTopics, function(topic) { return topic.id != currentTopicId })
}.property('Discourse.Babble.currentTopicId', 'Discourse.Babble.availableTopics'),

@observes('Discourse.Babble.currentTopic', 'availableTopics')
multipleTopicsAvailable: function() {
return this.get('availableTopics').length > 0
},

@observes('visible')
_visible: function() {
if (!this.ready()) { return }
Ember.run.scheduleOnce('afterRender', this, this._rendered)
Ember.run.scheduleOnce('afterRender', this, this.topicChanged)
},

@observes('visible')
_initialVisible: function() {
if (!this.ready() || this.get('isSetup')) { return }
this.set('isSetup', true)
this.set('topic', Discourse.Babble.topic)
this.set('topic.postStream', Discourse.Babble.postStream)
this.setupMessageBus()
this._visible()
@observes('Discourse.Babble.currentTopicId')
topicChanged: function() {
this._actions.viewChat(this)
this.set('initialScroll', true)
this.setupScrolling()
},

setupMessageBus: function() {
const self = this
var messageBus = Discourse.__container__.lookup('message-bus:main')
messageBus.subscribe('/babble/post', function(data) {
var postStream = self.get('topic.postStream')
var post = postStream.storePost(Discourse.Post.create(data))
post.created_at = moment(data.created_at, 'YYYY-MM-DD HH:mm:ss Z')
postStream.appendPost(post)

var scrolledToBottom = self.isElementScrolledToBottom(self.get('scrollContainer'))
var userIsAuthor = Discourse.User.current().id == post.user_id
if (scrolledToBottom || userIsAuthor) { self.scroll() }
})
@observes('Discourse.Babble.latestPost')
messageBusPostCallback: function() {
var scrolledToBottom = this.isElementScrolledToBottom(this.get('scrollContainer'))
if (scrolledToBottom || Discourse.Babble.lastPostIsMine()) { this.scroll() }
},

_rendered: function() {
this.set('initialScroll', true)
this.setupScrollContainer()
this.setupTracking()
},

setupTracking: function() {
setupScrolling: function() {
const self = this
self.set('scrollContainer', $('.babble-menu').find('.panel-body'))

var readOnScroll = function() {
var lastReadPostNumber = self.lastVisiblePostInScrollableDiv(self.get('scrollContainer'))
if (lastReadPostNumber > self.get('topic.last_read_post_number')) {
Discourse.ajax('/babble/topic/read/' + lastReadPostNumber + '.json').then(Discourse.Babble.refresh)
if (lastReadPostNumber > self.get('currentTopic.last_read_post_number')) {
Discourse.ajax('/babble/topics/' + self.get('currentTopicId') + '/read/' + lastReadPostNumber + '.json').then(Discourse.Babble.setCurrentTopic)
}
}

if (self.get('scrollContainer').get(0)) {
Ember.run.next(self, self.scroll)
}

self.get('scrollContainer').off('scroll')
self.get('scrollContainer').on('scroll', debounce(readOnScroll, 500))
},

setupScrollContainer: function() {
this.set('scrollContainer', $('.babble-menu').find('.panel-body'))
if (this.get('scrollContainer').get(0)) {
Ember.run.next(this, this.scroll)
}
},

scroll: function() {
var scrollSpeed = this.get('initialScroll') ? 0 : 750 // Scroll immediately on initial scroll
this.get('scrollContainer').animate({ scrollTop: this.getLastReadLinePosition() }, scrollSpeed)
Expand All @@ -84,5 +83,11 @@ export default Ember.Component.extend({
} else {
return container.get(0).scrollHeight
}
},

actions: {
viewChat: function(context) { (context || this).set('viewingChat', true) },
viewTopics: function(context) { (context || this).set('viewingChat', false) },
changeTopic: function(topic) { Discourse.ajax('/babble/topics/' + topic.id + '.json').then(Discourse.Babble.setCurrentTopic) }
}
});
77 changes: 77 additions & 0 deletions assets/javascripts/discourse/lib/babble.js.es6
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
export default Ember.Object.create({

setCurrentTopic: function(data) {
const self = Discourse.Babble

if (!data.id) {
self.set('currentTopic', null)
self.set('currentTopicId', null)
self.set('latestPost', null)
return
}

const messageBus = Discourse.__container__.lookup('message-bus:main')

var resetTopicField = function(topic, field) {
topic[field] = data[field]
if (!topic[field] && self.get('currentTopic')) { topic[field] = self.get('currentTopic')[field] }
}

var humanizeGroupName = function(group) {
if (!group.name) { return '' }
return group.name.charAt(0).toUpperCase() + group.name.slice(1).replace(/_/g, ' ')
}

var topic = Discourse.Topic.create(data)
resetTopicField(topic, 'last_read_post_number')
resetTopicField(topic, 'highest_post_number')

if (self.get('currentTopicId') != topic.id) {
if (self.get('currentTopicId')) {
messageBus.unsubscribe('/babble/topics/' + self.get('currentTopicId'))
messageBus.unsubscribe('/babble/topics/' + self.get('currentTopicId') + '/posts')
}
self.set('currentTopicId', topic.id)
messageBus.subscribe('/babble/topics/' + self.get('currentTopicId'), self.setCurrentTopic)
messageBus.subscribe('/babble/topics/' + self.get('currentTopicId') + '/posts', self.handleNewPost)

var postStream = Discourse.PostStream.create(topic.post_stream)
postStream.posts = topic.post_stream.posts
postStream.topic = topic

topic.postStream = postStream
topic.details.group_names = _.map(topic.details.allowed_groups, humanizeGroupName).join(', ')
} else {
topic.postStream = self.get('currentTopic.postStream')
}

self.set('unreadCount', topic.highest_post_number - topic.last_read_post_number)
self.set('currentTopic', topic)
},

setAvailableTopics: function(data) {
Discourse.Babble.set('availableTopics', (data || {}).topics || [])
},

lastPostIsMine: function() {
return Discourse.Babble.get('latestPost.user_id') == Discourse.User.current().id
},

handleNewPost: function(data) {
const self = Discourse.Babble

var postStream = self.get('currentTopic.postStream')
var post = postStream.storePost(Discourse.Post.create(data))
post.created_at = moment(data.created_at, 'YYYY-MM-DD HH:mm:ss Z')
postStream.appendPost(post)

self.set('latestPost', post)

if (self.lastPostIsMine()) {
self.set('unreadCount', 0)
} else {
var topic = self.get('currentTopic')
self.set('unreadCount', topic.highest_post_number - topic.last_read_post_number)
}
}
})
57 changes: 42 additions & 15 deletions assets/javascripts/discourse/templates/components/babble-menu.hbs
Original file line number Diff line number Diff line change
@@ -1,20 +1,47 @@
{{#menu-panel visible=visible}}
<section class="babble-chat">
<div class="babble-title-wrapper">
<div class="babble-title">
<h4 class="babble-group-title">{{topic.title}}</h4>
<i class="fa fa-eye" title="{{i18n 'babble.visibility_message' groupNames=topic.details.group_names}}"></i>
<div class="babble-title-wrapper">
<div class="babble-title">
{{#if viewingChat}}
<h4 class="babble-group-title">{{currentTopic.title}}</h4>
<button class="babble-context-toggle normalized">
<i class="fa fa-eye" title="{{i18n 'babble.topic_visibility_tooltip' groupNames=currentTopic.details.group_names}}"></i>
</button>
{{#if multipleTopicsAvailable}}
<button {{action 'viewTopics' bubbles=false}} class="babble-context-toggle for-topics normalized">
<i class="fa fa-exchange" title="{{i18n 'babble.view_topics_tooltip'}}"></i>
</button>
{{/if}}
{{else}}
<button {{action 'viewChat' bubbles=false}} class="babble-context-toggle for-chat normalized">
<i class="fa fa-chevron-left" title="{{i18n 'babble.view_chat_tooltip'}}"></i>
</button>
<h4 class="babble-topic-switcher-title">{{i18n 'babble.select_topic'}}</h4>
{{/if}}
</div>
</div>
</div>
<ul class="babble-posts">
{{#unless topic.postStream.posts}}
<li class="babble-empty-topic-message">{{i18n 'babble.empty_topic_message'}}</li>
{{/unless}}
{{#each post in topic.postStream.posts}}
{{babble-post post=post topic=topic}}
{{/each}}
{{conditional-loading-spinner condition=topic.postStream.loadingBelow}}
</ul>
{{babble-composer}}

{{#if viewingChat}}
<ul class="babble-posts">
{{#unless currentTopic.postStream.posts}}
<li class="babble-empty-topic-message">{{i18n 'babble.empty_topic_message'}}</li>
{{/unless}}
{{#each post in currentTopic.postStream.posts}}
{{babble-post post=post topic=currentTopic}}
{{/each}}
{{conditional-loading-spinner condition=currentTopic.postStream.loadingBelow}}
</ul>
{{babble-composer topic=currentTopic}}
{{else}}
<ul class="babble-available-topics">
{{#each topic in availableTopics}}
<li class="babble-available-topic row">
<button {{action 'changeTopic' topic bubbles=false}} class="normalized">
<div class="babble-available-topic-title">{{topic.title}}</div>
</button>
</li>
{{/each}}
</ul>
{{/if}}
</section>
{{/menu-panel}}

0 comments on commit 3d07748

Please sign in to comment.