Skip to content

Commit

Permalink
Add spellcheck to editor content
Browse files Browse the repository at this point in the history
  • Loading branch information
tevincent committed Sep 20, 2024
1 parent 7d02ba9 commit 8394e86
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 6 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,15 @@ editor.apply {
To safely use your own WebViewClient instance with the editor, you have to call the
RichHtmlEditorWebView's `notifyPageHasLoaded()` inside your custom WebViewClient's `onPageFinished()` callback.

### Activate/Deactivate spellcheck

Spellcheck is activated by default but if you don't want to have any spellcheck done on the editor content,
you can do that by doing so.

```kt
editor.withSpellCheck(false)
```

### More advanced features

For more advanced features, take a look at the [sample project](sample) or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import com.infomaniak.lib.richhtmleditor.executor.KeyboardOpener
import com.infomaniak.lib.richhtmleditor.executor.ScriptCssInjector
import com.infomaniak.lib.richhtmleditor.executor.ScriptCssInjector.CodeInjection
import com.infomaniak.lib.richhtmleditor.executor.ScriptCssInjector.CodeInjection.InjectionType
import com.infomaniak.lib.richhtmleditor.executor.SpellCheckHtmlSetter
import com.infomaniak.lib.richhtmleditor.executor.StateSubscriber
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
Expand Down Expand Up @@ -83,6 +84,7 @@ class RichHtmlEditorWebView @JvmOverloads constructor(
private val documentInitializer = DocumentInitializer()
private val stateSubscriber = StateSubscriber(this)
private val htmlSetter = HtmlSetter(this)
private val spellCheckHtmlSetter = SpellCheckHtmlSetter(this)
private val jsExecutor = JsExecutor(this)
private val scriptCssInjector = ScriptCssInjector(this)
private val keyboardOpener = KeyboardOpener(this)
Expand Down Expand Up @@ -134,6 +136,8 @@ class RichHtmlEditorWebView @JvmOverloads constructor(

webViewClient = RichHtmlEditorWebViewClient(::notifyPageHasLoaded)

withSpellCheck(true)

addJavascriptInterface(jsBridge, "editor")

stateSubscriber.executeWhenDomIsLoaded(null)
Expand Down Expand Up @@ -171,6 +175,11 @@ class RichHtmlEditorWebView @JvmOverloads constructor(
*/
fun addCss(css: String) = scriptCssInjector.executeWhenDomIsLoaded(CodeInjection(InjectionType.CSS, css))

/**
* Injects a custom attribute to the editor div to activate/deactivate spellchecking. By default, spellcheck is activated.
*/
fun withSpellCheck(enable: Boolean) = spellCheckHtmlSetter.executeWhenDomIsLoaded(enable)

/**
* Injects a custom script tag into the `<head>` of the editor template.
*
Expand Down Expand Up @@ -224,6 +233,7 @@ class RichHtmlEditorWebView @JvmOverloads constructor(

stateSubscriber.notifyDomLoaded()
htmlSetter.notifyDomLoaded()
spellCheckHtmlSetter.notifyDomLoaded()
jsExecutor.notifyDomLoaded()
scriptCssInjector.notifyDomLoaded()
keyboardOpener.notifyDomLoaded()
Expand Down Expand Up @@ -339,6 +349,9 @@ class RichHtmlEditorWebView @JvmOverloads constructor(
}

companion object {
// The id of this HTML tag is shared across multiple files and needs to remain the same
const val EDITOR_ID = "editor"

private const val KEYBOARD_SHOULD_REOPEN_KEY = "keyboardShouldReopen"
private const val SUPER_STATE_KEY = "superState"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.infomaniak.lib.richhtmleditor.executor

import android.webkit.WebView
import com.infomaniak.lib.richhtmleditor.RichHtmlEditorWebView.Companion.EDITOR_ID
import com.infomaniak.lib.richhtmleditor.looselyEscapeAsStringLiteralForJs

internal class HtmlSetter(private val webView: WebView) : JsLifecycleAwareExecutor<String>() {
Expand All @@ -26,11 +27,9 @@ internal class HtmlSetter(private val webView: WebView) : JsLifecycleAwareExecut

private fun WebView.insertUserHtml(html: String) {
val escapedHtmlStringLiteral = looselyEscapeAsStringLiteralForJs(html)
evaluateJavascript("""document.getElementById("$EDITOR_ID").innerHTML = $escapedHtmlStringLiteral""", null)
}

companion object {
// The id of this HTML tag is shared across multiple files and needs to remain the same
private const val EDITOR_ID = "editor"
evaluateJavascript(
"""document.getElementById("$EDITOR_ID").innerHTML = $escapedHtmlStringLiteral""",
null
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Infomaniak Rich HTML Editor - Android
* Copyright (C) 2024 Infomaniak Network SA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.infomaniak.lib.richhtmleditor.executor

import android.webkit.WebView
import com.infomaniak.lib.richhtmleditor.RichHtmlEditorWebView.Companion.EDITOR_ID

internal class SpellCheckHtmlSetter(private val webView: WebView) : JsLifecycleAwareExecutor<Boolean>() {

override fun executeImmediately(value: Boolean) = webView.insertSpellCheckValue(value)

private fun WebView.insertSpellCheckValue(enable: Boolean) {
val spellCheckValue = if (enable) "true" else "false"
evaluateJavascript(
"""document.getElementById("$EDITOR_ID").setAttribute("spellcheck", $spellCheckValue)""",
null
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class EditorSampleFragment : Fragment() {
// addCss(readAsset("editor_custom_css.css"))
// addScript("document.body.style['background'] = '#00FFFF'")
// subscribeToStates(setOf(StatusCommand.BOLD, StatusCommand.ITALIC))
// withSpellCheck(false)

isVisible = true
setOnFocusChangeListener { _, hasFocus -> setToolbarEnabledStatus(hasFocus) }
Expand Down

0 comments on commit 8394e86

Please sign in to comment.