Skip to content
This repository was archived by the owner on Aug 10, 2024. It is now read-only.

Commit 7a7e9ba

Browse files
authored
Merge pull request #278 from Derek52/Bugfix-StringDiff
Bugfix string diff
2 parents d482697 + 4b38420 commit 7a7e9ba

File tree

5 files changed

+93
-61
lines changed

5 files changed

+93
-61
lines changed

build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ ext {
2525
}
2626

2727
group 'com.github.kwebio'
28-
version '0.11.3'
28+
version '0.11.4'
2929

3030
repositories {
3131
mavenCentral()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package kweb.demos.testPages
2+
3+
import kweb.*
4+
import kweb.plugins.fomanticUI.fomantic
5+
import kweb.plugins.fomanticUI.fomanticUIPlugin
6+
import kweb.state.KVar
7+
import kweb.state.render
8+
import mu.KotlinLogging
9+
10+
11+
fun main() {
12+
DiffTestPage()
13+
}
14+
15+
class DiffTestPage {
16+
17+
private val logger = KotlinLogging.logger {}
18+
19+
val plugins = listOf(fomanticUIPlugin)
20+
val server: Kweb
21+
22+
var username = KVar("Initial")
23+
init {
24+
25+
/** Create a Kweb instance, and configure it to use the Fomantic
26+
* UI framework. Build a simple to-do list app listening on
27+
* http://localhost:7659/
28+
* */
29+
server = Kweb(port = 7659, debug = true, plugins = plugins, buildPage = {
30+
31+
doc.head {
32+
// Not required, but recommended by HTML spec
33+
meta(name = "Description", content = "A page to test server updating")
34+
}
35+
36+
doc.body {
37+
/** Kweb allows you to modularize your code however suits your needs
38+
best. Here I use an extension function defined elsewhere to
39+
draw some util outer page DOM elements */
40+
/** Kweb allows you to modularize your code however suits your needs
41+
best. Here I use an extension function defined elsewhere to
42+
draw some util outer page DOM elements */
43+
div(fomantic.ui.text.center.aligned.container) {
44+
val usernameInput = input(initialValue = "Initial")
45+
username = usernameInput.value
46+
println("initialValue: ${usernameInput.value.value}")
47+
usernameInput.setAttribute("class", "fomantic ui input")
48+
49+
render(username) {
50+
p().text("username: $it")
51+
}
52+
}
53+
54+
}
55+
})
56+
}
57+
}

src/main/kotlin/kweb/prelude.kt

+16-12
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,8 @@ fun ElementCreator<Element>.meta(
325325
}
326326
}
327327

328-
open class InputElement(override val element: Element) : ValueElement(element) {
328+
open class InputElement(override val element: Element, initialValue: String? = null) :
329+
ValueElement(element, initialValue = initialValue) {
329330
fun select() = element.callJsFunction("document.getElementById({}).select();", id.json)
330331

331332
fun setSelectionRange(start: Int, end: Int) = element.callJsFunction(
@@ -336,7 +337,8 @@ open class InputElement(override val element: Element) : ValueElement(element) {
336337
id.json, ro.json)
337338

338339
fun checked(initialValue : Boolean = false) : KVar<Boolean> {
339-
val kv = bind(accessor = { "document.getElementById(\"$it\").checked" }, updateOnEvent = "change", initialValue = JsonPrimitive(initialValue))
340+
val kv = bind(accessor = { "document.getElementById(\"$it\").checked" }, updateOnEvent = "change",
341+
initialValue = JsonPrimitive(initialValue))
340342
return kv.map(object : ReversibleFunction<JsonElement, Boolean>("") {
341343
override fun invoke(from: JsonElement) = from.jsonPrimitive.boolean
342344

@@ -365,7 +367,7 @@ fun ElementCreator<Element>.input(
365367
.set("value", JsonPrimitive(initialValue))
366368
.set("placeholder", JsonPrimitive(placeholder))
367369
.set("size", JsonPrimitive(size))
368-
)
370+
), initialValue = initialValue
369371
).also {
370372
if (new != null) new(ElementCreator(parent = it, insertBefore = null))
371373
}
@@ -390,7 +392,8 @@ fun ElementCreator<Element>.textArea(
390392
/**
391393
* [<SELECT>](https://www.w3schools.com/tags/tag_select.asp)
392394
*/
393-
class SelectElement(parent: Element) : ValueElement(parent, kvarUpdateEvent = "change")
395+
class SelectElement(parent: Element, initialValue: String? = null) :
396+
ValueElement(parent, kvarUpdateEvent = "change", initialValue = initialValue)
394397

395398
/**
396399
* [<SELECT>](https://www.w3schools.com/tags/tag_select.asp)
@@ -430,7 +433,7 @@ private fun select_sample() {
430433
/**
431434
* https://www.w3schools.com/tags/tag_textarea.asp
432435
*/
433-
open class TextAreaElement(parent: Element) : ValueElement(parent) {
436+
open class TextAreaElement(parent: Element, initialValue: String? = null) : ValueElement(parent, initialValue = initialValue) {
434437
//TODO ValueElement already provides a way to get the value of an element. I'm not sure why this function is here.
435438
//But, something needs to be done with it.
436439
override val read get() = TextAreaElementReader(this)
@@ -476,7 +479,8 @@ fun ElementCreator<Element>.label(
476479
*
477480
* @param kvarUpdateEvent The [value] of this element will update on this event, defaults to [input](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/input_event)
478481
*/
479-
abstract class ValueElement(open val element: Element, val kvarUpdateEvent: String = "input") : Element(element) {
482+
abstract class ValueElement(open val element: Element, val kvarUpdateEvent: String = "input",
483+
val initialValue: String? = null) : Element(element) {
480484
val valueJsExpression : String by lazy { "document.getElementById(\"$id\").value" }
481485

482486
suspend fun getValue():String = element.
@@ -514,14 +518,14 @@ abstract class ValueElement(open val element: Element, val kvarUpdateEvent: Stri
514518
get() {
515519
synchronized(this) {
516520
if (_valueKvar == null) {
517-
value = KVar("")
521+
value = KVar(initialValue ?: "")
518522
}
519523
}
520524
return _valueKvar!!
521525
}
522526
set(v) {
523527
if (_valueKvar != null) error("`value` may only be set once, and cannot be set after it has been retrieved")
524-
setValue(v, updateOn = kvarUpdateEvent)
528+
updateKVar(v, updateOn = kvarUpdateEvent)
525529
_valueKvar = v
526530
}
527531

@@ -534,7 +538,8 @@ abstract class ValueElement(open val element: Element, val kvarUpdateEvent: Stri
534538
data class DiffData(val prefixEndIndex: Int, val postfixOffset: Int, val diffString: String)
535539

536540
private fun applyDiff(oldString: String, diffData: DiffData) : String {
537-
return when {
541+
542+
val newString = when {
538543
diffData.postfixOffset == -1 -> {//these 2 edge cases prevent the prefix or the postfix from being
539544
// repeated when you append text to the beginning of the text or the end of the text
540545
oldString.substring(0, diffData.prefixEndIndex) + diffData.diffString
@@ -547,11 +552,10 @@ abstract class ValueElement(open val element: Element, val kvarUpdateEvent: Stri
547552
oldString.substring(oldString.length - diffData.postfixOffset)
548553
}
549554
}
555+
return newString
550556
}
551557

552-
fun setValue(toBind: KVar<String>, updateOn: String = "input") {
553-
setValue(toBind as KVal<String>)
554-
558+
private fun updateKVar(toBind: KVar<String>, updateOn: String = "input") {
555559
on(
556560
//language=JavaScript
557561
retrieveJs = "get_diff_changes(document.getElementById(\"${element.id}\"))")

src/main/resources/kweb/kweb_bootstrap.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -241,12 +241,12 @@ function get_diff_changes(htmlInputElement) {
241241
let shorterStringLength = (oldString.length > newString.length) ? newString.length : oldString.length;
242242

243243
for (let i = 0; i < shorterStringLength; i++) {
244-
if (oldString.charAt(i) == newString.charAt(i)) {
244+
if (oldString.charAt(i) === newString.charAt(i)) {
245245
commonPrefixEnd = i+1;
246246
} else break;
247247
}
248248
for(let offset = 0; offset < shorterStringLength - commonPrefixEnd; offset++) {
249-
if (oldString.charAt(oldStringLastIndex - offset) == newString.charAt(newStringLastIndex - offset)) {
249+
if (oldString.charAt(oldStringLastIndex - offset) === newString.charAt(newStringLastIndex - offset)) {
250250
commonPostfixOffset = offset+1;
251251
} else break;
252252
}
+17-46
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
package kweb
2-
/*
32
import io.github.bonigarcia.seljup.Arguments
43
import io.github.bonigarcia.seljup.SeleniumExtension
54
import io.kotlintest.shouldBe
@@ -20,7 +19,6 @@ import org.openqa.selenium.support.ThreadGuard
2019

2120
@ExtendWith(SeleniumExtension::class)
2221
class StringDiffTest(@Arguments("--headless") private var driver: WebDriver) {
23-
//class StringDiffTest(private var driver: WebDriver) {
2422

2523
init {
2624
//ThreadGuard.protect ensures that the webdriver can only be called by the thread that created it
@@ -48,61 +46,40 @@ class StringDiffTest(@Arguments("--headless") private var driver: WebDriver) {
4846
fun appendTextToBeginning() {
4947
driver.get("http://localhost:7660/")
5048
val inputField = driver.findElement<WebElement>(By.tagName("input"))
51-
inputField.sendKeys(Keys.HOME)
52-
inputField.sendKeys("Super ")
53-
inputField.sendKeys(Keys.ENTER)
54-
stringDiffTestApp.getValue().shouldBe("Super Lazy Brown Fox")
49+
inputField.sendKeys("${Keys.HOME}Super ")
50+
inputField.getAttribute("value").shouldBe("Super Lazy Brown Fox")
5551
}
5652

5753
@Test
5854
fun appendTextToMiddle() {
5955
driver.get("http://localhost:7660/")
6056
val inputField = driver.findElement<WebElement>(By.tagName("input"))
61-
inputField.sendKeys(Keys.HOME)
62-
for (i in 0 until 5) {
63-
inputField.sendKeys(Keys.ARROW_RIGHT)
64-
Thread.sleep(200);
65-
}
66-
inputField.sendKeys("Reddish ")
67-
inputField.sendKeys(Keys.ENTER)
68-
stringDiffTestApp.getValue().shouldBe("Lazy Reddish Brown Fox")
57+
inputField.sendKeys("${Keys.LEFT}${Keys.LEFT}1234")
58+
inputField.getAttribute("value").shouldBe("Lazy Brown F1234ox")
6959
}
7060

7161
@Test
7262
fun appendTextToEnd() {
7363
driver.get("http://localhost:7660/")
7464
val inputField = driver.findElement<WebElement>(By.tagName("input"))
75-
inputField.sendKeys(Keys.END)
7665
inputField.sendKeys(" Jumped")
77-
inputField.sendKeys(Keys.ENTER)
78-
stringDiffTestApp.getValue().shouldBe("Lazy Brown Fox Jumped")
66+
inputField.getAttribute("value").shouldBe("Lazy Brown Fox Jumped")
7967
}
8068

8169
@Test
8270
fun removeTextFromBeginning() {
8371
driver.get("http://localhost:7660/")
8472
val inputField = driver.findElement<WebElement>(By.tagName("input"))
85-
inputField.sendKeys(Keys.HOME)
86-
for (i in 0 until 5) {
87-
inputField.sendKeys(Keys.DELETE)
88-
}
89-
inputField.sendKeys(Keys.ENTER)
90-
stringDiffTestApp.getValue().shouldBe("Brown Fox")
73+
inputField.sendKeys("${Keys.HOME}${Keys.DELETE}${Keys.DELETE}${Keys.DELETE}${Keys.DELETE}${Keys.DELETE}")
74+
inputField.getAttribute("value").shouldBe("Brown Fox")
9175
}
9276

9377
@Test
9478
fun removeTextFromMiddle() {
9579
driver.get("http://localhost:7660/")
9680
val inputField = driver.findElement<WebElement>(By.tagName("input"))
97-
inputField.sendKeys(Keys.HOME)
98-
for (i in 0 until 5) {
99-
inputField.sendKeys(Keys.ARROW_RIGHT)
100-
}
101-
for (i in 0 until 6) {
102-
inputField.sendKeys(Keys.DELETE)
103-
}
104-
inputField.sendKeys(Keys.ENTER)
105-
stringDiffTestApp.getValue().shouldBe("Lazy Fox")
81+
inputField.sendKeys("${Keys.LEFT}${Keys.BACK_SPACE}${Keys.BACK_SPACE}")
82+
inputField.getAttribute("value").shouldBe("Lazy Brown x")
10683
}
10784

10885
@Test
@@ -114,26 +91,20 @@ class StringDiffTest(@Arguments("--headless") private var driver: WebDriver) {
11491
inputField.sendKeys(Keys.BACK_SPACE)
11592
}
11693
inputField.sendKeys(Keys.ENTER)
117-
stringDiffTestApp.getValue().shouldBe("Lazy Brown")
94+
inputField.getAttribute("value").shouldBe("Lazy Brown")
11895
}
11996

12097
}
12198

12299
class StringDiffTestApp {
123-
private lateinit var input: InputElement
124-
125-
val server: Kweb = Kweb(port= 7660) {
126-
doc.body.new {
127-
val inputKvar = KVar(false)
128-
render(inputKvar) {
129-
input = input(type = InputType.text, initialValue = "Lazy Brown Fox")
130-
}
131-
}
132-
}
100+
var inputString = KVar("")
133101

134-
suspend fun getValue(): String {
135-
return input.getValue()
102+
val server: Kweb = Kweb(port= 7660){
103+
doc.body {
104+
val input = input(initialValue = "Lazy Brown Fox")
105+
inputString = input.value
106+
}
136107
}
137108
}
138-
*/
109+
139110

0 commit comments

Comments
 (0)