Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smart keywords, "window.location.hostname" and new tabs #42

Open
ericpa06 opened this issue May 11, 2022 · 7 comments
Open

Smart keywords, "window.location.hostname" and new tabs #42

ericpa06 opened this issue May 11, 2022 · 7 comments
Labels
enhancement New feature or request

Comments

@ericpa06
Copy link

ericpa06 commented May 11, 2022

Sorry if the title doesn't make much sense, I didn't know how to explain in a short manner. A better explanation would be, Firefox has the smart keyword thing, where you can associate some shortcuts and there are several codes you can apply to it. Like for instance, this one here, which searches the current site you are in on Google:

javascript:location.href=('http://www.google.com/search?q=site:'+window.location.hostname+'%20%s')

image_3298

01.mp4

So for instance, if I'm on hackernews, and press "s" [my search term] + enter, the command automatically does a google search on that page.

The thing that is that, if instead "enter", I pressed "shit+enter", to do the same thing I wanted to do previously, but instead opening the that search on a new tab, it doesn't work, it ignores the "window.location.hostname" part, so therefore you end up with something like this:

02.mp4

I couldn't find any bugzilla report on this, actually, I'm not even sure if is a bug to be fair, but is something that it might break some people workflow. Anyway, I was wondering if it would be possible to make, sorta firefox use that "window.location.hostname" reference even when pressing shit+enter so that you can perform that search and open it on a new tab.

Or maybe you know some other workaround through this issue, like through some editing on the very smartkeywords that I'm not seeing. I would also be interesting on that.

Also, as always sorry to bother you. And thanks in advance for any help or advice.

@ericpa06 ericpa06 added the enhancement New feature or request label May 11, 2022
@aminomancer
Copy link
Owner

Yeah I see what you mean. It's a good point, this is a very unfortunate limitation of the javascript scheme feature. So, it's not quite ignoring the hostname part, more like the hostname is just evaluating to an empty string. So that javascript location.href=('http://www.google.com/search?q=site:'+window.location.hostname+'%20%s') is basically saying to combine the string http://www.google.com/search?q=site: with the value of window.location.hostname and then append the string %20%s which is a space + the search string.

The problem is that the target browser (a new tab) is empty at the time this property's value is evaluated. Instead of checking the current browser's location, it's creating a new tab first, then loading the bookmark URL into it, which is parsing the javascript encoded in the URL, and that javascript is then checking the current browser's location — from within the new tab, where it's running. So because the javascript is loaded inside the context of a new tab instead of the current browser, the window refers to a completely different object with a different location property. Not really a simple way around this because the whole "opening a new tab" thing is way upstream of the execution of the JS code inside the bookmark URL. The sequence basically goes

  1. Hit Enter
  2. Open new tab
  3. Load parsed URI in the new browsing context
  4. Parsed URI is of javascript scheme...
  5. Evaluate the "path" of the URL string in the new browser
  6. That javascript evaluation references window.location.hostname which, from this execution context, refers to the empty browser we just opened. So it returns "" (empty string)
  7. The javascript further sets location.href equal to 'http://www.google.com/search?q=site:'+''+'%20%s'
  8. We therefore load http://www.google.com/search?q=site:%20%s which means the google input field should say site: {search string}

When you just hit Enter, you're basically executing the javascript in the current selected tab. So location.hostname returns the hostname for the current browser's doc. But when you use a modifier key, you're causing it to open the result in a new tab/window, which means a new browser. And the javascript URL is evaluated in the browsing context associated with that new browser. So at the time of execution it's gonna be an empty string I believe.

There might be solutions or workarounds though. It might seem like we could just change the behavior in some way so that these URLs are parsed in the parent process or something. The main issue I see is that we can't make assumptions about where the execution should happen. Even in just this one example, we need to execute inside the browser in which the content should load, because that's how the google search is initiated. See where it says location.href=...? That's how it's launching google. It just means change the URL to the following string.

But we can't have it both ways. For that to successfully change the URL of the new browser, it needs to be executed inside the new browser. But that means when we query location.hostname we're going to get the hostname for the new browser. So you can see the problem. We're asking for information about the current browser's location and then we're trying to use that information to set a new browser's location. So those would need to refer to the location property of 2 different window objects. But that's not possible from within the very restrictive context in which these javascript URLs run.

Technically I think it's possible to write a keyword bookmark in such a way that it will open a new tab, but that wouldn't have anything to do with whether a modifier key is pressed. It would just be the normal behavior of the bookmark. And that would be done by using something like javascript:window.open('http://www.google.com/search?q=site:'+window.location.hostname+'%20%s', '_blank'); location.href = location.href;. Unfortunately that reloads the current tab in addition to opening a new tab, which sucks. I don't think that's avoidable since this relies on a new URI being loaded in the first place.

Overall I just don't think the keyword bookmark feature is very practical for this kind of feature. I think an extension would have a much easier time doing something like this, though address bar extensions are quite rare. It would also be possible to make something like this with autoconfig, but it would need to be incredibly sophisticated to integrate with the urlbar. We'd need to basically let the user create a "bookmark" whose only content is parent-process JS instructions. That way we can create all the parameters before even making a new tab. But that would be quite a project. A new urlbar result provider, a new UI for creating templates, etc. I don't think I'll have enough down time to produce and maintain something so massive by myself.

I'll show this to a few people and see what they think. This is a pretty open-ended idea so I'm sure there are lots of possibilities I'm not thinking of.

@ericpa06
Copy link
Author

Thank you so much for your well-explained and well-defined spot on explanation.

@aminomancer
Copy link
Owner

Hey let me know if this new script does what you're looking for. You can use the same keyword bookmark, but just replace the URL field with this:

ucjs:let where = gURLBar._whereToOpen(event); openWebLinkIn("https://www.google.com/search?q=site:" + gBrowser.currentURI.host + " %{searchString}", where);

@ericpa06
Copy link
Author

Man, you are a LEGEND! Thank you so much!!! It worked flawlessly :)

@aminomancer
Copy link
Owner

Great 😊

@aminomancer
Copy link
Owner

Here try this instead. I improved the keyword code so it should feel more professional

ucjs:let where = gURLBar._whereToOpen(event); let typedValue = "%{searchString}"; let {host} = new URL(gBrowser.currentURI.spec); let pathString = typedValue.trim().length ? "/search?client=firefox-b-1-d&q=" : ""; let hostString = pathString && host && ["https", "http"].includes(gBrowser.currentURI.scheme) ? "site:" + host + " " : ""; gURLBar.handleRevert(); gURLBar.blur(); openWebLinkIn("https://www.google.com" + pathString + hostString + typedValue, where);

@aminomancer
Copy link
Owner

aminomancer commented Jun 19, 2022

Remind me to look into setting custom favicons for ucjs: bookmarks. I assume they are seeking icons with page-icon: or moz-anno:favicon: and since these aren't really URLs, we just get a default globe favicon. Ideally we'd intercept the creation of the bookmark somehow and give it a custom icon if it matches /^ucjs:/, like the console icon I set for the ucjs: urlbar results. Not sure if that's possible and I gotta crash but I'll look into that when I get a chance.

note: PlacesUIUtils.loadFavicon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants