majro update

This commit is contained in:
Fabian Freund
2025-02-28 14:30:49 +01:00
parent a8957f6cf8
commit 3c4d479bd9
181 changed files with 7090 additions and 5299 deletions
@@ -19,7 +19,6 @@ linter:
unawaited_futures: true
discarded_futures: true
collection_methods_unrelated_type: true
require_trailing_commas: false
analyzer:
plugins:
@@ -9,7 +9,9 @@
"version": "1.0",
"content_scripts": [
{
"matches": ["<all_urls>"],
"matches": [
"<all_urls>"
],
"js": [
"readability.min.js",
"content.js"
@@ -26,4 +28,4 @@
"webNavigation",
"<all_urls>"
]
}
}
@@ -0,0 +1,32 @@
const port = browser.runtime.connectNative("mozacTurndownHtml");
const parser = new DOMParser();
port.onMessage.addListener(message => {
let requestId = message["id"];
switch (message["action"]) {
case "turndown":
console.log(message.args)
// Handle array of HTML strings
if (Array.isArray(message.args)) {
const results = message.args.map(htmlString => {
const document = parser.parseFromString(htmlString, 'text/html');
return parseFullMarkdown(document);
});
port.postMessage({
"id": requestId,
"status": "success",
"result": results
});
} else {
// Handle error case for invalid input
port.postMessage({
"id": requestId,
"status": "error",
"error": "Expected args to be an array of HTML strings"
});
}
break;
}
});
@@ -0,0 +1,21 @@
{
"manifest_version": 2,
"browser_specific_settings": {
"gecko": {
"id": "turndown@movenext.me"
}
},
"name": "Converts html to markdown",
"version": "1.0",
"background": {
"scripts": [
"readability.min.js",
"background.js"
]
},
"permissions": [
"geckoViewAddons",
"nativeMessaging",
"<all_urls>"
]
}
@@ -0,0 +1 @@
../../../../../../javascript/readability/dist/readability.min.js
@@ -8,6 +8,7 @@ import android.content.Context
import eu.lensai.flutter_mozilla_components.feature.ContainerProxyFeature
import eu.lensai.flutter_mozilla_components.feature.CookieManagerFeature
import eu.lensai.flutter_mozilla_components.feature.PrefManagerFeature
import eu.lensai.flutter_mozilla_components.feature.TurndownFeature
import mozilla.components.browser.engine.gecko.GeckoEngine
import mozilla.components.browser.engine.gecko.fetch.GeckoViewFetchClient
import mozilla.components.concept.engine.DefaultSettings
@@ -52,6 +53,7 @@ object EngineProvider {
CookieManagerFeature.install(it)
PrefManagerFeature.install(it)
ContainerProxyFeature.install(it)
TurndownFeature.install(it)
}
}
@@ -18,6 +18,7 @@ import eu.lensai.flutter_mozilla_components.api.GeckoSelectionActionControllerIm
import eu.lensai.flutter_mozilla_components.api.GeckoSessionApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoSuggestionApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoTabsApiImpl
import eu.lensai.flutter_mozilla_components.api.GeckoTurndownApiImpl
import eu.lensai.flutter_mozilla_components.feature.DefaultSelectionActionDelegate
import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonEvents
import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonsApi
@@ -38,6 +39,7 @@ import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionEvents
import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabContentEvents
import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabsApi
import eu.lensai.flutter_mozilla_components.pigeons.GeckoTurndownApi
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController
import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewEvents
@@ -123,6 +125,7 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware {
))
GeckoDeleteBrowsingDataController.setUp(_flutterPluginBinding.binaryMessenger, GeckoDeleteBrowsingDataControllerImpl())
GeckoDownloadsApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoDownloadsApiImpl())
GeckoTurndownApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoTurndownApiImpl())
ReaderViewEvents.setUp(
_flutterPluginBinding.binaryMessenger,
@@ -0,0 +1,53 @@
package eu.lensai.flutter_mozilla_components.api
import eu.lensai.flutter_mozilla_components.feature.ResultConsumer
import eu.lensai.flutter_mozilla_components.feature.TurndownFeature
import eu.lensai.flutter_mozilla_components.pigeons.GeckoTurndownApi
import org.json.JSONArray
import org.json.JSONObject
class GeckoTurndownApiImpl : GeckoTurndownApi {
private fun JSONObject.toMap(): Map<String, Any> {
val map = mutableMapOf<String, Any>()
val keys = this.keys()
while (keys.hasNext()) {
val key = keys.next()
when (val value = this.get(key)) {
is JSONObject -> map[key] = value.toMap()
is JSONArray -> map[key] = value.toList()
// JSONObject.NULL -> map[key] = null
else -> map[key] = value
}
}
return map
}
private fun JSONArray.toList(): List<Any> {
val list = mutableListOf<Any>()
for (i in 0 until this.length()) {
when (val value = this.get(i)) {
is JSONObject -> list.add(value.toMap())
is JSONArray -> list.add(value.toList())
JSONObject.NULL -> list.add(null as Any)
else -> list.add(value)
}
}
return list
}
override fun getMarkdown(htmlList: List<String>, callback: (Result<List<Any>>) -> Unit) {
TurndownFeature.scheduleRequest("turndown", htmlList, object :
ResultConsumer<JSONObject> {
override fun success(result: JSONObject) {
val resultArray = result.getJSONArray("result")
callback(Result.success(resultArray.toList()))
}
override fun error(errorCode: String, errorMessage: String?, errorDetails: Any?) {
callback(Result.failure(Exception("$errorCode $errorMessage $errorDetails")))
}
})
}
}
@@ -0,0 +1,104 @@
package eu.lensai.flutter_mozilla_components.feature
import androidx.annotation.VisibleForTesting
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import mozilla.components.concept.engine.webextension.MessageHandler
import mozilla.components.concept.engine.webextension.Port
import mozilla.components.concept.engine.webextension.WebExtensionRuntime
import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.webextensions.WebExtensionController
import org.json.JSONArray
import org.json.JSONObject
object TurndownFeature {
private val logger = Logger("turndown")
private const val PREF_MANAGER_REPORTER_EXTENSION_ID = "turndown@movenext.me"
private const val PREF_MANAGER_REPORTER_EXTENSION_URL = "resource://android/assets/extensions/turndown/"
private const val PREF_MANAGER_REPORTER_MESSAGING_ID = "mozacTurndownHtml"
private var nextRequestId: Int = 0
private val requestHandlers = HashMap<Int, ResultConsumer<JSONObject>>()
private val mutex = Mutex()
@VisibleForTesting
// This is an internal var to make it mutable for unit testing purposes only
internal var extensionController = WebExtensionController(
PREF_MANAGER_REPORTER_EXTENSION_ID,
PREF_MANAGER_REPORTER_EXTENSION_URL,
PREF_MANAGER_REPORTER_MESSAGING_ID,
)
fun scheduleRequest(command: String, args: Any, callback: ResultConsumer<JSONObject>) {
val message = JSONObject()
message.put("action", command);
message.put("args", when (args) {
is List<*> -> JSONArray(args)
else -> args
})
runBlocking {
withContext(Dispatchers.Default) {
mutex.withLock {
message.put("id", nextRequestId)
requestHandlers[nextRequestId] = callback
nextRequestId += 1
extensionController.sendBackgroundMessage(message)
}
}
}
}
private class TurndownBackgroundMessageHandler() : MessageHandler {
override fun onPortMessage(message: Any, port: Port) {
runBlocking {
withContext(Dispatchers.Default) {
mutex.withLock {
val messageJSON = message as JSONObject;
val requestId = messageJSON.getInt("id")
val status = messageJSON.getString("status")
if (status == "success") {
requestHandlers[requestId]?.success(message)
} else {
requestHandlers[requestId]?.error(
"Pref Manager",
"Failed to perform operation",
message.getString("error")
)
}
}
}
}
}
}
/**
* Installs the web extension in the runtime through the WebExtensionRuntime install method
*
* @param runtime a WebExtensionRuntime.
* @param productName a custom product name used to automatically label reports. Defaults to
* "android-components".
*/
fun install(runtime: WebExtensionRuntime) {
extensionController.registerBackgroundMessageHandler(
TurndownBackgroundMessageHandler(),
)
extensionController.install(
runtime,
onSuccess = {
logger.debug("Installed Turndown webextension: ${it.id}")
},
onError = { throwable ->
logger.error("Failed to install Turndown webextension: ", throwable)
},
)
}
}
@@ -2980,6 +2980,42 @@ interface GeckoPrefApi {
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface GeckoTurndownApi {
fun getMarkdown(htmlList: List<String>, callback: (Result<List<Any>>) -> Unit)
companion object {
/** The codec used by GeckoTurndownApi. */
val codec: MessageCodec<Any?> by lazy {
GeckoPigeonCodec()
}
/** Sets up an instance of `GeckoTurndownApi` to handle messages through the `binaryMessenger`. */
@JvmOverloads
fun setUp(binaryMessenger: BinaryMessenger, api: GeckoTurndownApi?, messageChannelSuffix: String = "") {
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoTurndownApi.getMarkdown$separatedMessageChannelSuffix", codec)
if (api != null) {
channel.setMessageHandler { message, reply ->
val args = message as List<Any?>
val htmlListArg = args[0] as List<String>
api.getMarkdown(htmlListArg) { result: Result<List<Any>> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(wrapError(error))
} else {
val data = result.getOrNull()
reply.reply(wrapResult(data))
}
}
}
} else {
channel.setMessageHandler(null)
}
}
}
}
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
interface GeckoContainerProxyApi {
fun setProxyPort(port: Long)
fun addContainerProxy(contextId: String)
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>readability [18 Jan 2025 at 20:19]</title>
<title>readability [24 Feb 2025 at 15:42]</title>
<link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAABrVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+O1foceMD///+J0/qK1Pr7/v8Xdr/9///W8P4UdL7L7P0Scr2r4Pyj3vwad8D5/f/2/f+55f3E6f34+/2H0/ojfMKpzOd0rNgQcb3F3O/j9f7c8v6g3Pz0/P/w+v/q+P7n9v6T1/uQ1vuE0vqLut/y+v+Z2fvt+f+15Pzv9fuc2/vR7v2V2Pvd6/bg9P7I6/285/2y4/yp3/zp8vk8i8kqgMT7/P31+fyv4vxGkcz6/P6/6P3j7vfS5PNnpNUxhcbO7f7F6v3O4vHK3/DA2u631Ouy0eqXweKJud5wqthfoNMMbLvY8f73+v2dxeR8sNtTmdDx9/zX6PSjyeaCtd1YnNGX2PuQveCGt95Nls42h8dLlM3F4vBtAAAAM3RSTlMAAyOx0/sKBvik8opWGBMOAe3l1snDm2E9LSb06eHcu5JpHbarfHZCN9CBb08zzkdNS0kYaptYAAAFV0lEQVRYw92X51/aYBDHHS2O2qqttVbrqNq9m+TJIAYIShBkWwqIiCgoWvfeq7Z2/s29hyQNyUcR7LveGwVyXy6XH8/9rqxglLfUPLxVduUor3h0rfp2TYvpivk37929TkG037hffoX0+peVtZQc1589rigVUdXS/ABSAyEmGIO/1XfvldSK8vs3OqB6u3m0nxmIrvgB0dj7rr7Y9IbuF68hnfFaiHA/sxqm0wciIG43P60qKv9WXWc1RXGh/mFESFABTSBi0sNAKzqet17eCtOb3kZIDwxEEU0oAIJGYxNBDhBND29e0rtXXbcpuPmED9IhEAAQ/AXEaF8EPmnrrKsv0LvWR3fg5sWDNAFZOgAgaKvZDogHNU9MFwnnYROkc56RD5CjAbQX9Ow4g7upCsvYu55aSI/Nj0H1akgKQEUM94dwK65hYRmFU9MIcH/fqJYOZYcnuJSU/waKDgTOEVaVKhwrTRP5XzgSpAITYzom7UvkhFX5VutmxeNnWDjjswTKTyfgluNDGbUpWissXhF3s7mlSml+czWkg3D0l1nNjGNjz3myOQOa1KM/jOS6ebdbAVTCi4gljHSFrviza7tOgRWcS0MOUX9zdNgag5w7rRqA44Lzw0hr1WqES36dFliSJFlh2rXIae3FFcDDgKdxrUIDePr8jGcSClV1u7A9xeN0ModY/pHMxmR1EzRh8TJiwqsHmKW0l4FCEZI+jHio+JdPPE9qwQtTRxku2D8sIeRL2LnxWSllANCQGOIiqVHAz2ye2JR0DcH+HoxDkaADLjgxjKQ+AwCX/g0+DNgdG0ukYCONAe+dbc2IAc6fwt1ARoDSezNHxV2Cmzwv3O6lDMV55edBGwGK9n1+x2F8EDfAGCxug8MhpsMEcTEAWf3rx2vZhe/LAmtIn/6apE6PN0ULKgywD9mmdxbmFl3OvD5AS5fW5zLbv/YHmcsBTjf/afDz3MaZTVCfAP9z6/Bw6ycv8EUBWJIn9zYcoAWWlW9+OzO3vkTy8H+RANLmdrpOuYWdZYEXpo+TlCJrW5EARb7fF+bWdqf3hhyZI1nWJQHgznErZhbjoEsWqi8dQNoE294aldzFurwSABL2XXMf9+H1VQGke9exw5P/AnA5Pv5ngMul7LOvO922iwACu8WkCwLCafvM4CeWPxfA8lNHcWZSoi8EwMAIciKX2Z4SWCMAa3snCZ/G4EA8D6CMLNFsGQhkkz/gQNEBbPCbWsxGUpYVu3z8IyNAknwJkfPMEhLyrdi5RTyUVACkw4GSFRNWJNEW+fgPGwHD8/JxnRuLabN4CGNRkAE23na2+VmEAUmrYymSGjMAYqH84YUIyzgzs3XC7gNgH36Vcc4zKY9o9fgPBXUAiHHwVboBHGLiX6Zcjp1f2wu4tvzZKo0ecPnDtQYDQvJXaBeNzce45Fp28ZQLrEZVuFqgBwOalArKXnW1UzlnSusQKJqKYNuz4tOnI6sZG4zanpemv+7ySU2jbA9h6uhcgpfy6G2PahirDZ6zvq6zDduMVFTKvzw8wgyEdelwY9in3XkEPs3osJuwRQ4qTkfzifndg9Gfc4pdsu82+tTnHZTBa2EAMrqr2t43pguc8tNm7JQVQ2S0ukj2d22dhXYP0/veWtwKrCkNoNimAN5+Xr/oLrxswKbVJjteWrX7eR63o4j9q0GxnaBdWgGA5VStpanIjQmEhV0/nVt5VOFUvix6awJhPcAaTEShgrG+iGyvb5a0Ndb1YGHFPEwoqAinoaykaID1o1pdPNu7XsnCKQ3R+hwWIIhGvORcJUBYXe3Xa3vq/mF/N9V13ugufMkfXn+KHsRD0B8AAAAASUVORK5CYII=" type="image/x-icon" />
<script>
@@ -31,7 +31,7 @@
<body>
<div id="app"></div>
<script>
window.chartData = [{"label":"readability.min.js","isAsset":true,"statSize":121815,"parsedSize":49051,"gzipSize":15893,"groups":[{"label":"node_modules","path":"./node_modules","statSize":92482,"groups":[{"label":"@mozilla/readability","path":"./node_modules/@mozilla/readability","statSize":88421,"groups":[{"id":804,"label":"Readability-readerable.js","path":"./node_modules/@mozilla/readability/Readability-readerable.js","statSize":4162},{"id":238,"label":"Readability.js","path":"./node_modules/@mozilla/readability/Readability.js","statSize":84033},{"id":396,"label":"index.js","path":"./node_modules/@mozilla/readability/index.js","statSize":226}],"parsedSize":0,"gzipSize":0},{"label":"remove-markdown","path":"./node_modules/remove-markdown","statSize":4061,"groups":[{"id":481,"label":"index.js","path":"./node_modules/remove-markdown/index.js","statSize":4061}],"parsedSize":0,"gzipSize":0}],"parsedSize":0,"gzipSize":0},{"label":"src","path":"./src","statSize":29333,"groups":[{"id":922,"label":"index.js + 1 modules (concatenated)","path":"./src/index.js + 1 modules (concatenated)","statSize":29333,"parsedSize":49043,"gzipSize":15893,"concatenated":true,"groups":[{"label":"src","path":"./src/index.js + 1 modules (concatenated)/src","statSize":4271,"groups":[{"id":null,"label":"index.js","path":"./src/index.js + 1 modules (concatenated)/src/index.js","statSize":4271,"parsedSize":7140,"gzipSize":2314,"inaccurateSizes":true}],"parsedSize":7140,"gzipSize":2314,"inaccurateSizes":true},{"label":"node_modules/turndown/lib","path":"./src/index.js + 1 modules (concatenated)/node_modules/turndown/lib","statSize":25062,"groups":[{"id":null,"label":"turndown.browser.es.js","path":"./src/index.js + 1 modules (concatenated)/node_modules/turndown/lib/turndown.browser.es.js","statSize":25062,"parsedSize":41902,"gzipSize":13578,"inaccurateSizes":true}],"parsedSize":41902,"gzipSize":13578,"inaccurateSizes":true}]}],"parsedSize":49043,"gzipSize":15893}],"isInitialByEntrypoint":{"main":true}}];
window.chartData = [{"label":"readability.min.js","isAsset":true,"statSize":121880,"parsedSize":49105,"gzipSize":15912,"groups":[{"label":"node_modules","path":"./node_modules","statSize":92482,"groups":[{"label":"@mozilla/readability","path":"./node_modules/@mozilla/readability","statSize":88421,"groups":[{"id":804,"label":"Readability-readerable.js","path":"./node_modules/@mozilla/readability/Readability-readerable.js","statSize":4162},{"id":238,"label":"Readability.js","path":"./node_modules/@mozilla/readability/Readability.js","statSize":84033},{"id":396,"label":"index.js","path":"./node_modules/@mozilla/readability/index.js","statSize":226}],"parsedSize":0,"gzipSize":0},{"label":"remove-markdown","path":"./node_modules/remove-markdown","statSize":4061,"groups":[{"id":481,"label":"index.js","path":"./node_modules/remove-markdown/index.js","statSize":4061}],"parsedSize":0,"gzipSize":0}],"parsedSize":0,"gzipSize":0},{"label":"src","path":"./src","statSize":29398,"groups":[{"id":922,"label":"index.js + 1 modules (concatenated)","path":"./src/index.js + 1 modules (concatenated)","statSize":29398,"parsedSize":49097,"gzipSize":15912,"concatenated":true,"groups":[{"label":"src","path":"./src/index.js + 1 modules (concatenated)/src","statSize":4336,"groups":[{"id":null,"label":"index.js","path":"./src/index.js + 1 modules (concatenated)/src/index.js","statSize":4336,"parsedSize":7241,"gzipSize":2346,"inaccurateSizes":true}],"parsedSize":7241,"gzipSize":2346,"inaccurateSizes":true},{"label":"node_modules/turndown/lib","path":"./src/index.js + 1 modules (concatenated)/node_modules/turndown/lib","statSize":25062,"groups":[{"id":null,"label":"turndown.browser.es.js","path":"./src/index.js + 1 modules (concatenated)/node_modules/turndown/lib/turndown.browser.es.js","statSize":25062,"parsedSize":41855,"gzipSize":13565,"inaccurateSizes":true}],"parsedSize":41855,"gzipSize":13565,"inaccurateSizes":true}]}],"parsedSize":49097,"gzipSize":15912}],"isInitialByEntrypoint":{"main":true}}];
window.entrypoints = ["main"];
window.defaultSizes = "parsed";
</script>
@@ -1,8 +1,8 @@
{
"hash": "68fe8281f85d9e1fa8f9",
"hash": "3b7b601a842a4a70dcf0",
"version": "5.97.1",
"time": 560,
"builtAt": 1737227987116,
"time": 695,
"builtAt": 1740408169935,
"publicPath": "auto",
"outputPath": "/home/fafre/development/repos/lensai/packages/flutter_mozilla_components/javascript/readability/dist",
"assetsByChunkName": {
@@ -14,14 +14,14 @@
{
"type": "asset",
"name": "readability.min.js",
"size": 49051,
"size": 49105,
"emitted": true,
"comparedForEmit": false,
"cached": false,
"info": {
"javascriptModule": false,
"minimized": true,
"size": 49051
"size": 49105
},
"chunkNames": [
"main"
@@ -43,9 +43,9 @@
"initial": true,
"entry": true,
"recorded": false,
"size": 122485,
"size": 122550,
"sizes": {
"javascript": 121815,
"javascript": 121880,
"runtime": 670
},
"names": [
@@ -59,7 +59,7 @@
"readability.min.js"
],
"auxiliaryFiles": [],
"hash": "bf73e1848f9bdc88f1b3",
"hash": "560dd27471dfc45dd435",
"childrenByOrder": {},
"id": 792,
"siblings": [],
@@ -428,9 +428,9 @@
"type": "module",
"moduleType": "javascript/esm",
"layer": null,
"size": 29333,
"size": 29398,
"sizes": {
"javascript": 29333
"javascript": 29398
},
"built": true,
"codeGenerated": true,
@@ -486,6 +486,7 @@
],
"usedExports": true,
"providedExports": [
"parseFullMarkdown",
"parseReaderable"
],
"optimizationBailout": [
@@ -497,9 +498,9 @@
"type": "module",
"moduleType": "javascript/auto",
"layer": null,
"size": 4271,
"size": 4336,
"sizes": {
"javascript": 4271
"javascript": 4336
},
"built": true,
"codeGenerated": false,
@@ -529,6 +530,7 @@
"reasons": [],
"usedExports": true,
"providedExports": [
"parseFullMarkdown",
"parseReaderable"
],
"optimizationBailout": [
@@ -743,9 +745,9 @@
"type": "module",
"moduleType": "javascript/esm",
"layer": null,
"size": 29333,
"size": 29398,
"sizes": {
"javascript": 29333
"javascript": 29398
},
"built": true,
"codeGenerated": true,
@@ -800,6 +802,7 @@
],
"usedExports": true,
"providedExports": [
"parseFullMarkdown",
"parseReaderable"
],
"optimizationBailout": [
@@ -811,9 +814,9 @@
"type": "module",
"moduleType": "javascript/auto",
"layer": null,
"size": 4271,
"size": 4336,
"sizes": {
"javascript": 4271
"javascript": 4336
},
"built": true,
"codeGenerated": false,
@@ -842,6 +845,7 @@
"reasons": [],
"usedExports": true,
"providedExports": [
"parseFullMarkdown",
"parseReaderable"
],
"optimizationBailout": [
@@ -1478,11 +1482,11 @@
"assets": [
{
"name": "readability.min.js",
"size": 49051
"size": 49105
}
],
"filteredAssets": 0,
"assetsSize": 49051,
"assetsSize": 49105,
"auxiliaryAssets": [],
"filteredAuxiliaryAssets": 0,
"auxiliaryAssetsSize": 0,
@@ -1500,11 +1504,11 @@
"assets": [
{
"name": "readability.min.js",
"size": 49051
"size": 49105
}
],
"filteredAssets": 0,
"assetsSize": 49051,
"assetsSize": 49105,
"auxiliaryAssets": [],
"filteredAuxiliaryAssets": 0,
"auxiliaryAssetsSize": 0,
@@ -6,106 +6,106 @@ const removeMarkdown = require('remove-markdown');
const turndownService = new TurndownService();
function sanitizeHtmlTags(node, unwantedSelectors) {
unwantedSelectors.forEach(selector => {
node.querySelectorAll(selector).forEach(el => el.remove());
});
unwantedSelectors.forEach(selector => {
node.querySelectorAll(selector).forEach(el => el.remove());
});
return node;
return node;
}
function parseFullMarkdown(node) {
const clonedDoc = node.cloneNode(true);
const clonedDoc = node.cloneNode(true);
sanitizeHtmlTags(clonedDoc, [
/* Navigation and Header Elements */
'nav',
'footer',
'header',
'aside',
'menu',
'toolbar',
sanitizeHtmlTags(clonedDoc, [
/* Navigation and Header Elements */
'nav',
'footer',
'header',
'aside',
'menu',
'toolbar',
/* Interactive Elements */
'form',
'button',
'[role="button"]',
'[type="button"]',
'dialog',
'modal',
/* Interactive Elements */
'form',
'button',
'[role="button"]',
'[type="button"]',
'dialog',
'modal',
/* Hidden Elements */
'[aria-hidden="true"]',
'[hidden]',
'[style*="display: none"]',
'[style*="visibility: hidden"]',
'.hidden',
'.invisible',
/* Hidden Elements */
'[aria-hidden="true"]',
'[hidden]',
'[style*="display: none"]',
'[style*="visibility: hidden"]',
'.hidden',
'.invisible',
/* Advertising and Marketing */
'.ad',
'.advertisement',
'.banner',
'.sponsored',
'.promotion',
'.popup',
'.newsletter',
'.subscribe',
/* Advertising and Marketing */
'.ad',
'.advertisement',
'.banner',
'.sponsored',
'.promotion',
'.popup',
'.newsletter',
'.subscribe',
/* Social Media */
'.social-share',
'.social-media',
'.share-buttons',
'.follow-us',
'.likes',
'.comments',
/* Social Media */
'.social-share',
'.social-media',
'.share-buttons',
'.follow-us',
'.likes',
'.comments',
/* Common UI Components */
'.cookie-notice',
'.cookie-banner',
'.modal',
'.overlay',
'.tooltip',
'.popup',
'.sidebar',
'.widget',
/* Common UI Components */
'.cookie-notice',
'.cookie-banner',
'.modal',
'.overlay',
'.tooltip',
'.popup',
'.sidebar',
'.widget',
/* Navigation Related */
'.breadcrumb',
'.pagination',
'.menu',
'.navbar',
'.navigation',
/* Navigation Related */
'.breadcrumb',
'.pagination',
'.menu',
'.navbar',
'.navigation',
/* Related Content */
'.related-posts',
'.recommended',
'.suggestions',
'.read-more',
/* Related Content */
'.related-posts',
'.recommended',
'.suggestions',
'.read-more',
/* Interactive Features */
'.search',
'.search-box',
'.login',
'.signup',
'.register',
/* Interactive Features */
'.search',
'.search-box',
'.login',
'.signup',
'.register',
/* Print-specific */
'.print-only',
'[media="print"]'
]);
/* Print-specific */
'.print-only',
'[media="print"]'
]);
const fullMarkdown = turndownService.turndown(clonedDoc.body.innerHTML);
const fullMarkdown = turndownService.turndown(clonedDoc.body.innerHTML);
let response = {
fullContentMarkdown: fullMarkdown,
fullContentPlain: removeMarkdown(fullMarkdown),
};
let response = {
fullContentMarkdown: fullMarkdown,
fullContentPlain: removeMarkdown(fullMarkdown),
};
return response;
return response;
}
function parseReaderable(document, options) {
const clonedDoc = document.cloneNode(true);
const clonedDoc = document.cloneNode(true);
sanitizeHtmlTags(clonedDoc, [
/* Technical Elements */
'script',
@@ -143,4 +143,6 @@ function parseReaderable(document, options) {
}
window.parseReaderable = parseReaderable;
export { parseReaderable };
window.parseFullMarkdown = parseFullMarkdown;
export { parseReaderable, parseFullMarkdown };
@@ -18,6 +18,7 @@ export 'src/domain/services/gecko_session.dart';
export 'src/domain/services/gecko_suggestions.dart';
export 'src/domain/services/gecko_tab.dart';
export 'src/domain/services/gecko_tab_content.dart';
export 'src/domain/services/gecko_turndown.dart';
export 'src/geckoview_widget.dart';
export 'src/pigeons/gecko.g.dart'
show
@@ -0,0 +1,7 @@
class TurndownResults {
final String plain;
final String? markdown;
TurndownResults({required this.plain, required String markdown})
: markdown = (plain != markdown) ? markdown : null;
}
@@ -13,7 +13,7 @@ class GeckoIconService {
IconSize size = IconSize.defaultSize,
bool isPrivate = false,
bool waitOnNetworkLoad = true,
}) async {
}) {
return _api.loadIcon(
IconRequest(
url: url.toString(),
@@ -0,0 +1,25 @@
import 'package:flutter_mozilla_components/src/domain/entities/turndown_result.dart';
import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart';
final _apiInstance = GeckoTurndownApi();
class GeckoTurndownService {
Future<List<TurndownResults>> turndownHtml(List<String> htmlList) async {
final markdownResult = await _apiInstance.getMarkdown(htmlList);
final results =
markdownResult
.cast()
.map(
(result) => TurndownResults(
// ignore: avoid_dynamic_calls valid
markdown: result['fullContentMarkdown'] as String,
// ignore: avoid_dynamic_calls valid
plain: result['fullContentPlain'] as String,
),
)
.toList();
return results;
}
}
@@ -9,8 +9,8 @@ import 'package:flutter/services.dart';
import 'package:flutter_mozilla_components/src/domain/services/gecko_browser.dart';
class GeckoView extends StatefulWidget {
final FutureOr<void> Function()? preInitializationStep;
final FutureOr<void> Function()? postInitializationStep;
final Future<void> Function()? preInitializationStep;
final Future<void> Function()? postInitializationStep;
const GeckoView({
super.key,
@@ -62,7 +62,7 @@ class _GeckoViewState extends State<GeckoView> {
creationParams: {},
creationParamsCodec: const StandardMessageCodec(),
)
..addOnPlatformViewCreatedListener((value) async {
..addOnPlatformViewCreatedListener((value) {
params.onPlatformViewCreated(value);
SchedulerBinding.instance.addPostFrameCallback((_) async {
@@ -3123,6 +3123,48 @@ class GeckoPrefApi {
}
}
class GeckoTurndownApi {
/// Constructor for [GeckoTurndownApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
/// BinaryMessenger will be used which routes to the host platform.
GeckoTurndownApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''})
: pigeonVar_binaryMessenger = binaryMessenger,
pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : '';
final BinaryMessenger? pigeonVar_binaryMessenger;
static const MessageCodec<Object?> pigeonChannelCodec = _PigeonCodec();
final String pigeonVar_messageChannelSuffix;
Future<List<Object>> getMarkdown(List<String> htmlList) async {
final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoTurndownApi.getMarkdown$pigeonVar_messageChannelSuffix';
final BasicMessageChannel<Object?> pigeonVar_channel = BasicMessageChannel<Object?>(
pigeonVar_channelName,
pigeonChannelCodec,
binaryMessenger: pigeonVar_binaryMessenger,
);
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(<Object?>[htmlList]);
final List<Object?>? pigeonVar_replyList =
await pigeonVar_sendFuture as List<Object?>?;
if (pigeonVar_replyList == null) {
throw _createConnectionError(pigeonVar_channelName);
} else if (pigeonVar_replyList.length > 1) {
throw PlatformException(
code: pigeonVar_replyList[0]! as String,
message: pigeonVar_replyList[1] as String?,
details: pigeonVar_replyList[2],
);
} else if (pigeonVar_replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else {
return (pigeonVar_replyList[0] as List<Object?>?)!.cast<Object>();
}
}
}
class GeckoContainerProxyApi {
/// Constructor for [GeckoContainerProxyApi]. The [binaryMessenger] named argument is
/// available for dependency injection. If it is left null, the default
@@ -942,6 +942,12 @@ abstract class GeckoPrefApi {
void resetPrefs(List<String>? preferenceNames);
}
@HostApi()
abstract class GeckoTurndownApi {
@async
List<Object> getMarkdown(List<String> htmlList);
}
@HostApi()
abstract class GeckoContainerProxyApi {
void setProxyPort(int port);
@@ -15,7 +15,7 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
lint: ^2.6.1
lint: ^2.8.0
pigeon: ^24.2.1
# For information on the generic Dart part of this file, see the
@@ -19,7 +19,6 @@ linter:
unawaited_futures: true
discarded_futures: true
collection_methods_unrelated_type: true
require_trailing_commas: false
analyzer:
plugins:
+1 -1
View File
@@ -11,7 +11,7 @@ dependencies:
sqlite3_vec:
path: ../
sqlite3: ^2.7.4
sqlite3_flutter_libs: ^0.5.30
sqlite3_flutter_libs: ^0.5.31
dev_dependencies:
integration_test:
+1 -1
View File
@@ -15,7 +15,7 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
lint: ^2.6.1
lint: ^2.8.0
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec