diff options
9 files changed, 76 insertions, 38 deletions
diff --git a/kvision-modules/kvision-bootstrap-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemoteInput.kt b/kvision-modules/kvision-bootstrap-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemoteInput.kt index b2dad8fe..5d60e4fe 100644 --- a/kvision-modules/kvision-bootstrap-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemoteInput.kt +++ b/kvision-modules/kvision-bootstrap-select-remote/src/main/kotlin/pl/treksoft/kvision/form/select/SelectRemoteInput.kt @@ -28,6 +28,8 @@ import kotlinx.serialization.ImplicitReflectionSerializer import kotlinx.serialization.builtins.list import kotlinx.serialization.stringify import org.w3c.dom.get +import pl.treksoft.jquery.JQueryAjaxSettings +import pl.treksoft.jquery.JQueryXHR import pl.treksoft.kvision.core.Container import pl.treksoft.kvision.remote.CallAgent import pl.treksoft.kvision.remote.HttpMethod @@ -72,12 +74,14 @@ open class SelectRemoteInput<T : Any>( private val url: String private val labelsCache = mutableMapOf<String, String>() private var initRun = false + private var beforeSend: ((JQueryXHR, JQueryAjaxSettings) -> dynamic)? init { val (_url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") this.url = _url + this.beforeSend = ajaxOptions?.beforeSend if (!preload) { val data = obj { q = "{{{q}}}" @@ -103,9 +107,10 @@ open class SelectRemoteInput<T : Any>( }.toTypedArray() }, data = data, - beforeSend = { _, b -> + beforeSend = { xhr, b -> + beforeSend?.invoke(xhr, b) @Suppress("UnsafeCastFromDynamic") - val q = decodeURIComponent(b.data.substring(2)) + val q = decodeURIComponent(b.asDynamic().data.substring(2)) val state = stateFunction?.invoke() b.data = JSON.plain.stringify(JsonRpcRequest(0, url, listOf(q, this.value, state))) true @@ -131,7 +136,8 @@ open class SelectRemoteInput<T : Any>( val values = callAgent.remoteCall( url, JSON.plain.stringify(JsonRpcRequest(0, url, listOf(null, null, state))), - HttpMethod.POST + HttpMethod.POST, + beforeSend = beforeSend ).await() JSON.plain.parse(RemoteOption.serializer().list, values.result as String).forEach { add( @@ -168,7 +174,8 @@ open class SelectRemoteInput<T : Any>( val initials = callAgent.remoteCall( url, JSON.plain.stringify(JsonRpcRequest(0, url, listOf(null, it, state))), - HttpMethod.POST + HttpMethod.POST, + beforeSend = beforeSend ).await() JSON.plain.parse(RemoteOption.serializer().list, initials.result as String).mapNotNull { it.text diff --git a/kvision-modules/kvision-bootstrap-select/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt b/kvision-modules/kvision-bootstrap-select/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt index cfda10e2..9b549cba 100644 --- a/kvision-modules/kvision-bootstrap-select/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt +++ b/kvision-modules/kvision-bootstrap-select/src/main/kotlin/pl/treksoft/kvision/form/select/AjaxOptions.kt @@ -21,6 +21,7 @@ */ package pl.treksoft.kvision.form.select +import pl.treksoft.jquery.JQueryAjaxSettings import pl.treksoft.jquery.JQueryXHR import pl.treksoft.kvision.KVManagerSelect.AJAX_REQUEST_DELAY import pl.treksoft.kvision.KVManagerSelect.KVNULL @@ -85,7 +86,7 @@ enum class DataType(internal val type: String) { data class AjaxOptions( val url: String? = null, val preprocessData: ((dynamic) -> dynamic)? = null, - val beforeSend: ((JQueryXHR, dynamic) -> dynamic)? = null, + val beforeSend: ((JQueryXHR, JQueryAjaxSettings) -> dynamic)? = null, val data: dynamic = null, val httpType: HttpType = HttpType.GET, val dataType: DataType = DataType.JSON, diff --git a/kvision-modules/kvision-bootstrap-typeahead-remote/src/main/kotlin/pl/treksoft/kvision/form/text/TypeaheadRemoteInput.kt b/kvision-modules/kvision-bootstrap-typeahead-remote/src/main/kotlin/pl/treksoft/kvision/form/text/TypeaheadRemoteInput.kt index 932a86ff..afefae58 100644 --- a/kvision-modules/kvision-bootstrap-typeahead-remote/src/main/kotlin/pl/treksoft/kvision/form/text/TypeaheadRemoteInput.kt +++ b/kvision-modules/kvision-bootstrap-typeahead-remote/src/main/kotlin/pl/treksoft/kvision/form/text/TypeaheadRemoteInput.kt @@ -45,6 +45,7 @@ import kotlin.browser.window * @param delay a delay between lookups * @param type text input type (default "text") * @param value text input value + * @param taAjaxOptions AJAX options for remote data source * @param classes a set of CSS class names */ @OptIn(ImplicitReflectionSerializer::class) @@ -53,7 +54,9 @@ open class TypeaheadRemoteInput<T : Any>( function: suspend T.(String?, String?) -> List<String>, private val stateFunction: (() -> String)? = null, items: Int? = 8, minLength: Int = 1, delay: Int = 0, - type: TextInputType = TextInputType.TEXT, value: String? = null, classes: Set<String> = setOf() + type: TextInputType = TextInputType.TEXT, value: String? = null, + taAjaxOptions: TaAjaxOptions? = null, + classes: Set<String> = setOf() ) : TypeaheadInput(null, null, items, minLength, delay, type, value, classes) { private val kvUrlPrefix = window["kv_remote_url_prefix"] @@ -63,8 +66,9 @@ open class TypeaheadRemoteInput<T : Any>( val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - this.ajaxOptions = TaAjaxOptions( - urlPrefix + url.drop(1), + val tempAjaxOptions = taAjaxOptions ?: TaAjaxOptions() + this.ajaxOptions = tempAjaxOptions.copy( + url = urlPrefix + url.drop(1), preprocessQuery = { query -> val state = stateFunction?.invoke() JSON.plain.stringify(JsonRpcRequest(0, url, listOf(query, state))) @@ -88,13 +92,23 @@ fun <T : Any> Container.typeaheadRemoteInput( stateFunction: (() -> String)? = null, items: Int? = 8, minLength: Int = 1, delay: Int = 0, type: TextInputType = TextInputType.TEXT, value: String? = null, + taAjaxOptions: TaAjaxOptions? = null, classes: Set<String>? = null, className: String? = null, init: (TypeaheadRemoteInput<T>.() -> Unit)? = null ): TypeaheadRemoteInput<T> { val typeaheadRemoteInput = TypeaheadRemoteInput( - serviceManager, function, stateFunction, items, minLength, delay, type, value, classes ?: className.set + serviceManager, + function, + stateFunction, + items, + minLength, + delay, + type, + value, + taAjaxOptions, + classes ?: className.set ).apply { init?.invoke(this) } diff --git a/kvision-modules/kvision-bootstrap-typeahead/src/main/kotlin/pl/treksoft/kvision/form/text/TaAjaxOptions.kt b/kvision-modules/kvision-bootstrap-typeahead/src/main/kotlin/pl/treksoft/kvision/form/text/TaAjaxOptions.kt index 29dc9dc9..5f45ac91 100644 --- a/kvision-modules/kvision-bootstrap-typeahead/src/main/kotlin/pl/treksoft/kvision/form/text/TaAjaxOptions.kt +++ b/kvision-modules/kvision-bootstrap-typeahead/src/main/kotlin/pl/treksoft/kvision/form/text/TaAjaxOptions.kt @@ -21,6 +21,7 @@ */ package pl.treksoft.kvision.form.text +import pl.treksoft.jquery.JQueryAjaxSettings import pl.treksoft.jquery.JQueryXHR /** @@ -59,10 +60,10 @@ enum class DataType(internal val type: String) { * [JQuery ajax.processData](http://api.jquery.com/jquery.ajax/#jQuery-ajax-settings) option */ data class TaAjaxOptions( - val url: String, + val url: String? = null, val preprocessQuery: ((String) -> dynamic)? = null, val preprocessData: ((dynamic) -> Array<String>)? = null, - val beforeSend: ((JQueryXHR, dynamic) -> dynamic)? = null, + val beforeSend: ((JQueryXHR, JQueryAjaxSettings) -> dynamic)? = null, val httpType: HttpType = HttpType.GET, val dataType: DataType = DataType.JSON, val processData: Boolean = true diff --git a/kvision-modules/kvision-bootstrap-typeahead/src/main/kotlin/pl/treksoft/kvision/form/text/TypeaheadInput.kt b/kvision-modules/kvision-bootstrap-typeahead/src/main/kotlin/pl/treksoft/kvision/form/text/TypeaheadInput.kt index 104c7f8d..46bf4b62 100644 --- a/kvision-modules/kvision-bootstrap-typeahead/src/main/kotlin/pl/treksoft/kvision/form/text/TypeaheadInput.kt +++ b/kvision-modules/kvision-bootstrap-typeahead/src/main/kotlin/pl/treksoft/kvision/form/text/TypeaheadInput.kt @@ -119,7 +119,7 @@ open class TypeaheadInput( val data = ajaxOptions.preprocessQuery?.invoke(query) ?: obj { this.query = query } - jQuery.ajax(ajaxOptions.url, obj { + jQuery.ajax(ajaxOptions.url!!, obj { this.contentType = "application/json" this.data = data this.method = ajaxOptions.httpType.type diff --git a/kvision-modules/kvision-common-remote/src/jsMain/kotlin/pl/treksoft/kvision/remote/CallAgent.kt b/kvision-modules/kvision-common-remote/src/jsMain/kotlin/pl/treksoft/kvision/remote/CallAgent.kt index 3d865f04..e357c024 100644 --- a/kvision-modules/kvision-common-remote/src/jsMain/kotlin/pl/treksoft/kvision/remote/CallAgent.kt +++ b/kvision-modules/kvision-common-remote/src/jsMain/kotlin/pl/treksoft/kvision/remote/CallAgent.kt @@ -57,7 +57,8 @@ open class CallAgent { fun jsonRpcCall( url: String, data: List<String?> = listOf(), - method: HttpMethod = HttpMethod.POST + method: HttpMethod = HttpMethod.POST, + beforeSend: ((JQueryXHR, JQueryAjaxSettings) -> Boolean)? = null ): Promise<String> { val jsonRpcRequest = JsonRpcRequest(counter++, url, data) val jsonData = if (method == HttpMethod.GET) { @@ -103,6 +104,7 @@ open class CallAgent { this.xhrFields = obj { this.withCredentials = true } + this.beforeSend = beforeSend }) } } diff --git a/kvision-modules/kvision-common-remote/src/jsMain/kotlin/pl/treksoft/kvision/remote/KVRemoteAgent.kt b/kvision-modules/kvision-common-remote/src/jsMain/kotlin/pl/treksoft/kvision/remote/KVRemoteAgent.kt index 8836c7f1..fe655b87 100644 --- a/kvision-modules/kvision-common-remote/src/jsMain/kotlin/pl/treksoft/kvision/remote/KVRemoteAgent.kt +++ b/kvision-modules/kvision-common-remote/src/jsMain/kotlin/pl/treksoft/kvision/remote/KVRemoteAgent.kt @@ -34,6 +34,8 @@ import kotlinx.serialization.builtins.list import kotlinx.serialization.serializer import kotlinx.serialization.stringify import org.w3c.dom.get +import pl.treksoft.jquery.JQueryAjaxSettings +import pl.treksoft.jquery.JQueryXHR import kotlin.browser.window import kotlin.reflect.KClass @@ -42,8 +44,10 @@ import kotlin.reflect.KClass */ @Suppress("LargeClass", "TooManyFunctions") @OptIn(ImplicitReflectionSerializer::class, ExperimentalCoroutinesApi::class) -open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : - RemoteAgent { +open class KVRemoteAgent<T : Any>( + val serviceManager: KVServiceMgr<T>, + val beforeSend: ((JQueryXHR, JQueryAjaxSettings) -> Boolean)? = null +) : RemoteAgent { val callAgent = CallAgent() @@ -54,7 +58,7 @@ open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - return callAgent.jsonRpcCall(url, method = method).then { + return callAgent.jsonRpcCall(url, method = method, beforeSend = beforeSend).then { try { @Suppress("UNCHECKED_CAST") deserialize<RET>(it, RET::class.js.name) @@ -78,7 +82,7 @@ open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - return callAgent.jsonRpcCall(url, method = method).then { + return callAgent.jsonRpcCall(url, method = method, beforeSend = beforeSend).then { try { deserializeList<RET>(it, RET::class.js.name) } catch (t: NotStandardTypeException) { @@ -102,7 +106,7 @@ open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - return callAgent.jsonRpcCall(url, listOf(data), method).then { + return callAgent.jsonRpcCall(url, listOf(data), method, beforeSend).then { try { @Suppress("UNCHECKED_CAST") deserialize<RET>(it, RET::class.js.name) @@ -127,7 +131,7 @@ open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - return callAgent.jsonRpcCall(url, listOf(data), method).then { + return callAgent.jsonRpcCall(url, listOf(data), method, beforeSend).then { try { deserializeList<RET>(it, RET::class.js.name) } catch (t: NotStandardTypeException) { @@ -152,7 +156,7 @@ open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - return callAgent.jsonRpcCall(url, listOf(data1, data2), method).then { + return callAgent.jsonRpcCall(url, listOf(data1, data2), method, beforeSend).then { try { @Suppress("UNCHECKED_CAST") deserialize<RET>(it, RET::class.js.name) @@ -178,7 +182,7 @@ open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - return callAgent.jsonRpcCall(url, listOf(data1, data2), method).then { + return callAgent.jsonRpcCall(url, listOf(data1, data2), method, beforeSend).then { try { deserializeList<RET>(it, RET::class.js.name) } catch (t: NotStandardTypeException) { @@ -204,7 +208,7 @@ open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - return callAgent.jsonRpcCall(url, listOf(data1, data2, data3), method).then { + return callAgent.jsonRpcCall(url, listOf(data1, data2, data3), method, beforeSend).then { try { @Suppress("UNCHECKED_CAST") deserialize<RET>(it, RET::class.js.name) @@ -231,7 +235,7 @@ open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - return callAgent.jsonRpcCall(url, listOf(data1, data2, data3), method).then { + return callAgent.jsonRpcCall(url, listOf(data1, data2, data3), method, beforeSend).then { try { deserializeList<RET>(it, RET::class.js.name) } catch (t: NotStandardTypeException) { @@ -258,7 +262,7 @@ open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4), method).then { + return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4), method, beforeSend).then { try { @Suppress("UNCHECKED_CAST") deserialize<RET>(it, RET::class.js.name) @@ -290,7 +294,7 @@ open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4), method).then { + return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4), method, beforeSend).then { try { deserializeList<RET>(it, RET::class.js.name) } catch (t: NotStandardTypeException) { @@ -325,7 +329,7 @@ open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4, data5), method).then { + return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4, data5), method, beforeSend).then { try { @Suppress("UNCHECKED_CAST") deserialize<RET>(it, RET::class.js.name) @@ -361,7 +365,7 @@ open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4, data5), method).then { + return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4, data5), method, beforeSend).then { try { deserializeList<RET>(it, RET::class.js.name) } catch (t: NotStandardTypeException) { @@ -398,7 +402,7 @@ open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4, data5, data6), method).then { + return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4, data5, data6), method, beforeSend).then { try { @Suppress("UNCHECKED_CAST") deserialize<RET>(it, RET::class.js.name) @@ -436,7 +440,7 @@ open class KVRemoteAgent<T : Any>(val serviceManager: KVServiceMgr<T>) : val (url, method) = serviceManager.getCalls()[function.toString().replace("\\s".toRegex(), "")] ?: throw IllegalStateException("Function not specified!") - return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4, data5, data6), method).then { + return callAgent.jsonRpcCall(url, listOf(data1, data2, data3, data4, data5, data6), method, beforeSend).then { try { deserializeList<RET>(it, RET::class.js.name) } catch (t: NotStandardTypeException) { diff --git a/kvision-modules/kvision-tabulator-remote/src/main/kotlin/pl/treksoft/kvision/tabulator/TabulatorRemote.kt b/kvision-modules/kvision-tabulator-remote/src/main/kotlin/pl/treksoft/kvision/tabulator/TabulatorRemote.kt index e61ced55..21bfc5d4 100644 --- a/kvision-modules/kvision-tabulator-remote/src/main/kotlin/pl/treksoft/kvision/tabulator/TabulatorRemote.kt +++ b/kvision-modules/kvision-tabulator-remote/src/main/kotlin/pl/treksoft/kvision/tabulator/TabulatorRemote.kt @@ -24,6 +24,8 @@ package pl.treksoft.kvision.tabulator import kotlinx.serialization.ImplicitReflectionSerializer import kotlinx.serialization.stringify import org.w3c.dom.get +import pl.treksoft.jquery.JQueryAjaxSettings +import pl.treksoft.jquery.JQueryXHR import pl.treksoft.kvision.core.Container import pl.treksoft.kvision.remote.CallAgent import pl.treksoft.kvision.remote.HttpMethod @@ -69,6 +71,10 @@ open class TabulatorRemote<T : Any, E : Any>( ?: throw IllegalStateException("Function not specified!") val callAgent = CallAgent() + + @Suppress("UnsafeCastFromDynamic") + val beforeSend: ((JQueryXHR, JQueryAjaxSettings) -> Boolean)? = options.ajaxConfig.beforeSend + options.ajaxConfig.beforeSend = undefined options.ajaxURL = urlPrefix + url.drop(1) options.ajaxRequestFunc = { _, _, params -> val page = params.page @@ -91,15 +97,16 @@ open class TabulatorRemote<T : Any, E : Any>( @Suppress("UnsafeCastFromDynamic") val data = JSON.plain.stringify(JsonRpcRequest(0, url, listOf(page, size, filters, sorters, state))) - callAgent.remoteCall(url, data, method = HttpMethod.valueOf(method.name)).then { r: dynamic -> - val result = kotlin.js.JSON.parse<dynamic>(r.result as String) - @Suppress("UnsafeCastFromDynamic") - if (page != null) { - result - } else { - result.data + callAgent.remoteCall(url, data, method = HttpMethod.valueOf(method.name), beforeSend = beforeSend) + .then { r: dynamic -> + val result = kotlin.js.JSON.parse<dynamic>(r.result as String) + @Suppress("UnsafeCastFromDynamic") + if (page != null) { + result + } else { + result.data + } } - } } } } diff --git a/kvision-tools/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/KVProcessor.kt b/kvision-tools/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/KVProcessor.kt index 5d5cc514..6a0a0130 100644 --- a/kvision-tools/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/KVProcessor.kt +++ b/kvision-tools/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/KVProcessor.kt @@ -158,12 +158,14 @@ class KVProcessor : AbstractProcessor() { appendln("//") appendln("package $packageName") appendln() + appendln("import pl.treksoft.jquery.JQueryAjaxSettings") + appendln("import pl.treksoft.jquery.JQueryXHR") appendln("import pl.treksoft.kvision.remote.KVRemoteAgent") getTypes(cl.methods()).sorted().forEach { appendln("import $it") } appendln() - appendln("actual class $baseName : $iName, KVRemoteAgent<$baseName>(${baseName}Manager) {") + appendln("actual class $baseName(beforeSend: ((JQueryXHR, JQueryAjaxSettings) -> Boolean)? = null) : $iName, KVRemoteAgent<$baseName>(${baseName}Manager, beforeSend) {") cl.methods().forEach { val name = it.name val params = it.allParameters.drop(1) |