BlackGlory / eternity

🌲 A minimalist JavaScript user script loader and manager for modern browsers.
MIT License
16 stars 3 forks source link

Support loading a script from *.user.js file #17

Open techygrrrl opened 1 month ago

techygrrrl commented 1 month ago

Other user script runners have the ability to auto-load a user script into the extension when visiting a *.user.js URL.

Would it be possible to add this feature to this extension?

Right now when I try to do this, I see this error, which is the same error I see when the extension is disabled.

image

BlackGlory commented 1 month ago

I'm not really interested in hijacking browser navigation, but the extension does need a way to import scripts.

The most likely option to be implemented would be to load the currently selected text into the editor via the context menu.

examosa commented 3 weeks ago

What about importing from a URL?

BlackGlory commented 3 weeks ago

What about importing from a URL?

The current UI design needs to be modified to support importing from URLs. I do not plan to provide a single-page dashboard, so I have to find a way to use the limited space of the popup window. Perhaps the easiest way is to change all text buttons to icon buttons to free up space.

examosa commented 3 weeks ago

Now that I think about it, importing from a URL is already technically possible using the @update-url tag. However, it currently seems to be broken.

To test it, I created a new script with the following content:

// ==UserScript==
// @name Google Translate Auto Languages
// @update-url https://update.greasyfork.org/scripts/378166/Google%20Translate%20Auto%20Languages.user.js
// @match *://translate.google.com/*
// ==UserScript==

When clicking the update button from the editor, nothing happens. Same goes for the "Update All Scripts" button from the popup.

I think it's because of the way applyPropertyDecorators is being used here which in turn is causing this to be undefined here at runtime.

BlackGlory commented 3 weeks ago

@examosa Just updated the code, should fix it. In the latest version, invalid scripts can be downloaded and saved. The extension lacks a good way to tell the user that the script is invalid.

examosa commented 3 weeks ago

I was still unable to update from the URL with the latest changes; I got it working locally by making the following change:

diff --git a/src/background/index.ts b/src/background/index.ts
index 1c5a576..8ba406d 100644
--- a/src/background/index.ts
+++ b/src/background/index.ts
@@ -90,14 +90,7 @@ createServer<IBackgroundAPI>(
   applyPropertyDecorators(
     api
   , Object.keys(api) as Array<keyof IBackgroundAPI>
-  , (fn: (...args: unknown[]) => unknown) => {
-      return async function (this: typeof api, ...args: unknown[]): Promise<unknown> {
-        // 等待初始化/迁移执行完毕
-        await launched
-
-        return await Reflect.apply(fn, this, args)
-      }
-    }
+  , (fn: (...args: unknown[]) => unknown) => (...args: unknown[]) => launched.then(fn.bind(api, ...args))
   ) as ImplementationOf<IBackgroundAPI>
 )
BlackGlory commented 3 weeks ago

I may be too tired, but they should be equivalent code. The only difference is that the first code uses this and the second code directly passes in the api object. Did you modify other parts of the code?

examosa commented 3 weeks ago

As originally written, the code is using a this parameter which only carries type information; the actual value of this still winds up as undefined at runtime because the async function is defined inside an arrow function where this is lexically bound. So each fn of api either has to be explicitly bound to api when invoked, or already bound to api before using applyPropertyDecorators e.g. with bind from your extra-proxy lib.

A smaller change to the same effect:

diff --git a/src/background/index.ts b/src/background/index.ts
index 1c5a576..39800a9 100644
--- a/src/background/index.ts
+++ b/src/background/index.ts
@@ -91,11 +91,11 @@ createServer<IBackgroundAPI>(
     api
   , Object.keys(api) as Array<keyof IBackgroundAPI>
   , (fn: (...args: unknown[]) => unknown) => {
-      return async function (this: typeof api, ...args: unknown[]): Promise<unknown> {
+      return async function (...args: unknown[]): Promise<unknown> {
         // 等待初始化/迁移执行完毕
         await launched

-        return await Reflect.apply(fn, this, args)
+        return await Reflect.apply(fn, api, args) // fn.apply(api, args) would also work
       }
     }
   ) as ImplementationOf<IBackgroundAPI>

It might also be a good idea to update applyPropertyDecorators to forward the this binding of value if it's a function; it could either pass obj as a second argument to propertyDecorator or invoke it using Function.prototype.call.

BlackGlory commented 3 weeks ago

@examosa Sadly, you are wrong. applyPropertyDecorators was actually designed with tests specifically for this use case, which you can find here: https://github.com/BlackGlory/extra-proxy/blob/master/__tests__/decorator.spec.ts, and the this in this code doesn't work the way you think, I don't want to give a JavaScript lecture here.

The real question is why the code that works in my browser doesn't work in yours.

examosa commented 3 weeks ago

Ah, you're right! I must have forgotten to reload the extension after rebuilding the first time 😅

Xdy1579883916 commented 3 weeks ago

@examosa

Although eternity uses a Meta similar to Greasemonkey, it does not fully support Greasemonkey's script Meta

Thanks to @BlackGlory for open source. vanilla-pudding borrows the idea and Code of ​​eternity. You are welcome to try it.

  1. First you need to create a new script, paste Meta in the editor, and save it(CTRL + S) image

  2. Refresh the editor page and you will find that the plugin is automatically converted into a compliant Meta image

  3. Yes. Next, we need to click Update, and the plugin will update the script content according to the @update-url address. Refresh the editor page to see the updated source code. image

I tested your script and it works fine on the Google Translate page ~