All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dukescript.api.kt.Models.kt Maven / Gradle / Ivy

@file:JvmName("Models")

package com.dukescript.api.kt

import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
import net.java.html.json.Models
import com.dukescript.api.kt.impl.*

/** Defines an observable property.
* @param initialValue inital value of the property
* @param onChange code to invoke whenever the value of the property changes
* @sample com.dukescript.api.kt.test.KModel.message
* @sample com.dukescript.api.kt.test.KModel.rotating
*/
inline fun  Model.Provider.observable(initialValue: T, noinline onChange: (() -> Unit)? = null): Model.Writable {
    return this.objs.observable(T::class.java, initialValue, onChange);

/*-
 * #%L
 * %%
 * Copyright (C) 2017 Dukehoff GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
}

/** Defines an observable array property.
* @param items optional elements to fill the array with
*/
inline fun  Model.Provider.observableList(vararg items: T, noinline onChange: (() -> Unit)? = null): Model.Readable> {
    var arr : Array = items
    return this.objs.observableList(T::class.java, arr, onChange);
}

/** Defines derived, computed property. Its value depends
* on other properties and is recomputed when those dependant
* properties change.
* @sample com.dukescript.api.kt.test.KModel.message
* @sample com.dukescript.api.kt.test.KModel.words
*
*/
fun  Model.Provider.computed(fn : () -> T): Model.Readable {
    return Model.Readable { js: Model.Provider, prop : KProperty<*> ->
        ProtoType.registerPrototype(js).addProp(js.objs, false, null, prop, fn = fn as (() -> Any))
        ComputedP as ReadOnlyProperty
    }
}

/** Creates a handler to react on action happening
* in the user interface.
* @sample com.dukescript.api.kt.test.KModel.rotating
* @sample com.dukescript.api.kt.test.KModel.turnAnimationOn
*/
fun Model.Provider.action(f: () -> Unit): Model.Readable {
    val fn: (Any?) -> Unit = { _ -> f() }
    return Model.Readable { js, prop ->
        ProtoType.registerPrototype(js).addFn(js.objs, prop, fn)
        ActionProperty(Action(Token))
    }
}

/** Creates a handler to react on action happening
* in the user interface and provide identification of
* the interface element that triggered the action.
*
* @sample com.dukescript.api.kt.test.KModel.message
* @sample com.dukescript.api.kt.test.KModel.selectWord
*
* @param f one argument function to handle the operation
*/
inline fun  Model.Provider.actionWithData(noinline f: (T?) -> Unit): Model.Readable {
    return this.actionWithData(T::class.java, f)
}

/** Creates a handler to react on action happening
* in the user interface and provide identification of
* the interface element that triggered the action.
* @param type the type of the interface element the function expects
* @param f one argument function to handle the operation
*/
fun  Model.Provider.actionWithData(type: Class, f: (T?) -> Unit): Model.Readable {
    val fn: (Any?) -> Unit = { raw ->
        val value: T? = (this.objs as ModelImpl).extractValue(type, raw)
        f(value)
    }
    return Model.Readable { js, prop ->
        ProtoType.registerPrototype(js).addFn(js.objs, prop, fn)
        ActionProperty(Action(Token))
    }
}

/** Represents an operation callable from the user interface.
* @sample com.dukescript.api.kt.test.KModel.message
* @sample com.dukescript.api.kt.test.KModel.showScreenSize
* @sample com.dukescript.api.kt.test.KModel.selectWord
*/
final class Action internal constructor (token : Token) {
}

private class ActionProperty constructor (val action : Action) : ReadOnlyProperty  {
    override fun getValue(thisRef: Model.Provider, property: KProperty<*>): Action = action
}

/** Initializes an asynchronous REST connection and calls back when a result
 * is obtained.
 *
 * @sample com.dukescript.api.kt.test.KModel.loadFromJSON
 */
inline fun  Model.Provider.loadJSON(
    baseUrl: String, noinline onSuccess: (List) -> Unit,
    noinline onError: ((kotlin.Throwable) -> Unit)? = null,
    method : String = "GET", data : Any? = null,
    headers : Map? = null, afterUrl: String? = null
) {
    objs.loadJSON(T::class.java, baseUrl, onSuccess, onError, method, data, headers, afterUrl)
}

/** Instantiates new [Model] associated with provided `javaObj` and
 * holding all the necessary data for communication with JavaScript.
 * If you have an object that you want to mirror in the JavaScript side,
 * create a class and implement [Model.Provider] - it has just a single
 * read only property - implement it by instantiating the [Model]
 * instance with a pointer to your object.
 *
 * @sample com.dukescript.api.kt.test.TestData
 */
public fun Model(thiz: Model.Provider): Model = ModelImpl(thiz)

/** Holds internal data associated with provided kotlin object. Create using
 * the `Model` factory method:
 *
 * @sample com.dukescript.api.kt.test.TestData
 */
public open class Model internal constructor(token : Token) {
    /** Helper method. Called from [com.dukescript.api.kt.observable].
     */
    public fun  observable(type: Class, initialValue: T, onChange: (() -> Unit)?): Model.Writable {
        return Model.Writable { js: Model.Provider, prop : KProperty<*> ->
            ProtoType.registerPrototype(js).addProp(js.objs, false, type, prop, init = initialValue, change = onChange)
            ObservableP as ReadWriteProperty
        }
    }

    /** Helper method. Called from [com.dukescript.api.kt.observableList].
     */
    public fun  observableList(type: Class, items: Array, onChange: (() -> Unit)?): Model.Readable> {
        return Model.Readable> { js: Model.Provider, prop : KProperty<*> ->
            val index = ProtoType.registerPrototype(js).addProp(js.objs, true, type, prop, change = onChange)
            ListP(js.objs, prop.name, index, items)
        }
    }

    /** Helper method that is called by [com.dukescript.api.kt.loadJSON].
     */
    fun  loadJSON(
        clazz: Class,
        baseUrl: String, onSuccess: (List) -> Unit,
        onError: ((kotlin.Throwable) -> Unit)?,
        method : String, data : Any?,
        headers : Map?, afterUrl: String?
    ) {
        val headerText = if (headers != null) {
            var t = ""
            for (entry in headers.entries) {
                t += "${entry.key}: ${entry.value}"
            }
            t
        } else {
            ""
        }
        var impl = this as com.dukescript.api.kt.impl.ModelImpl;
        impl.proto.loadJSONWithHeaders(0, headerText, baseUrl, afterUrl, method, data, clazz, onSuccess, onError)
    }

    /** Interface to implement by objects that willing to expose its properties
     * (e.g. [com.dukescript.api.kt.observable], 
     * [com.dukescript.api.kt.observableList] or [com.dukescript.api.kt.computed])
     * as [Model]s. Trivial implementation can look like this:
     *
     * @sample com.dukescript.api.kt.test.TestData
     */
    public interface Provider {
        /** The property to fill with [Model] instance associated your
         * object.
         */
        val objs: Model;
    }

    /** Delegate for creating read-write property.
    */
    public final class Writable constructor (
        private val factory : (Model.Provider, KProperty<*>) -> ReadWriteProperty
    ) {
        /** Creates read/write property.
         */
        operator fun provideDelegate(
            thisRef: Model.Provider, prop: KProperty<*>
        ): ReadWriteProperty {
            return factory(thisRef, prop)
        }
    }

    /** Delegate for creating read-only property.
    */
    public final class Readable internal constructor (
        private val factory : (Model.Provider, KProperty<*>) -> ReadOnlyProperty
    ) {
        /** Creates read only property.
         */
        operator fun provideDelegate(
                thisRef: Model.Provider,
                prop: KProperty<*>
        ): ReadOnlyProperty {
            return factory(thisRef, prop)
        }
    }
}

/** Activates given [Model] in the current context.
 * @param model class with [observable] or [computed] properties and [actions][action]
 * @param id optional id of a UI element to apply the model to
 */
public fun applyBindings(model : Model.Provider, id : String? = null) {
    Models.applyBindings(model, id)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy