Chat
python
core/views/chat.py (LOC 17)
from django.views.generic.base import TemplateView
from django.core.cache import cache
from .mixins import ChatMixin
class ChatView(ChatMixin, TemplateView):
demo_template = '_chat_demo.html'
subtitle = 'Chat'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['chats'] = cache.get("chats", [])
return context
chat = ChatView.as_view()
core/reflexes/chat_reflex.py (LOC 26)
from sockpuppet.reflex import Reflex
from sockpuppet.channel import Channel
from django.core.cache import cache
from django.utils import timezone
class ChatReflex(Reflex):
def post(self, color, message, message_id):
chats = cache.get("chats", [])
self.total = 100
if len(chats) > self.total:
chats = []
if message:
chats.append({
'message': message,
'messageId': message_id,
'created_at': timezone.now()
})
cache.set("chats", chats)
channel = Channel("ChatChannel")
channel.dispatch_event({
'name': 'chats:added',
'detail': {'messageId': message_id}
})
channel.broadcast()
javascript
core/javascript/controllers/chat_controller.js (LOC 54)
import Rails from '@rails/ujs'
import { debounce } from 'lodash-es'
import ApplicationController from './application_controller'
let lastMessageId
const reload = controller => {
controller.stimulate('ChatReflex#reload')
}
const debouncedReload = debounce(reload, 100)
export default class extends ApplicationController {
static get targets () {
return ['list', 'input']
}
connect () {
super.connect()
this.scroll(100)
}
post (event) {
console.log("post");
Rails.stopEverything(event)
lastMessageId = Math.random()
this.stimulate(
'ChatReflex#post',
this.element.dataset.color,
this.inputTarget.value,
lastMessageId
)
}
afterPost () {
this.inputTarget.value = ''
this.inputTarget.focus()
this.scroll(1)
}
scroll (delay = 10) {
const lists = document.querySelectorAll('[data-target="chat.list"]')
setTimeout(() => {
lists.forEach(e => (e.scrollTop = e.scrollHeight))
}, delay)
}
reload (event) {
if (!event.detail) return
const { messageId } = event.detail
if (messageId === lastMessageId) return
debouncedReload(this)
}
}
html
core/templates/_chat_demo.html (LOC 24)
<article id="red"
data-controller="chat"
data-action="chats:added@document->chat#reload cable-ready:after-morph@document->chat#scroll"
data-reflex-root="#chat-container"
>
<span id="chat-container" data-target="chat.list">
{% for chat in chats %}
<aside class="message" style="min-height:auto; margin-top: 15px;">
<p>
{{ chat.message }} <sup>{{ chat.created_at|timesince }} ago </sup>
</p>
</aside>
{% endfor %}
</span>
<form>
<textarea data-target="chat.input" placeholder="Type your message.." minlength="4"></textarea>
<button data-action="click->chat#post" type="submit"> Send </button>
<div>
<small>Messages stored {{chats|length}}</small>
</div>
</form>
</article>