Commit 62b7ffd3 authored by Arturo Mejia's avatar Arturo Mejia
Browse files

Closes #1472: Adding support for JavaScript confirm dialogs.

parent 991938f5
......@@ -289,10 +289,51 @@ internal class GeckoPromptDelegate(private val geckoEngineSession: GeckoEngineSe
override fun onButtonPrompt(
session: GeckoSession,
title: String?,
msg: String?,
btnMsg: Array<out String>?,
message: String?,
buttonTitles: Array<out String?>?,
callback: ButtonCallback
) = Unit
) {
val hasShownManyDialogs = callback.hasCheckbox()
val positiveButtonTitle = buttonTitles?.get(GeckoSession.PromptDelegate.BUTTON_TYPE_POSITIVE) ?: ""
val negativeButtonTitle = buttonTitles?.get(GeckoSession.PromptDelegate.BUTTON_TYPE_NEGATIVE) ?: ""
val neutralButtonTitle = buttonTitles?.get(GeckoSession.PromptDelegate.BUTTON_TYPE_NEUTRAL) ?: ""
val onConfirmPositiveButton: (Boolean) -> Unit = { showMoreDialogs ->
callback.checkboxValue = showMoreDialogs
callback.confirm(GeckoSession.PromptDelegate.BUTTON_TYPE_POSITIVE)
}
val onConfirmNegativeButton: (Boolean) -> Unit = { showMoreDialogs ->
callback.checkboxValue = showMoreDialogs
callback.confirm(GeckoSession.PromptDelegate.BUTTON_TYPE_NEGATIVE)
}
val onConfirmNeutralButton: (Boolean) -> Unit = { showMoreDialogs ->
callback.checkboxValue = showMoreDialogs
callback.confirm(GeckoSession.PromptDelegate.BUTTON_TYPE_NEUTRAL)
}
val onDismiss: () -> Unit = {
callback.dismiss()
}
geckoEngineSession.notifyObservers {
onPromptRequest(
PromptRequest.Confirm(
title ?: "",
message ?: "",
hasShownManyDialogs,
positiveButtonTitle,
negativeButtonTitle,
neutralButtonTitle,
onConfirmPositiveButton,
onConfirmNegativeButton,
onConfirmNeutralButton,
onDismiss
)
)
}
}
private fun GeckoChoice.toChoice(): Choice {
val choiceChildren = items?.map { it.toChoice() }?.toTypedArray()
......
......@@ -207,14 +207,6 @@ class GeckoPromptDelegateTest {
assertEquals((alertRequest as PromptRequest.Alert).message, "message")
}
@Test
fun `hitting functions not yet implemented`() {
val mockSession = GeckoEngineSession(Mockito.mock(GeckoRuntime::class.java))
val gecko = GeckoPromptDelegate(mockSession)
gecko.onButtonPrompt(mock(), "", "", null, mock())
gecko.onPopupRequest(mock(), "")
}
@Test
fun `hitting default values`() {
val mockSession = GeckoEngineSession(Mockito.mock(GeckoRuntime::class.java))
......@@ -223,6 +215,7 @@ class GeckoPromptDelegateTest {
gecko.onDateTimePrompt(mock(), null, DATETIME_TYPE_WEEK, null, null, null, mock())
gecko.onDateTimePrompt(mock(), null, DATETIME_TYPE_MONTH, null, null, null, mock())
gecko.onDateTimePrompt(mock(), null, DATETIME_TYPE_TIME, null, "", "", mock())
gecko.onButtonPrompt(mock(), null, null, arrayOf<String?>(null, null, null), mock())
}
@Test
......@@ -918,6 +911,81 @@ class GeckoPromptDelegateTest {
assertTrue(onDenyWasCalled)
}
@Test
fun `onButtonPrompt must provide a Confirm PromptRequest`() {
val mockSession = GeckoEngineSession(Mockito.mock(GeckoRuntime::class.java))
var request: PromptRequest.Confirm? = null
var onPositiveButtonWasCalled = false
var onNegativeButtonWasCalled = false
var onNeutralButtonWasCalled = false
var dismissWasCalled = false
var setCheckboxValueWasCalled = false
val promptDelegate = GeckoPromptDelegate(mockSession)
mockSession.register(object : EngineSession.Observer {
override fun onPromptRequest(promptRequest: PromptRequest) {
request = promptRequest as PromptRequest.Confirm
}
})
val callback = object : GeckoSession.PromptDelegate.ButtonCallback {
override fun confirm(button: Int) {
when (button) {
GeckoSession.PromptDelegate.BUTTON_TYPE_POSITIVE -> onPositiveButtonWasCalled = true
GeckoSession.PromptDelegate.BUTTON_TYPE_NEGATIVE -> onNegativeButtonWasCalled = true
GeckoSession.PromptDelegate.BUTTON_TYPE_NEUTRAL -> onNeutralButtonWasCalled = true
}
}
override fun setCheckboxValue(value: Boolean) {
setCheckboxValueWasCalled = true
}
override fun dismiss() {
dismissWasCalled = true
}
override fun getCheckboxValue(): Boolean = false
override fun hasCheckbox(): Boolean = true
override fun getCheckboxMessage(): String = ""
}
promptDelegate.onButtonPrompt(
mock(),
"title",
"message",
arrayOf("positive", "neutral", "negative"),
callback
)
with(request!!) {
assertNotNull(request)
assertEquals(title, "title")
assertEquals(message, "message")
assertEquals(hasShownManyDialogs, true)
assertEquals(positiveButtonTitle, "positive")
assertEquals(negativeButtonTitle, "negative")
assertEquals(neutralButtonTitle, "neutral")
onConfirmPositiveButton(false)
assertTrue(onPositiveButtonWasCalled)
onConfirmNegativeButton(false)
assertTrue(onNegativeButtonWasCalled)
onConfirmNeutralButton(false)
assertTrue(onNeutralButtonWasCalled)
assertTrue(setCheckboxValueWasCalled)
onDismiss()
assertTrue(dismissWasCalled)
}
}
open class DefaultGeckoChoiceCallback : GeckoSession.PromptDelegate.ChoiceCallback {
override fun confirm(items: Array<out GeckoChoice>?) = Unit
override fun dismiss() {}
......
......@@ -41,6 +41,9 @@ import org.mozilla.geckoview.GeckoSession.PromptDelegate.AuthOptions.AUTH_FLAG_P
import org.mozilla.geckoview.GeckoSession.PromptDelegate.AuthOptions.AUTH_LEVEL_NONE
import org.mozilla.geckoview.GeckoSession.PromptDelegate.AuthOptions.AUTH_LEVEL_PW_ENCRYPTED
import org.mozilla.geckoview.GeckoSession.PromptDelegate.AuthOptions.AUTH_LEVEL_SECURE
import org.mozilla.geckoview.GeckoSession.PromptDelegate.BUTTON_TYPE_NEGATIVE
import org.mozilla.geckoview.GeckoSession.PromptDelegate.BUTTON_TYPE_NEUTRAL
import org.mozilla.geckoview.GeckoSession.PromptDelegate.BUTTON_TYPE_POSITIVE
import org.mozilla.geckoview.GeckoSession.PromptDelegate.DATETIME_TYPE_DATE
import org.mozilla.geckoview.GeckoSession.PromptDelegate.DATETIME_TYPE_DATETIME_LOCAL
import org.mozilla.geckoview.GeckoSession.PromptDelegate.DATETIME_TYPE_MONTH
......@@ -289,10 +292,51 @@ internal class GeckoPromptDelegate(private val geckoEngineSession: GeckoEngineSe
override fun onButtonPrompt(
session: GeckoSession,
title: String?,
msg: String?,
btnMsg: Array<out String>?,
message: String?,
buttonTitles: Array<out String?>?,
callback: ButtonCallback
) = Unit
) {
val hasShownManyDialogs = callback.hasCheckbox()
val positiveButtonTitle = buttonTitles?.get(BUTTON_TYPE_POSITIVE) ?: ""
val negativeButtonTitle = buttonTitles?.get(BUTTON_TYPE_NEGATIVE) ?: ""
val neutralButtonTitle = buttonTitles?.get(BUTTON_TYPE_NEUTRAL) ?: ""
val onConfirmPositiveButton: (Boolean) -> Unit = { showMoreDialogs ->
callback.checkboxValue = showMoreDialogs
callback.confirm(BUTTON_TYPE_POSITIVE)
}
val onConfirmNegativeButton: (Boolean) -> Unit = { showMoreDialogs ->
callback.checkboxValue = showMoreDialogs
callback.confirm(BUTTON_TYPE_NEGATIVE)
}
val onConfirmNeutralButton: (Boolean) -> Unit = { showMoreDialogs ->
callback.checkboxValue = showMoreDialogs
callback.confirm(BUTTON_TYPE_NEUTRAL)
}
val onDismiss: () -> Unit = {
callback.dismiss()
}
geckoEngineSession.notifyObservers {
onPromptRequest(
PromptRequest.Confirm(
title ?: "",
message ?: "",
hasShownManyDialogs,
positiveButtonTitle,
negativeButtonTitle,
neutralButtonTitle,
onConfirmPositiveButton,
onConfirmNegativeButton,
onConfirmNeutralButton,
onDismiss
)
)
}
}
private fun GeckoChoice.toChoice(): Choice {
val choiceChildren = items?.map { it.toChoice() }?.toTypedArray()
......
......@@ -39,6 +39,9 @@ import org.junit.Assert
import org.junit.Assert.assertNotNull
import org.mozilla.geckoview.AllowOrDeny
import org.mozilla.geckoview.GeckoResult
import org.mozilla.geckoview.GeckoSession.PromptDelegate.BUTTON_TYPE_NEGATIVE
import org.mozilla.geckoview.GeckoSession.PromptDelegate.BUTTON_TYPE_NEUTRAL
import org.mozilla.geckoview.GeckoSession.PromptDelegate.BUTTON_TYPE_POSITIVE
import org.mozilla.geckoview.GeckoSession.PromptDelegate.TextCallback
import org.mozilla.geckoview.GeckoSession.PromptDelegate.DATETIME_TYPE_DATE
import org.mozilla.geckoview.GeckoSession.PromptDelegate.DATETIME_TYPE_DATETIME_LOCAL
......@@ -207,14 +210,6 @@ class GeckoPromptDelegateTest {
assertEquals((alertRequest as PromptRequest.Alert).message, "message")
}
@Test
fun `hitting functions not yet implemented`() {
val mockSession = GeckoEngineSession(Mockito.mock(GeckoRuntime::class.java))
val gecko = GeckoPromptDelegate(mockSession)
gecko.onButtonPrompt(mock(), "", "", null, mock())
gecko.onPopupRequest(mock(), "")
}
@Test
fun `hitting default values`() {
val mockSession = GeckoEngineSession(Mockito.mock(GeckoRuntime::class.java))
......@@ -223,6 +218,7 @@ class GeckoPromptDelegateTest {
gecko.onDateTimePrompt(mock(), null, DATETIME_TYPE_WEEK, null, null, null, mock())
gecko.onDateTimePrompt(mock(), null, DATETIME_TYPE_MONTH, null, null, null, mock())
gecko.onDateTimePrompt(mock(), null, DATETIME_TYPE_TIME, null, "", "", mock())
gecko.onButtonPrompt(mock(), null, null, arrayOf<String?>(null, null, null), mock())
}
@Test
......@@ -918,6 +914,81 @@ class GeckoPromptDelegateTest {
assertTrue(onDenyWasCalled)
}
@Test
fun `onButtonPrompt must provide a Confirm PromptRequest`() {
val mockSession = GeckoEngineSession(Mockito.mock(GeckoRuntime::class.java))
var request: PromptRequest.Confirm? = null
var onPositiveButtonWasCalled = false
var onNegativeButtonWasCalled = false
var onNeutralButtonWasCalled = false
var dismissWasCalled = false
var setCheckboxValueWasCalled = false
val promptDelegate = GeckoPromptDelegate(mockSession)
mockSession.register(object : EngineSession.Observer {
override fun onPromptRequest(promptRequest: PromptRequest) {
request = promptRequest as PromptRequest.Confirm
}
})
val callback = object : GeckoSession.PromptDelegate.ButtonCallback {
override fun confirm(button: Int) {
when (button) {
BUTTON_TYPE_POSITIVE -> onPositiveButtonWasCalled = true
BUTTON_TYPE_NEGATIVE -> onNegativeButtonWasCalled = true
BUTTON_TYPE_NEUTRAL -> onNeutralButtonWasCalled = true
}
}
override fun setCheckboxValue(value: Boolean) {
setCheckboxValueWasCalled = true
}
override fun dismiss() {
dismissWasCalled = true
}
override fun getCheckboxValue(): Boolean = false
override fun hasCheckbox(): Boolean = true
override fun getCheckboxMessage(): String = ""
}
promptDelegate.onButtonPrompt(
mock(),
"title",
"message",
arrayOf("positive", "neutral", "negative"),
callback
)
with(request!!) {
assertNotNull(request)
assertEquals(title, "title")
assertEquals(message, "message")
assertEquals(hasShownManyDialogs, true)
assertEquals(positiveButtonTitle, "positive")
assertEquals(negativeButtonTitle, "negative")
assertEquals(neutralButtonTitle, "neutral")
onConfirmPositiveButton(false)
assertTrue(onPositiveButtonWasCalled)
onConfirmNegativeButton(false)
assertTrue(onNegativeButtonWasCalled)
onConfirmNeutralButton(false)
assertTrue(onNeutralButtonWasCalled)
assertTrue(setCheckboxValueWasCalled)
onDismiss()
assertTrue(dismissWasCalled)
}
}
open class DefaultGeckoChoiceCallback : GeckoSession.PromptDelegate.ChoiceCallback {
override fun confirm(items: Array<out GeckoChoice>?) = Unit
override fun dismiss() {}
......
......@@ -291,10 +291,51 @@ internal class GeckoPromptDelegate(private val geckoEngineSession: GeckoEngineSe
override fun onButtonPrompt(
session: GeckoSession,
title: String?,
msg: String?,
btnMsg: Array<out String>?,
message: String?,
buttonTitles: Array<out String?>?,
callback: ButtonCallback
) = Unit
) {
val hasShownManyDialogs = callback.hasCheckbox()
val positiveButtonTitle = buttonTitles?.get(GeckoSession.PromptDelegate.BUTTON_TYPE_POSITIVE) ?: ""
val negativeButtonTitle = buttonTitles?.get(GeckoSession.PromptDelegate.BUTTON_TYPE_NEGATIVE) ?: ""
val neutralButtonTitle = buttonTitles?.get(GeckoSession.PromptDelegate.BUTTON_TYPE_NEUTRAL) ?: ""
val onConfirmPositiveButton: (Boolean) -> Unit = { showMoreDialogs ->
callback.checkboxValue = showMoreDialogs
callback.confirm(GeckoSession.PromptDelegate.BUTTON_TYPE_POSITIVE)
}
val onConfirmNegativeButton: (Boolean) -> Unit = { showMoreDialogs ->
callback.checkboxValue = showMoreDialogs
callback.confirm(GeckoSession.PromptDelegate.BUTTON_TYPE_NEGATIVE)
}
val onConfirmNeutralButton: (Boolean) -> Unit = { showMoreDialogs ->
callback.checkboxValue = showMoreDialogs
callback.confirm(GeckoSession.PromptDelegate.BUTTON_TYPE_NEUTRAL)
}
val onDismiss: () -> Unit = {
callback.dismiss()
}
geckoEngineSession.notifyObservers {
onPromptRequest(
PromptRequest.Confirm(
title ?: "",
message ?: "",
hasShownManyDialogs,
positiveButtonTitle,
negativeButtonTitle,
neutralButtonTitle,
onConfirmPositiveButton,
onConfirmNegativeButton,
onConfirmNeutralButton,
onDismiss
)
)
}
}
private fun GeckoChoice.toChoice(): Choice {
val choiceChildren = items?.map { it.toChoice() }?.toTypedArray()
......
......@@ -204,13 +204,6 @@ class GeckoPromptDelegateTest {
assertEquals((alertRequest as PromptRequest.Alert).message, "message")
}
@Test
fun `hitting functions not yet implemented`() {
val mockSession = GeckoEngineSession(Mockito.mock(GeckoRuntime::class.java))
val gecko = GeckoPromptDelegate(mockSession)
gecko.onButtonPrompt(mock(), "", "", null, mock())
}
@Test
fun `hitting default values`() {
val mockSession = GeckoEngineSession(Mockito.mock(GeckoRuntime::class.java))
......@@ -219,6 +212,7 @@ class GeckoPromptDelegateTest {
gecko.onDateTimePrompt(null, null, DATETIME_TYPE_WEEK, null, null, null, mock())
gecko.onDateTimePrompt(null, null, DATETIME_TYPE_MONTH, null, null, null, mock())
gecko.onDateTimePrompt(null, null, DATETIME_TYPE_TIME, null, "", "", mock())
gecko.onButtonPrompt(mock(), null, null, arrayOf<String?>(null, null, null), mock())
}
@Test
......@@ -911,6 +905,81 @@ class GeckoPromptDelegateTest {
assertTrue(onDenyWasCalled)
}
@Test
fun `onButtonPrompt must provide a Confirm PromptRequest`() {
val mockSession = GeckoEngineSession(Mockito.mock(GeckoRuntime::class.java))
var request: PromptRequest.Confirm? = null
var onPositiveButtonWasCalled = false
var onNegativeButtonWasCalled = false
var onNeutralButtonWasCalled = false
var dismissWasCalled = false
var setCheckboxValueWasCalled = false
val promptDelegate = GeckoPromptDelegate(mockSession)
mockSession.register(object : EngineSession.Observer {
override fun onPromptRequest(promptRequest: PromptRequest) {
request = promptRequest as PromptRequest.Confirm
}
})
val callback = object : GeckoSession.PromptDelegate.ButtonCallback {
override fun confirm(button: Int) {
when (button) {
GeckoSession.PromptDelegate.BUTTON_TYPE_POSITIVE -> onPositiveButtonWasCalled = true
GeckoSession.PromptDelegate.BUTTON_TYPE_NEGATIVE -> onNegativeButtonWasCalled = true
GeckoSession.PromptDelegate.BUTTON_TYPE_NEUTRAL -> onNeutralButtonWasCalled = true
}
}
override fun setCheckboxValue(value: Boolean) {
setCheckboxValueWasCalled = true
}
override fun dismiss() {
dismissWasCalled = true
}
override fun getCheckboxValue(): Boolean = false
override fun hasCheckbox(): Boolean = true
override fun getCheckboxMessage(): String = ""
}
promptDelegate.onButtonPrompt(
mock(),
"title",
"message",
arrayOf("positive", "neutral", "negative"),
callback
)
with(request!!) {
assertNotNull(request)
assertEquals(title, "title")
assertEquals(message, "message")
assertEquals(hasShownManyDialogs, true)
assertEquals(positiveButtonTitle, "positive")
assertEquals(negativeButtonTitle, "negative")
assertEquals(neutralButtonTitle, "neutral")
onConfirmPositiveButton(false)
assertTrue(onPositiveButtonWasCalled)
onConfirmNegativeButton(false)
assertTrue(onNegativeButtonWasCalled)
onConfirmNeutralButton(false)
assertTrue(onNeutralButtonWasCalled)
assertTrue(setCheckboxValueWasCalled)
onDismiss()
assertTrue(dismissWasCalled)
}
}
open class DefaultGeckoChoiceCallback : GeckoSession.PromptDelegate.ChoiceCallback {
override fun confirm(items: Array<out GeckoChoice>?) = Unit
override fun dismiss() {}
......
......@@ -150,8 +150,8 @@ sealed class PromptRequest {
/**
* Value type that represents a request for a selecting one or multiple files.
* @property defaultColor true if the user can select more that one file false otherwise.
* @property onConfirm callback to notify that the user has selected a single file.
* @property onDismiss callback to notify that the user has canceled the file selection.
* @property onConfirm callback to notify that the user has selected a color.
* @property onDismiss callback to notify that the user has canceled the dialog.
*/
data class Color(
val defaultColor: String,
......@@ -173,4 +173,34 @@ sealed class PromptRequest {
val onAllow: () -> Unit,
val onDeny: () -> Unit
) : PromptRequest()
/**
* Value type that represents a request for showing a
* <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm>confirm prompt</a>.
*
* The prompt can have up to three buttons, they could be positive, negative and neutral.
*
* @property title of the dialog.
* @property message the body of the dialog.
* @property hasShownManyDialogs tells if this page has shown multiple prompts within a short period of time.
* @property positiveButtonTitle optional title for the positive button.
* @property negativeButtonTitle optional title for the negative button.
* @property neutralButtonTitle optional title for the neutral button.
* @property onConfirmPositiveButton callback to notify that the user has clicked the positive button.
* @property onConfirmNegativeButton callback to notify that the user has clicked the negative button.
* @property onConfirmNeutralButton callback to notify that the user has clicked the neutral button.
* @property onDismiss callback to notify that the user has canceled the dialog.
*/
data class Confirm(
val title: String,
val message: String,
val hasShownManyDialogs: Boolean = false,
val positiveButtonTitle: String = "",
val negativeButtonTitle: String = "",
val neutralButtonTitle: String = "",
val onConfirmPositiveButton: (Boolean) -> Unit,