Sockpuppet Expo


Chat

Messages stored 0
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>