diff --git a/core/javascript/chat.js b/core/javascript/chat.js
deleted file mode 100644
index 82f77e3..0000000
--- a/core/javascript/chat.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Application } from 'stimulus'
-import StimulusReflex from 'stimulus_reflex'
-import WebsocketConsumer from 'sockpuppet-js'
-import ChatController from './controllers/chat_controller'
-
-const application = Application.start()
-const consumer = new WebsocketConsumer('ws://localhost:8000/ws/sockpuppet-sync')
-
-application.register("chat", ChatController)
-StimulusReflex.initialize(application, { consumer })
diff --git a/core/javascript/controllers/chat_controller.js b/core/javascript/controllers/chat_controller.js
index f7dd935..2b488f4 100644
--- a/core/javascript/controllers/chat_controller.js
+++ b/core/javascript/controllers/chat_controller.js
@@ -1,14 +1,51 @@
-import { Controller } from 'stimulus';
-import StimulusReflex from 'stimulus_reflex';
+import Rails from '@rails/ujs'
+import { debounce } from 'lodash-es'
+import ApplicationController from './application_controller'
-export default class extends Controller {
- connect() {
- StimulusReflex.register(this)
+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) {
+ Rails.stopEverything(event)
+ lastMessageId = Math.random()
+ this.stimulate(
+ 'ChatReflex#post',
+ this.element.dataset.color,
+ this.inputTarget.value,
+ lastMessageId
+ )
}
- increment(event) {
- console.log('increment')
- event.preventDefault()
- this.stimulate('ChatReflex#increment', 1)
+ 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..f8bacdb 100644
--- a/core/reflexes/book_search_reflex.py
+++ b/core/reflexes/book_search_reflex.py
@@ -4,7 +4,7 @@
class BookSearchReflex(Reflex):
def perform(self, query=""):
- resp = requests.get('http://openlibrary.org/search.json', params={'q':query})
+ resp = requests.get("http://openlibrary.org/search.json", params={"q": query})
resp.raise_for_status()
books = resp.json()
self.books = books.get("docs", [])
diff --git a/core/templates/_chat_demo.html b/core/templates/_chat_demo.html
index d792f7b..cc40fef 100644
--- a/core/templates/_chat_demo.html
+++ b/core/templates/_chat_demo.html
@@ -1 +1,19 @@
-chat demo
+
+
+
+ {% for chat in chats %}
+
+ {% endfor %}
+
+
+
diff --git a/core/templates/chat.html b/core/templates/chat.html
deleted file mode 100644
index b363e6e..0000000
--- a/core/templates/chat.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-{% load static %}
-
-
-
-
- Increment {{ count }}
-
diff --git a/core/views/book_search.py b/core/views/book_search.py
index e7ba2c3..f61dd85 100644
--- a/core/views/book_search.py
+++ b/core/views/book_search.py
@@ -1,15 +1,9 @@
from django.views.generic.base import TemplateView
-from .mixins import MixinBase
+from .mixins import BookSearchMixin
-class BookSearch(MixinBase, TemplateView):
+class BookSearch(BookSearchMixin, TemplateView):
demo_template = "_book_search_demo.html"
subtitle = 'Search Book'
- files = (
- ('core/reflexes/book_search_reflex.py', 'python', 'python3'),
- ('core/views/book_search.py', 'python', 'python3'),
- ('core/javascript/controllers/book_search_controller.js', 'javascript', 'javascript'),
- ('core/templates/_book_search_demo.html', 'html', 'htmldjango'),
- )
book_search = BookSearch.as_view()
diff --git a/core/views/chat.py b/core/views/chat.py
index 580de5b..aa1f096 100644
--- a/core/views/chat.py
+++ b/core/views/chat.py
@@ -3,7 +3,7 @@
class ChatView(MixinBase, TemplateView):
demo_template = '_chat_demo.html'
- subtitle = 'Increment'
+ subtitle = 'Chat'
files = (
('core/views/chat.py', 'python', 'python3'),
('core/reflexes/chat_reflex.py', 'python', 'python3'),
@@ -13,7 +13,7 @@ class ChatView(MixinBase, TemplateView):
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
- context['count'] = self.request.session.get("count", 0)
+ context['chats'] = [dict(message='message1')]
return context
chat = ChatView.as_view()
diff --git a/core/views/example.py b/core/views/example.py
index 6825b3e..4089b45 100644
--- a/core/views/example.py
+++ b/core/views/example.py
@@ -1,15 +1,9 @@
from django.views.generic.base import TemplateView
-from .mixins import MixinBase
+from .mixins import ExampleMixin
-class ExampleView(MixinBase, TemplateView):
+class ExampleView(ExampleMixin, TemplateView):
demo_template = '_example_demo.html'
subtitle = 'Increment'
- files = (
- ('core/views/example.py', 'python', 'python3'),
- ('core/reflexes/example_reflex.py', 'python', 'python3'),
- ('core/javascript/controllers/example_controller.js', 'javascript', 'javascript'),
- ('core/templates/_example_demo.html', 'html', 'htmldjango'),
- )
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
diff --git a/core/views/mixins.py b/core/views/mixins.py
index 17eb9a1..5a5a03c 100644
--- a/core/views/mixins.py
+++ b/core/views/mixins.py
@@ -6,27 +6,48 @@
class MixinBase:
- template_name="demo.html"
+ template_name = "demo.html"
demo_template = None
subtitle = None
def get_files(self):
files = defaultdict(list)
path_ = lambda x: open(os.path.join(BASE_PATH, x)).read()
- for filename, filetype, pygment_type in self.files:
+ for filename, filetype, pygment_type in self.files:
filesrc = path_(filename)
- files[filetype].append({
- 'src': filesrc,
- 'pygment_type': pygment_type,
- 'filename': filename,
- 'loc': len(filesrc.split('\n'))
- })
+ files[filetype].append(
+ {
+ "src": filesrc,
+ "pygment_type": pygment_type,
+ "filename": filename,
+ "loc": len(filesrc.split("\n")),
+ }
+ )
return dict(files)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- context['files'] = self.get_files()
- context['demo_template'] = self.demo_template
- context['subtitle'] = self.subtitle
+ context["files"] = self.get_files()
+ context["demo_template"] = self.demo_template
+ context["subtitle"] = self.subtitle
return context
+
+class BookSearchMixin(MixinBase):
+ files = (
+ ("core/reflexes/book_search_reflex.py", "python", "python3"),
+ ("core/views/book_search.py", "python", "python3"),
+ ("core/javascript/controllers/book_search_controller.js", "javascript",
+ "javascript",),
+ ("core/templates/_book_search_demo.html", "html", "htmldjango"),
+ )
+
+
+class ExampleMixin(MixinBase):
+ files = (
+ ('core/views/example.py', 'python', 'python3'),
+ ('core/reflexes/example_reflex.py', 'python', 'python3'),
+ ('core/javascript/controllers/example_controller.js', 'javascript', 'javascript'),
+ ('core/templates/_example_demo.html', 'html', 'htmldjango'),
+ )
+
diff --git a/package.json b/package.json
index 953f1d1..1192c24 100644
--- a/package.json
+++ b/package.json
@@ -19,5 +19,10 @@
"stimulus_reflex": "^3.4.0-pre5",
"webpack": "^5.6.0",
"webpack-cli": "^4.2.0"
+ },
+ "dependencies": {
+ "@rails/ujs": "^6.0.3-4",
+ "lodash-es": "^4.17.15",
+ "turbolinks": "^5.2.0"
}
}
diff --git a/yarn.lock b/yarn.lock
index 016d5dd..6f59fe0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7,6 +7,11 @@
resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-6.0.3.tgz#722b4b639936129307ddbab3a390f6bcacf3e7bc"
integrity sha512-I01hgqxxnOgOtJTGlq0ZsGJYiTEEiSGVEGQn3vimZSqEP1HqzyFNbzGTq14Xdyeow2yGJjygjoFF1pmtE+SQaw==
+"@rails/ujs@^6.0.3-4":
+ version "6.0.3-4"
+ resolved "https://nexus.gcds.coke.com/repository/npm-group/@rails/ujs/-/ujs-6.0.3-4.tgz#8dafc84178080f9c4f21076953ea1d0dc0bfe0fc"
+ integrity sha512-pNEEndJYNMCYEZG79MkoMc40AYKBfm0md8pawJ/SUu/1aIhToJcKu+9hHT/7WMLudsakOgC/C8KKFuZOs4QTgw==
+
"@stimulus/core@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@stimulus/core/-/core-1.1.1.tgz#42b0cfe5b73ca492f41de64b77a03980bae92c82"
@@ -639,6 +644,11 @@ locate-path@^5.0.0:
dependencies:
p-locate "^4.1.0"
+lodash-es@^4.17.15:
+ version "4.17.15"
+ resolved "https://nexus.gcds.coke.com/repository/npm-group/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78"
+ integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==
+
lodash@^4.17.15:
version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
@@ -976,6 +986,11 @@ tslib@^1.9.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+turbolinks@^5.2.0:
+ version "5.2.0"
+ resolved "https://nexus.gcds.coke.com/repository/npm-group/turbolinks/-/turbolinks-5.2.0.tgz#e6877a55ea5c1cb3bb225f0a4ae303d6d32ff77c"
+ integrity sha512-pMiez3tyBo6uRHFNNZoYMmrES/IaGgMhQQM+VFF36keryjb5ms0XkVpmKHkfW/4Vy96qiGW3K9bz0tF5sK9bBw==
+
typical@^5.0.0, typical@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066"