diff --git a/.gitignore b/.gitignore
index 9785c98..0b3ff61 100644
--- a/.gitignore
+++ b/.gitignore
@@ -154,3 +154,4 @@ dmypy.json
node_modules
/static
/core/static/dist
+.env/
diff --git a/CODEOWNERS b/CODEOWNERS
new file mode 100644
index 0000000..dbb3228
--- /dev/null
+++ b/CODEOWNERS
@@ -0,0 +1,2 @@
+* zodman
+* jonathan-s
diff --git a/app/urls.py b/app/urls.py
index fa8bc0f..c89a875 100644
--- a/app/urls.py
+++ b/app/urls.py
@@ -5,6 +5,7 @@
import core.views.example
import core.views.book_search
+import core.views.chat
urlpatterns = [
@@ -13,4 +14,5 @@
path('book-search/', core.views.book_search.book_search,
name='book_search'),
path('example/', core.views.example.example, name='example'),
+ path('chat/', core.views.chat.chat, name='chat'),
] + staticfiles_urlpatterns()
diff --git a/core/javascript/controllers/chat_controller.js b/core/javascript/controllers/chat_controller.js
new file mode 100644
index 0000000..7f080f3
--- /dev/null
+++ b/core/javascript/controllers/chat_controller.js
@@ -0,0 +1,52 @@
+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) {
+ const { messageId } = event.detail
+ if (messageId === lastMessageId) return
+ debouncedReload(this)
+ }
+}
+
diff --git a/core/javascript/example.js b/core/javascript/example.js
index 1c72462..6d732b2 100644
--- a/core/javascript/example.js
+++ b/core/javascript/example.js
@@ -1,20 +1,28 @@
import { Application } from 'stimulus'
import StimulusReflex from 'stimulus_reflex'
import WebsocketConsumer from 'sockpuppet-js'
-
+import CableReady from 'cable_ready'
import debounced from 'debounced'
import BookSearchController from './controllers/book_search_controller'
import ExampleController from './controllers/example_controller'
+import ChatController from './controllers/chat_controller'
debounced.initialize()
-//import TurboLinks from 'turbolinks'
+import TurboLinks from 'turbolinks'
-//TurboLinks.start()
+TurboLinks.start()
const application = Application.start()
const ssl = location.protocol !== 'https:' ? '' : 's';
const consumer = new WebsocketConsumer(`ws${ssl}://${location.hostname}:${location.port}/ws/sockpuppet-sync`)
+consumer.subscriptions.create('ChatChannel', {
+ received (data) {
+ if (data.cableReady) CableReady.perform(data.operations)
+ }
+})
+
application.register("example", ExampleController)
application.register("book-search", BookSearchController)
+application.register("chat", ChatController)
StimulusReflex.initialize(application, { consumer, debug: true })
diff --git a/core/reflexes/book_search_reflex.py b/core/reflexes/book_search_reflex.py
index 0b448dd..22007a0 100644
--- a/core/reflexes/book_search_reflex.py
+++ b/core/reflexes/book_search_reflex.py
@@ -3,9 +3,9 @@
class BookSearchReflex(Reflex):
- def perform(self, query=""):
- resp = requests.get('http://openlibrary.org/search.json', params={'q':query})
+ def perform(self, query=''):
+ resp = requests.get('http://openlibrary.org/search.json', params={'q': query})
resp.raise_for_status()
books = resp.json()
- self.books = books.get("docs", [])
- self.count = books["num_found"]
+ self.books = books.get('docs', [])
+ self.count = books['num_found']
diff --git a/core/reflexes/chat_reflex.py b/core/reflexes/chat_reflex.py
new file mode 100644
index 0000000..2b143e6
--- /dev/null
+++ b/core/reflexes/chat_reflex.py
@@ -0,0 +1,21 @@
+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", [])
+ chats.append({
+ 'message': message,
+ 'message_id': message_id,
+ 'created_at': timezone.now()
+ })
+ cache.set("chats", chats)
+ channel = Channel("chat")
+ channel.dispatch_event({
+ 'name': 'chats:added',
+ 'detail': {'messagre_id': message_id}
+ })
+ channel.broadcast()
diff --git a/core/templates/_chat_demo.html b/core/templates/_chat_demo.html
new file mode 100644
index 0000000..2cebf93
--- /dev/null
+++ b/core/templates/_chat_demo.html
@@ -0,0 +1,21 @@
+
+