Add post auto update

This commit is contained in:
Lars Westermann 2019-05-25 17:37:17 +02:00
parent 2be6c7c819
commit 74c297263e
Signed by: lars.westermann
GPG key ID: 9D417FA5BB9D5E1D
13 changed files with 354 additions and 40 deletions

View file

@ -61,7 +61,8 @@ class WebSocketClient() {
ScheduleRepository.handler,
TrackRepository.handler,
UserRepository.handler,
WorkGroupRepository.handler
WorkGroupRepository.handler,
PostRepository.handler
)
init {

View file

@ -1,8 +1,10 @@
package de.kif.frontend
import de.kif.frontend.views.calendar.initCalendar
import de.kif.frontend.views.initTableLayout
import de.kif.frontend.views.table.initTableLayout
import de.kif.frontend.views.initWorkGroupConstraints
import de.kif.frontend.views.overview.initOverviewMain
import de.kif.frontend.views.overview.initPosts
import de.westermann.kwebview.components.init
import kotlin.browser.document
@ -18,4 +20,10 @@ fun main() = init {
if (document.getElementsByClassName("work-group-constraints").length > 0) {
initWorkGroupConstraints()
}
if (document.getElementsByClassName("overview-main").length > 0) {
initOverviewMain()
}
if (document.getElementsByClassName("post").length > 0) {
initPosts()
}
}

View file

@ -82,6 +82,30 @@ suspend fun repositoryPost(
}
}
suspend fun repositoryRawGet(
url: String
): String {
console.log("GET: $url")
val promise = Promise<String> { resolve, reject ->
val xhttp = XMLHttpRequest()
xhttp.onreadystatechange = {
if (xhttp.readyState == 4.toShort()) {
if (xhttp.status == 200.toShort() || xhttp.status == 304.toShort()) {
resolve(xhttp.responseText)
} else {
reject(NoSuchElementException("${xhttp.status}: ${xhttp.statusText}"))
}
}
}
xhttp.open("GET", url, true)
xhttp.send()
}
return promise.await()
}
suspend fun <T> Promise<T>.await(): T = suspendCoroutine { cont ->
then({ cont.resume(it) }, { cont.resumeWithException(it) })
}

View file

@ -0,0 +1,56 @@
package de.kif.frontend.repository
import de.kif.common.Message
import de.kif.common.Repository
import de.kif.common.RepositoryType
import de.kif.common.model.Post
import de.kif.frontend.MessageHandler
import de.westermann.kobserve.event.EventHandler
import kotlinx.serialization.DynamicObjectParser
import kotlinx.serialization.list
object PostRepository : Repository<Post> {
override val onCreate = EventHandler<Long>()
override val onUpdate = EventHandler<Long>()
override val onDelete = EventHandler<Long>()
private val parser = DynamicObjectParser()
override suspend fun get(id: Long): Post? {
val json = repositoryGet("/api/post/$id") ?: return null
return parser.parse(json, Post.serializer())
}
override suspend fun create(model: Post): Long {
return repositoryPost("/api/posts", Message.json.stringify(Post.serializer(), model))
?: throw IllegalStateException("Cannot create model!")
}
override suspend fun update(model: Post) {
if (model.id == null) throw IllegalStateException("Cannot update model which was not created!")
repositoryPost("/api/post/${model.id}", Message.json.stringify(Post.serializer(), model))
}
override suspend fun delete(id: Long) {
repositoryPost("/api/post/$id/delete")
}
override suspend fun all(): List<Post> {
val json = repositoryGet("/api/posts") ?: return emptyList()
return parser.parse(json, Post.serializer().list)
}
suspend fun htmlByUrl(url: String): String {
return repositoryRawGet("/api/p/$url")
}
val handler = object : MessageHandler(RepositoryType.POST) {
override fun onCreate(id: Long) = onCreate.emit(id)
override fun onUpdate(id: Long) = onUpdate.emit(id)
override fun onDelete(id: Long) = onDelete.emit(id)
}
}

View file

@ -0,0 +1,41 @@
package de.kif.frontend.views.overview
import de.kif.frontend.iterator
import de.kif.frontend.repository.PostRepository
import org.w3c.dom.HTMLElement
import org.w3c.dom.get
import kotlin.browser.document
fun initOverviewMain() {
val main = document.getElementsByClassName("overview-main")[0] as HTMLElement
PostRepository.onCreate {
val post = PostView.create(it)
post.classList += "overview-post"
val first = main.firstElementChild as? HTMLElement
if (first == null) {
main.appendChild(post.html)
return@onCreate
}
if (first.classList.contains("post")) {
main.insertBefore(post.html, first)
return@onCreate
}
val next = first.nextElementSibling as? HTMLElement
if (next == null) {
main.appendChild(post.html)
} else {
main.insertBefore(post.html, next)
}
}
}
fun initPosts() {
val postList = document.getElementsByClassName("post")
for (post in postList) {
PostView(post)
}
}

View file

@ -0,0 +1,69 @@
package de.kif.frontend.views.overview
import de.kif.common.model.Post
import de.kif.frontend.launch
import de.kif.frontend.repository.PostRepository
import de.westermann.kwebview.View
import de.westermann.kwebview.components.Link
import de.westermann.kwebview.createHtmlView
import org.w3c.dom.HTMLAnchorElement
import org.w3c.dom.HTMLElement
import org.w3c.dom.get
import org.w3c.dom.set
import kotlin.browser.document
class PostView(
view: HTMLElement
) : View(view) {
private var postId = dataset["id"]?.toLongOrNull() ?: -1
private val nameView: Link
private val contentView: View
private fun reload() {
launch {
val p = PostRepository.get(postId) ?: return@launch
nameView.text = p.name
nameView.target = "/p/${p.url}"
contentView.html.innerHTML = PostRepository.htmlByUrl(p.url)
}
}
init {
val nameHtml = view.getElementsByClassName("post-name")[0]
nameView = nameHtml?.let { Link.wrap(it as HTMLAnchorElement) } ?: Link().also {
html.appendChild(it.html)
it.classList += "post-name"
}
// val editHtml = view.getElementsByClassName("post-edit")[0]
// editView = editHtml?.let { Link.wrap(it as HTMLAnchorElement) } ?: Link()
val contentHtml = view.getElementsByClassName("post-content")[0]
contentView = contentHtml?.let { wrap(it as HTMLElement) } ?: wrap(createHtmlView()).also {
html.appendChild(it.html)
it.classList += "post-content"
}
PostRepository.onUpdate {
if (it == postId) {
reload()
}
}
PostRepository.onDelete {
html.remove()
}
}
companion object {
fun create(postId: Long): PostView {
val div = document.createElement("div") as HTMLElement
div.classList.add("post")
div.dataset["id"] = postId.toString()
return PostView(div).also(PostView::reload)
}
}
}

View file

@ -1,9 +1,6 @@
package de.kif.frontend.views
package de.kif.frontend.views.table
import de.kif.frontend.iterator
import de.kif.frontend.views.table.RoomTableLine
import de.kif.frontend.views.table.TableLine
import de.kif.frontend.views.table.WorkGroupTableLine
import de.westermann.kwebview.components.InputView
import org.w3c.dom.HTMLFormElement
import org.w3c.dom.HTMLInputElement

View file

@ -11,7 +11,11 @@ import org.w3c.dom.HTMLAnchorElement
*
* @author lars
*/
class Link(target: String) : ViewCollection<View>(createHtmlView<HTMLAnchorElement>("a")) {
class Link(view: HTMLAnchorElement = createHtmlView()) : View(view) {
constructor(target: String, view: HTMLAnchorElement = createHtmlView()): this(view) {
this.target = target
}
override val html = super.html as HTMLAnchorElement
@ -27,8 +31,8 @@ class Link(target: String) : ViewCollection<View>(createHtmlView<HTMLAnchorEleme
html.href = value
}
init {
this.target = target
companion object {
fun wrap(view: HTMLAnchorElement) = Link(view)
}
}

View file

@ -1036,6 +1036,7 @@ form {
.overview-post {
max-height: 20rem;
overflow: hidden;
margin-bottom: 1rem;
&::after {
content: '';