use khtml library
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
|
||||
jpacrepo.version=2024.02.24
|
||||
jpacrepo.version=2024.03.01
|
||||
|
||||
lys.version=2024.02.24
|
||||
lys.version=2024.03.01
|
||||
|
@@ -18,6 +18,7 @@ kotlin {
|
||||
jsMain {
|
||||
dependencies {
|
||||
implementation catalog.klevtree
|
||||
implementation catalog.khtml
|
||||
implementation group: 'org.jetbrains.kotlinx', name: 'kotlinx-serialization-json', version: '1.6.2'
|
||||
|
||||
implementation(npm("bootstrap", "5.3.2"))
|
||||
|
@@ -1,182 +0,0 @@
|
||||
package net.woggioni.jpacrepo
|
||||
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
import kotlin.coroutines.startCoroutine
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
import kotlin.js.Promise
|
||||
import org.w3c.dom.Document
|
||||
import org.w3c.dom.Element
|
||||
import org.w3c.dom.events.Event
|
||||
|
||||
object HtmlUtils {
|
||||
fun Element.removeChildren() {
|
||||
while (true) {
|
||||
removeChild(firstChild ?: break)
|
||||
}
|
||||
}
|
||||
|
||||
fun Element.on(eventName : String, eventListener : (Event) -> Unit) {
|
||||
addEventListener(eventName, eventListener)
|
||||
}
|
||||
|
||||
fun launch(block: suspend () -> Unit) {
|
||||
block.startCoroutine(object : Continuation<Unit> {
|
||||
override val context: CoroutineContext get() = EmptyCoroutineContext
|
||||
override fun resumeWith(result: Result<Unit>) {}
|
||||
})
|
||||
}
|
||||
|
||||
suspend fun <T> Promise<T>.await(): T = suspendCoroutine { cont ->
|
||||
then({ cont.resume(it) }, { cont.resumeWithException(it) })
|
||||
}
|
||||
}
|
||||
|
||||
class HtmlBuilder private constructor(private val doc : Document, val el: Element) {
|
||||
|
||||
companion object {
|
||||
fun <T> of(doc : Document, el: Element, cb : HtmlBuilder.(el : Element) -> T) : T {
|
||||
return HtmlBuilder(doc, el).cb(el)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T> dfd(
|
||||
name : String,
|
||||
attrs : Map<String, String>,
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T {
|
||||
val child = doc.createElement(name)
|
||||
for((key, value) in attrs) {
|
||||
child.setAttribute(key, value)
|
||||
}
|
||||
el.appendChild(child)
|
||||
return HtmlBuilder(doc, child).cb(child)
|
||||
}
|
||||
|
||||
fun <T> html(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("html", attrs, cb)
|
||||
fun <T> head(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("head", attrs, cb)
|
||||
fun <T> body(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("body", attrs, cb)
|
||||
|
||||
fun <T> use(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("use", attrs, cb)
|
||||
fun <T> svg(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("svg", attrs, cb)
|
||||
fun <T> div(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("div", attrs, cb)
|
||||
fun <T> header(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("header", attrs, cb)
|
||||
fun <T> main(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("main", attrs, cb)
|
||||
fun <T> footer(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("footer", attrs, cb)
|
||||
fun <T> a(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("a", attrs, cb)
|
||||
fun <T> meta(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("meta", attrs, cb)
|
||||
fun <T> script(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("script", attrs, cb)
|
||||
fun <T> link(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("link", attrs, cb)
|
||||
fun <T> title(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("title", attrs, cb)
|
||||
fun <T> p(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("p", attrs, cb)
|
||||
fun <T> span(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("span", attrs, cb)
|
||||
fun <T> i(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("i", attrs, cb)
|
||||
fun <T> del(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("del", attrs, cb)
|
||||
fun <T> s(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("s", attrs, cb)
|
||||
fun <T> ins(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("ins", attrs, cb)
|
||||
fun <T> u(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("u", attrs, cb)
|
||||
fun <T> b(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("b", attrs, cb)
|
||||
fun <T> small(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("small", attrs, cb)
|
||||
fun <T> strong(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("strong", attrs, cb)
|
||||
fun <T> em(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("em", attrs, cb)
|
||||
fun <T> mark(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("mark", attrs, cb)
|
||||
fun <T> obj(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("object", attrs, cb)
|
||||
fun <T> h1(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("h1", attrs, cb)
|
||||
fun <T> h2(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("h2", attrs, cb)
|
||||
fun <T> h3(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("h3", attrs, cb)
|
||||
fun <T> h4(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("h4", attrs, cb)
|
||||
fun <T> h5(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("h5", attrs, cb)
|
||||
fun <T> h6(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("h6", attrs, cb)
|
||||
fun <T> table(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("table", attrs, cb)
|
||||
fun <T> thead(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("thead", attrs, cb)
|
||||
fun <T> tbody(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("tbody", attrs, cb)
|
||||
fun <T> tfoot(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("tfoot", attrs, cb)
|
||||
fun <T> tr(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("tr", attrs, cb)
|
||||
fun <T> th(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("th", attrs, cb)
|
||||
fun <T> td(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("td", attrs, cb)
|
||||
fun <T> ol(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("ol", attrs, cb)
|
||||
fun <T> ul(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("ul", attrs, cb)
|
||||
fun <T> li(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("li", attrs, cb)
|
||||
fun <T> img(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("img", attrs, cb)
|
||||
fun <T> form(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("form", attrs, cb)
|
||||
fun <T> label(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("label", attrs, cb)
|
||||
fun <T> button(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("button", attrs, cb)
|
||||
fun <T> input(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("input", attrs, cb)
|
||||
fun <T> select(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("select", attrs, cb)
|
||||
fun <T> option(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("option", attrs, cb)
|
||||
fun <T> meter(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("meter", attrs, cb)
|
||||
fun <T> nav(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("nav", attrs, cb)
|
||||
fun <T> menu(attrs : Map<String, String> = emptyMap(),
|
||||
cb : HtmlBuilder.(el : Element) -> T) : T = dfd("menu", attrs, cb)
|
||||
|
||||
|
||||
fun classes(vararg classes : String) {
|
||||
for(cls in classes) el.classList.add(cls)
|
||||
}
|
||||
|
||||
fun attr(key: String, value : String) {
|
||||
el.setAttribute(key, value)
|
||||
}
|
||||
|
||||
fun text(txt : String) {
|
||||
el.appendChild(doc.createTextNode(txt))
|
||||
}
|
||||
|
||||
fun on(eventName : String, cb: (Event) -> Unit) {
|
||||
el.addEventListener(eventName, cb)
|
||||
}
|
||||
}
|
@@ -6,11 +6,12 @@ import kotlinx.browser.document
|
||||
import kotlinx.browser.window
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import net.woggioni.jpacrepo.HtmlUtils.await
|
||||
import net.woggioni.jpacrepo.HtmlUtils.launch
|
||||
import net.woggioni.jpacrepo.HtmlUtils.on
|
||||
import net.woggioni.jpacrepo.HtmlUtils.removeChildren
|
||||
import net.woggioni.jpacrepo.common.JpacrepoCommons.toHexString
|
||||
import net.woggioni.khtml.Khtml
|
||||
import net.woggioni.khtml.Khtml.Companion.await
|
||||
import net.woggioni.khtml.Khtml.Companion.launch
|
||||
import net.woggioni.khtml.Khtml.Companion.on
|
||||
import net.woggioni.khtml.Khtml.Companion.removeChildren
|
||||
import net.woggioni.klevtree.LevTrie
|
||||
import org.w3c.dom.CustomEvent
|
||||
import org.w3c.dom.Element
|
||||
@@ -132,7 +133,7 @@ suspend fun buildTable(root: Element, searchTerm: String, commonElement: Element
|
||||
while (children.length > 0) {
|
||||
children[0]!!.remove()
|
||||
}
|
||||
HtmlBuilder.of(document, root) {
|
||||
Khtml.of(document, root) {
|
||||
table {
|
||||
classes("table", "table-striped", "pkgtable")
|
||||
thead {
|
||||
@@ -209,9 +210,9 @@ suspend fun buildTable(root: Element, searchTerm: String, commonElement: Element
|
||||
?.let { it[selectedVersion] }
|
||||
availablePackages?.keys?.first()
|
||||
}
|
||||
var selectedCompressionFormat = getFirstAvailableCompressionFormat()
|
||||
var selectedCompressionFormat: CompressionFormat?
|
||||
|
||||
fun HtmlBuilder.createCompressionFormatDropdown() {
|
||||
fun Khtml.createCompressionFormatDropdown() {
|
||||
val availablePackages = packages
|
||||
?.let { it[selectedVersion] }
|
||||
availablePackages?.keys?.let { compressionFormats ->
|
||||
@@ -236,24 +237,21 @@ suspend fun buildTable(root: Element, searchTerm: String, commonElement: Element
|
||||
|
||||
val compressionFormatCell = td {
|
||||
createCompressionFormatDropdown()
|
||||
el
|
||||
}
|
||||
val fileNameCell = td {
|
||||
selectedPackage?.let {
|
||||
text(it.second.fileName)
|
||||
}
|
||||
el
|
||||
}
|
||||
val sizeCell = td {
|
||||
selectedPackage?.let {
|
||||
text(it.second.size.toHumanReadableByteSize())
|
||||
}
|
||||
el
|
||||
}
|
||||
on(REFRESH_TABLE_ROW_EVENT_NAME) { evt ->
|
||||
on(REFRESH_TABLE_ROW_EVENT_NAME) {
|
||||
selectedCompressionFormat = getFirstAvailableCompressionFormat()
|
||||
compressionFormatCell.removeChildren()
|
||||
HtmlBuilder.of(document, compressionFormatCell) {
|
||||
Khtml.of(document, compressionFormatCell) {
|
||||
createCompressionFormatDropdown()
|
||||
}
|
||||
selectedPackage = archive.pkgMap[arch]?.let {
|
||||
@@ -278,9 +276,9 @@ suspend fun buildTable(root: Element, searchTerm: String, commonElement: Element
|
||||
}
|
||||
}
|
||||
|
||||
private fun HtmlBuilder.buildPackageSearchSection(commonElement: Element) {
|
||||
val root = el
|
||||
private fun Khtml.buildPackageSearchSection(commonElement: Element) {
|
||||
var selectedPackageName: String? = null
|
||||
val root = element
|
||||
div {
|
||||
classes("row", "g-5")
|
||||
div {
|
||||
@@ -354,7 +352,7 @@ private fun HtmlBuilder.buildPackageSearchSection(commonElement: Element) {
|
||||
}
|
||||
div { table ->
|
||||
classes("row", "align-items-md-stretch")
|
||||
root.on(REFRESH_TABLE_EVENT_NAME) { evt ->
|
||||
root.on(REFRESH_TABLE_EVENT_NAME) { evt : Event ->
|
||||
launch {
|
||||
(evt as? CustomEvent)?.let { pnuv ->
|
||||
table.let { t ->
|
||||
@@ -371,7 +369,7 @@ private fun HtmlBuilder.buildPackageSearchSection(commonElement: Element) {
|
||||
|
||||
fun main(vararg args: String) {
|
||||
js("require ('./scss/styles.scss');")
|
||||
HtmlBuilder.of(document, document.body as HTMLElement) {
|
||||
Khtml.of(document, document.body as HTMLElement) {
|
||||
main { main ->
|
||||
div {
|
||||
classes("container", "py-4")
|
||||
@@ -392,7 +390,7 @@ fun main(vararg args: String) {
|
||||
div {
|
||||
classes("container")
|
||||
div {
|
||||
val commonElement = el
|
||||
val commonElement = element
|
||||
classes("row", "align-items-start")
|
||||
div {
|
||||
classes("col-3")
|
||||
@@ -405,7 +403,7 @@ fun main(vararg args: String) {
|
||||
text("Package Cart")
|
||||
}
|
||||
}
|
||||
fun HtmlBuilder.createSelectedPackageList() {
|
||||
fun Khtml.createSelectedPackageList() {
|
||||
if (selectedPackages.isNotEmpty()) {
|
||||
div {
|
||||
classes("card-body")
|
||||
@@ -433,7 +431,7 @@ fun main(vararg args: String) {
|
||||
}
|
||||
button {
|
||||
classes("btn", "btn-primary", "w-100")
|
||||
el.asDynamic().style.marginTop = "10px"
|
||||
element.asDynamic().style.marginTop = "10px"
|
||||
val totalSize = selectedPackages
|
||||
.asSequence()
|
||||
.map(PkgTuple::size)
|
||||
@@ -453,9 +451,9 @@ fun main(vararg args: String) {
|
||||
.map(PkgTuple::fileName)
|
||||
.joinToString(" ")
|
||||
temporaryForm.appendChild(textField)
|
||||
el.appendChild(temporaryForm)
|
||||
element.appendChild(temporaryForm)
|
||||
temporaryForm.submit()
|
||||
el.removeChild(temporaryForm)
|
||||
element.removeChild(temporaryForm)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -464,7 +462,7 @@ fun main(vararg args: String) {
|
||||
div {
|
||||
createSelectedPackageList()
|
||||
commonElement.on(REFRESH_SELECTED_PACKAGES_EVENT_NAME) {
|
||||
el.removeChildren()
|
||||
element.removeChildren()
|
||||
createSelectedPackageList()
|
||||
}
|
||||
}
|
||||
@@ -474,7 +472,6 @@ fun main(vararg args: String) {
|
||||
classes("col-9")
|
||||
buildPackageSearchSection(commonElement)
|
||||
}
|
||||
el
|
||||
}
|
||||
}
|
||||
footer {
|
||||
|
Reference in New Issue
Block a user