comparison src/thread.html.luan @ 42:0c1b820fff34

use push
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 08 Nov 2022 14:02:28 -0700
parents 1ce75c5ab0f7
children 96f0c3d65698
comparison
equal deleted inserted replaced
41:acb730710328 42:0c1b820fff34
1 local Luan = require "luan:Luan.luan" 1 local Luan = require "luan:Luan.luan"
2 local error = Luan.error 2 local error = Luan.error
3 local ipairs = Luan.ipairs or error() 3 local ipairs = Luan.ipairs or error()
4 local Time = require "luan:Time.luan" 4 local Time = require "luan:Time.luan"
5 local time_now = Time.now or error() 5 local time_now = Time.now or error()
6 local Html = require "luan:Html.luan"
7 local html_encode = Html.encode or error()
6 local Io = require "luan:Io.luan" 8 local Io = require "luan:Io.luan"
7 local Http = require "luan:http/Http.luan" 9 local Http = require "luan:http/Http.luan"
8 local Shared = require "site:/lib/Shared.luan" 10 local Shared = require "site:/lib/Shared.luan"
9 local head = Shared.head or error() 11 local head = Shared.head or error()
10 local header = Shared.header or error() 12 local header = Shared.header or error()
11 local footer = Shared.footer or error() 13 local footer = Shared.footer or error()
14 local delete_post = Shared.delete_post or error()
15 local show_post = Shared.show_post or error()
12 local Forum = require "site:/lib/Forum.luan" 16 local Forum = require "site:/lib/Forum.luan"
13 local forum_title = Forum.title or error() 17 local forum_title = Forum.title or error()
14 local Db = require "site:/lib/Db.luan" 18 local Db = require "site:/lib/Db.luan"
15 local Post = require "site:/lib/Post.luan" 19 local Post = require "site:/lib/Post.luan"
16 local Bbcode = require "site:/lib/Bbcode.luan" 20 local Bbcode = require "site:/lib/Bbcode.luan"
17 local bbcode_to_html = Bbcode.to_html or error() 21 local bbcode_to_html = Bbcode.to_html or error()
18 local User = require "site:/lib/User.luan" 22 local User = require "site:/lib/User.luan"
19 23
20
21 local function deletePost()
22 %><a href="javascript:" onclick="deletePost(parentNode)">delete</a><%
23 end
24 24
25 return function() 25 return function()
26 local root_id = Http.request.parameters.root or error() 26 local root_id = Http.request.parameters.root or error()
27 local docs, total_hits = Db.search("post_root_id:"..root_id,1,1000,{sort="id"}) 27 local docs, total_hits = Db.search("post_root_id:"..root_id,1,1000,{sort="id"})
28 local posts = Post.from_docs(docs) 28 local posts = Post.from_docs(docs)
58 line-height: 1.4; 58 line-height: 1.4;
59 } 59 }
60 textarea { 60 textarea {
61 width: 100%; 61 width: 100%;
62 xmax-width: 450px; 62 xmax-width: 450px;
63 height: 100px; 63 xheight: 100px;
64 } 64 }
65 </style> 65 <% if user_name == nil then %>
66 [logged_in] {
67 display: none;
68 }
69 <% end %>
70 [only_user] {
71 display: none;
72 }
73 <% if user_name ~= nil then %>
74 [only_user="<%=html_encode(user_name)%>"] {
75 display: initial;
76 }
77 <% end %>
78 div[post]:first-of-type [delete_opton] {
79 display: none;
80 }
81 body[thread_size="1"] div[post]:first-of-type [delete_opton] {
82 display: initial;
83 }
84 </style>
66 <script> 85 <script>
67 function getPostDiv(node) { 86 function getPostDiv(node) {
68 do { 87 do {
69 if( node.getAttribute('post') ) 88 if( node.getAttribute('post') )
70 return node; 89 return node;
78 } 97 }
79 function saveEdit(src) { 98 function saveEdit(src) {
80 let postDiv = getPostDiv(src); 99 let postDiv = getPostDiv(src);
81 let post = postDiv.getAttribute('post'); 100 let post = postDiv.getAttribute('post');
82 let text = postDiv.querySelector('textarea').value; 101 let text = postDiv.querySelector('textarea').value;
102 cancelEdit(src);
83 let postData = 'post=' + post + '&text=' + encodeURIComponent(text); 103 let postData = 'post=' + post + '&text=' + encodeURIComponent(text);
84 ajax('save_edit.js',postData); 104 ajax('save_edit.js',postData);
105 }
106 function updated(postId,html) {
107 let postDiv = document.querySelector('[post="'+postId+'"]');
108 if(postDiv)
109 postDiv.querySelector('[message]').innerHTML = html;
110 }
111
112 function newPost() {
113 let postDiv = document.querySelector('[post="new"]');
114 let textarea = postDiv.querySelector('textarea')
115 let text = textarea.value;
116 textarea.value = '';
117 let postData = 'root=<%=root_id%>&text=' + encodeURIComponent(text);
118 ajax('new_post.js',postData);
119 }
120 function added(postId,html,thread_size) {
121 if( document.querySelector('[post="'+postId+'"]') )
122 return;
123 let newDiv = document.querySelector('[post="new"]');
124 newDiv.insertAdjacentHTML('beforebegin',html);
125 document.body.setAttribute('thread_size',thread_size);
85 } 126 }
86 127
87 function uploaded(input,url,filename) { 128 function uploaded(input,url,filename) {
88 let postDiv = getPostDiv(input); 129 let postDiv = getPostDiv(input);
89 let textarea = postDiv.querySelector('textarea'); 130 let textarea = postDiv.querySelector('textarea');
98 span.innerHTML = document.querySelector('[hidden][undelete]').innerHTML; 139 span.innerHTML = document.querySelector('[hidden][undelete]').innerHTML;
99 } 140 }
100 function deleteYes(span) { 141 function deleteYes(span) {
101 let post = getPostDiv(span).getAttribute('post'); 142 let post = getPostDiv(span).getAttribute('post');
102 ajax( '/delete.js?post=' + post ); 143 ajax( '/delete.js?post=' + post );
144 }
145 function deleted(postId,thread_size) {
146 let postDiv = document.querySelector('[post="'+postId+'"]');
147 if(!postDiv)
148 return
149 postDiv.outerHTML = '';
150 document.body.setAttribute('thread_size',thread_size);
103 } 151 }
104 152
105 function init() { 153 function init() {
106 let spans = document.querySelectorAll('span[ago]'); 154 let spans = document.querySelectorAll('span[ago]');
107 for( let i=0; i<spans.length; i++ ) { 155 for( let i=0; i<spans.length; i++ ) {
109 let date = span.getAttribute('date'); 157 let date = span.getAttribute('date');
110 date = parseInt(date); 158 date = parseInt(date);
111 span.title = new Date(date).toLocaleString(); 159 span.title = new Date(date).toLocaleString();
112 } 160 }
113 } 161 }
162
163 let eventSource = new EventSource(location.href);
164 eventSource.onmessage = function(event) {
165 eval( event.data );
166 };
114 </script> 167 </script>
115 </head> 168 </head>
116 <body onload="init()"> 169 <body onload="init()" thread_size="<%=Post.thread_size(root_id)%>">
117 <% header() %> 170 <% header() %>
118 <div content> 171 <div content>
119 <h1><%=subject_html%></h1> 172 <h1><%=subject_html%></h1>
120 <% for _, post in ipairs(posts) do 173 <% for _, post in ipairs(posts) do
121 if post.is_deleted then 174 show_post(post,now)
122 continue 175 end %>
123 end 176 <div post=new logged_in>
124 %> 177 <hr>
125 <hr> 178 <textarea oninput="fixTextarea(this)"></textarea>
126 <div post="<%=post.id%>"> 179 <p>
127 <div author> 180 <input type=file onchange="upload(this,uploaded)">
128 <img src="/images/profile.png"> 181 <button onclick="fileButtonClick(this)">Upload File</button>
129 <a href="/whatever"><%= post.author_name %></a> 182 <button onclick="newPost()">save</button>
130 <span ago date="<%=post.date%>"><% post.ago(now) %> ago</span> 183 </p>
131 </div>
132 <div output>
133 <% bbcode_to_html(post.content) %>
134 <p>
135 <a href="/reply.html?parent=<%=post.id%>">reply</a>
136 <% if post.author_name == user_name then %>
137 - <a href="javascript:ajax('/edit.js?post=<%=post.id%>')">edit</a>
138 - <span delete><%deletePost()%></span>
139 <% end %>
140 </p>
141 </div>
142 <div edit></div>
143 </div> 184 </div>
144 <% end %>
145 </div> 185 </div>
146 <% footer() %> 186 <% footer() %>
187
147 <span hidden delete>Delete? <a href="javascript:" onclick="deleteYes(parentNode)">yes</a> / <a href="javascript:" onclick="deleteNo(parentNode)">no</a></span> 188 <span hidden delete>Delete? <a href="javascript:" onclick="deleteYes(parentNode)">yes</a> / <a href="javascript:" onclick="deleteNo(parentNode)">no</a></span>
148 <span hidden undelete><%deletePost()%></span> 189 <span hidden undelete><%delete_post()%></span>
149 <div hidden edit> 190 <div hidden edit>
150 <textarea></textarea> 191 <textarea oninput="fixTextarea(this)"></textarea>
151 <p> 192 <p>
152 <input type=file onchange="upload(this,uploaded)"> 193 <input type=file onchange="upload(this,uploaded)">
153 <button onclick="fileButtonClick(this)">Upload File</button> 194 <button onclick="fileButtonClick(this)">Upload File</button>
154 <button onclick="saveEdit(this)">save</button> 195 <button onclick="saveEdit(this)">save</button>
155 <button onclick="cancelEdit(this)">cancel</button> 196 <button onclick="cancelEdit(this)">cancel</button>