From 3bd7f8060417e614f5f06387ca0fbc7923f990ec Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Sat, 27 Jul 2024 10:34:14 +0200 Subject: [PATCH] Implement window.close for Chrome Partially fulfill #180 --- README.md | 1 + app/src/main/assets/GM.js | 9 ++++++ .../main/java/org/matrix/chromext/Listener.kt | 32 +++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/README.md b/README.md index e0b8c63..401e80a 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ Currently, ChromeXt supports almost all [Tampermonkey APIs](https://www.tampermo 5. @grant: GM_addStyle, GM_addElement, GM_xmlhttpRequest, GM_openInTab, GM_registerMenuCommand (shown in the `Resources` panel of eruda), GM_unregisterMenuCommand, GM_download, unsafeWindow (= window) 6. @grant: GM_setValue, GM_getValue (less powerful than GM.getValue), GM_listValues, GM_addValueChangeListener, GM_removeValueChangeListener, GM_setClipboard, GM_cookie, GM_notification 7. @require, @resource (without [Subresource Integrity](https://www.tampermonkey.net/documentation.php#api:Subresource_Integrity)) +8. window.close (implemented for most Chromium based browsers) These APIs are implemented differently from the official ones, please refer to the source files [Local.kt](app/src/main/java/org/matrix/chromext/script/Local.kt) and diff --git a/app/src/main/assets/GM.js b/app/src/main/assets/GM.js index 2801af0..6a6698e 100644 --- a/app/src/main/assets/GM.js +++ b/app/src/main/assets/GM.js @@ -35,6 +35,15 @@ function GM_addStyle(css) { } // Kotlin separator +window.close = new Proxy(window.close, { + apply(_target, _this, _args) { + const ChromeXt = LockedChromeXt.unlock(key); + ChromeXt.dispatch("close"); + return Reflect.apply(...arguments); + }, +}); +// Kotlin separator + const unsafeWindow = window; // Kotlin separator diff --git a/app/src/main/java/org/matrix/chromext/Listener.kt b/app/src/main/java/org/matrix/chromext/Listener.kt index 5790adc..1b92c60 100644 --- a/app/src/main/java/org/matrix/chromext/Listener.kt +++ b/app/src/main/java/org/matrix/chromext/Listener.kt @@ -36,6 +36,7 @@ import org.matrix.chromext.script.parseScript import org.matrix.chromext.utils.ERUD_URL import org.matrix.chromext.utils.Log import org.matrix.chromext.utils.XMLHttpRequest +import org.matrix.chromext.utils.findMethod import org.matrix.chromext.utils.invalidUserScriptUrls import org.matrix.chromext.utils.isChromeXtFrontEnd import org.matrix.chromext.utils.isDevToolsFrontEnd @@ -143,6 +144,37 @@ object Listener { if (isUserScript(url)) invalidUserScriptUrls.add(url!!) callback = "if (Symbol.ChromeXt) Symbol.ChromeXt.lock(${Local.key},'${Local.name}');" } + "close" -> { + val activity = Chrome.getContext() + if (currentTab != null && + activity::class.java == UserScriptProxy.chromeTabbedActivity && + !Chrome.isSamsung) { + val tab = Chrome.load("org.chromium.chrome.browser.tab.Tab") + val tabModel = Chrome.load("org.chromium.chrome.browser.tabmodel.TabModel") + val getCurrentTabModel = + findMethod(activity::class.java, true) { + parameterTypes.size == 0 && returnType == tabModel + } + val model = getCurrentTabModel.invoke(activity)!! + val closeTab = + findMethod(model::class.java) { + returnType == Boolean::class.java && + parameterTypes contentDeepEquals + arrayOf( + tab, + tab, + Boolean::class.java, + Boolean::class.java, + Boolean::class.java, + Int::class.java) + } + closeTab.invoke(model, currentTab, null, false, false, false, 0) + } else { + val msg = "Action close failed with tab ${currentTab} and context ${activity}" + Log.w(msg) + callback = "console.error('ChromeXt Error', ${msg});" + } + } "focus" -> { Chrome.updateTab(currentTab) }