Mercurial Hosting > chat
changeset 10:f9e6a4cc4f7d
add Post
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 30 Oct 2024 23:18:45 -0600 |
parents | b8b12fd8be22 |
children | 563a5358f2ee |
files | src/add_post.js.luan src/chat.css src/chat.html.luan src/chat.js src/chat.js.luan src/get_chat.js.luan src/images/send.svg src/lib/Db.luan src/lib/Post.luan src/lib/Shared.luan src/site.css |
diffstat | 11 files changed, 283 insertions(+), 74 deletions(-) [+] |
line wrap: on
line diff
diff -r b8b12fd8be22 -r f9e6a4cc4f7d src/add_post.js.luan --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/add_post.js.luan Wed Oct 30 23:18:45 2024 -0600 @@ -0,0 +1,34 @@ +local Luan = require "luan:Luan.luan" +local error = Luan.error +local Time = require "luan:Time.luan" +local time_now = Time.now or error() +local Io = require "luan:Io.luan" +local Http = require "luan:http/Http.luan" +local User = require "site:/lib/User.luan" +local current_user = User.current or error() +local Db = require "site:/lib/Db.luan" +local run_in_transaction = Db.run_in_transaction or error() +local Chat = require "site:/lib/Chat.luan" +local get_chat_by_id = Chat.get_by_id or error() +local Post = require "site:/lib/Post.luan" +local new_post = Post.new or error() + + +return function() + local user = current_user() or error() + local chat = Http.request.parameters.chat or error() + local content = Http.request.parameters.content or error() + run_in_transaction( function() + chat = get_chat_by_id(chat) or error() + local now = time_now() + local post = new_post{ + chat_id = chat.id + author_id = user.id + date = now + content = content + } + post.save() + chat.updated = now + chat.save() + end ) +end
diff -r b8b12fd8be22 -r f9e6a4cc4f7d src/chat.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/chat.css Wed Oct 30 23:18:45 2024 -0600 @@ -0,0 +1,75 @@ +div[content] { + margin-bottom: 0; + display: flex; + xheight: 100%; + height: calc(100vh - 32px); + margin-left: calc(3% - 8px); + margin-right: 0; +} + +div[chats] { + width: 250px; + padding-right: 8px; + flex-shrink: 0; + overflow-y: auto; +} + +div[chats] > div { + margin-top: 2px; + margin-bottom: 2px; + padding-top: 16px; + padding-bottom: 16px; + padding-left: 8px; + padding-right: 8px; + border-radius: 4px; +} + +div[chats] > div:hover, +div[chats] > div[selected] { + background-color: LightBlue; +} + +div[posts] { + padding-left: 8px; + border-left: 1px solid; + width: 100%; + display: flex; + flex-direction: column; +} + +div[posts] > * { + padding-right: 3vw; +} + +div[top] { + display: flex; + justify-content: space-between; + align-items: center; +} + +div[main] { + overflow-y: auto; +} + +div[post] { + margin-top: 16px; + margin-bottom: 16px; +} + +div[text] { + white-space-collapse: preserve; +} + +div[input] { + padding-top: 1em; + padding-bottom: 1em; + display: flex; + gap: 8px; + align-items: flex-end; +} + +div[input] textarea { + flex-grow: 1; + max-height: 150px; + resize: none; +}
diff -r b8b12fd8be22 -r f9e6a4cc4f7d src/chat.html.luan --- a/src/chat.html.luan Wed Oct 30 10:18:13 2024 -0600 +++ b/src/chat.html.luan Wed Oct 30 23:18:45 2024 -0600 @@ -2,6 +2,7 @@ local error = Luan.error local ipairs = Luan.ipairs or error() local pairs = Luan.pairs or error() +local range = Luan.range or error() local Table = require "luan:Table.luan" local concat = Table.concat or error() local is_empty = Table.is_empty or error() @@ -11,6 +12,7 @@ local Shared = require "site:/lib/Shared.luan" local head = Shared.head or error() local header = Shared.header or error() +local started = Shared.started or error() local User = require "site:/lib/User.luan" local current_user = User.current or error() local get_user_by_email = User.get_by_email or error() @@ -82,54 +84,9 @@ <head> <% head() %> <style> - body { - height: 100vh; - display: flex; - flex-direction: column; - } - div[content] { - margin-bottom: 0; - display: flex; - height: 100%; - margin-left: calc(3% - 8px); - } - div[chats] { - width: 250px; - padding-right: 8px; - } - div[chats] > div { - margin-top: 2px; - margin-bottom: 2px; - padding-top: 16px; - padding-bottom: 16px; - padding-left: 8px; - padding-right: 8px; - border-radius: 4px; - } - div[chats] > div:hover, - div[chats] > div[selected] { - background-color: LightBlue; - } - div[posts] { - padding-left: 8px; - border-left: 1px solid; - } + @import "chat.css?s=<%=started%>"; </style> - <script> - 'use strict'; - - let currentChatId = null; - - function selectChat(div) { - let chatId = div.getAttribute('chat'); - if( chatId === currentChatId ) - return; - let selected = div.parentNode.querySelector('[selected]'); - if( selected ) selected.removeAttribute('selected'); - div.setAttribute('selected',''); - ajax(`chat.js?chat=${chatId}`); - } - </script> + <script src="chat.js?s=<%=started%>"></script> </head> <body> <% header() %>
diff -r b8b12fd8be22 -r f9e6a4cc4f7d src/chat.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/chat.js Wed Oct 30 23:18:45 2024 -0600 @@ -0,0 +1,48 @@ +'use strict'; + +let currentChatId = null; + +function selectChat(div) { + let chatId = div.getAttribute('chat'); + if( chatId === currentChatId ) + return; + let selected = div.parentNode.querySelector('[selected]'); + if( selected ) selected.removeAttribute('selected'); + div.setAttribute('selected',''); + ajax(`get_chat.js?chat=${chatId}`); + currentChatId = chatId; +} + +function fixTextarea(event) { + let textarea = event.target; + textarea.style.height = 'initial'; + textarea.style.height = (textarea.scrollHeight+2) + 'px'; + textarea.scrollIntoViewIfNeeded(false); +} + +const isMobile = 'ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0; + +function addPost() { + let textarea = document.querySelector('div[input] textarea'); + let text = textarea.value; + if( text.trim() === '' ) + return; + ajax(`add_post.js?chat=${currentChatId}&content=${encodeURIComponent(text)}`); + textarea.value = ''; + console.log('addPost'); +} + +function textareaKey(event) { + if( event.keyCode===13 && !event.shiftKey && !event.ctrlKey && !isMobile ) { + event.preventDefault(); + addPost(); + } +} + +function fixDates() { + let spans = document.querySelectorAll('span[when][fix]'); + for( let span of spans ) { + span.textContent = new Date(Number(span.textContent)).toLocaleString(); + span.removeAttribute('fix'); + } +}
diff -r b8b12fd8be22 -r f9e6a4cc4f7d src/chat.js.luan --- a/src/chat.js.luan Wed Oct 30 10:18:13 2024 -0600 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -local Luan = require "luan:Luan.luan" -local error = Luan.error -local Parsers = require "luan:Parsers.luan" -local json_string = Parsers.json_string or error() -local Io = require "luan:Io.luan" -local Http = require "luan:http/Http.luan" -local User = require "site:/lib/User.luan" -local current_user = User.current or error() -local Chat = require "site:/lib/Chat.luan" -local get_chat_by_id = Chat.get_by_id or error() - - -local function html() - local user = current_user() or error() - local chat = Http.request.parameters.chat or error() - chat = get_chat_by_id(chat) or error() -%> - <p><%= chat.other_users_email(user) %></p> -<% -end - -return function() - Io.stdout = Http.response.text_writer() -%> - document.querySelector('div[posts]').innerHTML = <%=json_string(`html()`)%>; -<% -end
diff -r b8b12fd8be22 -r f9e6a4cc4f7d src/get_chat.js.luan --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/get_chat.js.luan Wed Oct 30 23:18:45 2024 -0600 @@ -0,0 +1,64 @@ +local Luan = require "luan:Luan.luan" +local error = Luan.error +local ipairs = Luan.ipairs or error() +local Parsers = require "luan:Parsers.luan" +local json_string = Parsers.json_string or error() +local Html = require "luan:Html.luan" +local html_encode = Html.encode or error() +local Io = require "luan:Io.luan" +local Http = require "luan:http/Http.luan" +local User = require "site:/lib/User.luan" +local get_user_by_id = User.get_by_id or error() +local current_user = User.current or error() +local Chat = require "site:/lib/Chat.luan" +local get_chat_by_id = Chat.get_by_id or error() +local Post = require "site:/lib/Post.luan" +local post_search = Post.search or error() + + +local function post_html(post) + local author = get_user_by_id(post.author_id) + local id = post.id +%> + <div post="<%=id%>"> + <div who> + <span author><%=author.email%></span> + <span when fix><%=post.date%></span> + </div> + <div text><%= html_encode(post.content) %></div> + </div> +<% +end + +local function html() + local user = current_user() or error() + local chat = Http.request.parameters.chat or error() + chat = get_chat_by_id(chat) or error() + local posts = post_search( "post_chat_id:"..chat.id, "id" ) +%> + <div top> + <h3><%= chat.other_users_email(user) %></h3> + <button>delete</button> + </div> + <div main> +<% + for _, post in ipairs(posts) do + post_html(post) + end +%> + <div input> + <textarea oninput="fixTextarea(event)" onkeydown="textareaKey(event)"></textarea> + <button onclick="addPost()" title="Send"><img src="/images/send.svg"></button> + </div> + </div> +<% +end + +return function() + Io.stdout = Http.response.text_writer() +%> + document.querySelector('div[posts]').innerHTML = <%=json_string(`html()`)%>; + fixDates(); + document.querySelector('div[input] textarea').focus(); +<% +end
diff -r b8b12fd8be22 -r f9e6a4cc4f7d src/images/send.svg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/images/send.svg Wed Oct 30 23:18:45 2024 -0600 @@ -0,0 +1,1 @@ +<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M120-160v-640l760 320-760 320Zm80-120 474-200-474-200v140l240 60-240 60v140Zm0 0v-400 400Z"/></svg> \ No newline at end of file
diff -r b8b12fd8be22 -r f9e6a4cc4f7d src/lib/Db.luan --- a/src/lib/Db.luan Wed Oct 30 10:18:13 2024 -0600 +++ b/src/lib/Db.luan Wed Oct 30 23:18:45 2024 -0600 @@ -24,6 +24,8 @@ Db.indexed_fields.chat_user_ids = Lucene.type.long Db.indexed_fields.chat_updated = Lucene.type.long +Db.indexed_fields.post_chat_id = Lucene.type.long + function Db.not_in_transaction() logger.error(new_error("not in transaction")) end
diff -r b8b12fd8be22 -r f9e6a4cc4f7d src/lib/Post.luan --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/Post.luan Wed Oct 30 23:18:45 2024 -0600 @@ -0,0 +1,53 @@ +local Luan = require "luan:Luan.luan" +local error = Luan.error +local ipairs = Luan.ipairs or error() +local Number = require "luan:Number.luan" +local long = Number.long or error() +local Db = require "site:/lib/Db.luan" + + +local Post = {} + +local function from_doc(doc) + doc.type == "post" or error "wrong type" + return Post.new { + id = doc.id + chat_id = doc.post_chat_id + author_id = doc.author_id + date = doc.date + content = doc.content + } +end + +local function to_doc(post) + return { + type = "post" + id = post.id + post_chat_id = long(post.chat_id) + author_id = long(post.author_id) + date = long(post.date) + content = post.content or error() + } +end + +function Post.new(post) + function post.save() + local doc = to_doc(post) + Db.save(doc) + post.id = doc.id + end + + return post +end + +function Post.search(query,sort,rows) + rows = rows or 1000000 + local posts = {} + local docs = Db.search(query,1,rows,{sort=sort}) + for _, doc in ipairs(docs) do + posts[#posts+1] = from_doc(doc) + end + return posts +end + +return Post