-
Notifications
You must be signed in to change notification settings - Fork 9.7k
[url_launcher] Fixed missing # in links href when opening in new tab on the web #4221
[url_launcher] Fixed missing # in links href when opening in new tab on the web #4221
Conversation
|
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed (or fixed any issues), please reply here with What to do if you already signed the CLAIndividual signers
Corporate signers
ℹ️ Googlers: Go here for more info. |
|
@googlebot I signed it! |
|
Thanks for the submission.
Just because an end-to-end test may not be feasible does not mean a change can't have tests. You are transforming a property in a setter, which should be easily unit testable.
In the future, please don't check things in the checklist that you have not actually done. Asserting yourself that you don't think it needs a test isn't one of the options described here. |
|
You are fully right, @stuartmorgan. I definitely should not tick a checkbox then there is an unanswered question on it, and you are right with the getter too. Thank you for the reminder. I just added a corresponding test, and it's passing (at least on my local machine). |
| // in case an internal uri is given, a leading `#` must be added to avoid | ||
| // invalid links when opening in a new tab | ||
| if (!uri.hasScheme) { | ||
| href = '#' + href; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not entirely sure this is going to be true forever, for example, there's a new Uri Strategy that doesn't use the # and instead uses the browser history API.
/cc @mdebbar can you take a look at this fix and see if it can be applied as is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right @ditman. This works only with the HashUrlStrategy. If someone uses the PathUrlStrategy or any other custom url strategy, it won't work.
We need to figure out a way to grab the current url strategy used by the app, and call prepareExternalUrl to obtain the correct path that should go in the link href.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May you tell me whether my idea is right:
Would it be possible to somehow publicly make available _customUrlStrategy in engine:lib/web_ui/lib/src/engine/window.dart:38?
That way, the platform interface could check the present url strategy, right?
Would you mind if I create a corresponding getter in the file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Except of that it's nether public nor exported in the library, the UrlStrategy could be fetched from the web's platform dispatcher as in the following dummy code: EnginePlatformDispatcher.instance.(_windows[0]! as EngineFlutterWindow).browserHistory.urlStrategy; as depicted in engine:lib/web_ui/lib/src/engine/platform_dispatcher.dart:972
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@TheOneWithTheBraid: at the plugins level we can't know (for now) what's the URL strategy picked by the current app (even if we exposed that information from the engine, it'd take a few months for it to trickle down to the stable channel), to add a # or not.
However, programmers of web apps do know what type of links their web app needs.
As an alternative solution, have you tried setting your link widget with a URL similar to:
#/another/internal/route instead of /another/internal/route (I think this was the example in the originally reported issue)?
Is the problem then that when clicking on the URL it doesn't work?
I think it might be easier to teach the Link widget/Flutter framework to recognize those URLs when dealing with the onClick of the Link element, rather than attempting to "fix" the URL that the programmer is setting in links.
(Note that now we have 2 URL strategies, but if more end up being added, we might end up needing some extra behavior for each of them!)
Apologies if I'm misunderstanding the problem, but as far as I'm currently understanding this, I think we're attempting a fix in the wrong component!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it might be useful to access to current URL strategy anyway, right?
Yes, I don't have any problem with some of that information being exposed (or maybe a Link generator component that is compatible with the current URL strategy). The biggest problem of exposing these web-only APIs (for now) is that there's not a good place to expose them in a consistent way. (this is not a problem exclusive of this particular API, it's a flutter web issue in general!)
The purpose of the link is to work as a "normal" a href, with regards to clicking, copy-pasting and dragging to the address bar; we need to review that flutter is not doing "too much" with links for them to work (because the browser will not do that much)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May you tell me whether my idea is right:
Would it be possible to somehow publicly make available
_customUrlStrategyinengine:lib/web_ui/lib/src/engine/window.dart:38?That way, the platform interface could check the present url strategy, right?
Would you mind if I create a corresponding getter in the file?
Yes, this should work.
However, programmers of web apps do know what type of links their web app needs.
The idea is that inside your app, you don't need to know how the URL is represented in the browser. It could be a simple path /route or a hash path #/route or something completely different, depending on the url strategy. But your app shouldn't care about this difference. Only the url strategy needs to know about this (and you could implement your own url strategy if you want to customize this).
The url strategy has two methods to handle this:
-
prepareExternalUrl: converts an app route name to the path that goes in the browser url bar and<a>elements, etc. For example,HashUrlStrategy.prepareExternalUrladds a#to the beginning of the route name to make it a hash path. -
getPath: converts a path from the browser url bar to a route name for the app to consume. For example,HashUrlStrategy.getPathgets the hash part of the browser location, and strips the#from it.
(Note that now we have 2 URL strategies, but if more end up being added, we might end up needing some extra behavior for each of them!)
It doesn't matter how many url strategies there are (actually, users can create their own custom url strategies today, so we already have more than two). The Link widget shouldn't do any #-specific behavior/logic. It should just call UrlStrategy.prepareExternalUrl and let it handle the hash if necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe a Link generator component that is compatible with the current URL strategy
Ahh, there you go @mdebbar, the prepareExternalUrl from each strategy!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I now opened flutter/flutter#90708 exposing a getter required to call prepareExternalUrl. Let's wait for it to trickle down, I'd propose. Right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mdebbar I now use the newly implemented getter here. May you check whether my implementation is proper?
|
Marking as a draft to remove it from our review queue; please remove the draft designation once this can proceed on stable. |
|
Was the necessary change in 2.8? I see that the commit has some 2.8.0-*.pre tags, which suggest yes, but I know there were some version oddities on master. |
|
It seems like the |
|
The PR is now rebased on the current HEAD. It would be wonderful to have it merged before new conflicts occur. |
We don't merge unreviewed PRs; this PR has not been approved by any reviewer. |
- fix the the CHANGELOG in order to use the requestd past-tense statements Signed-off-by: TheOneWithTheBraid <[email protected]>
mdebbar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me! I would love for @ditman to take a look too in case there's some plugins-specific stuff that I missed.
Co-authored-by: Mouad Debbar <[email protected]>
ditman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If @mdebbar is happy, I'm happy. I checked that the minimum version of flutter is >=2.10.0 so this only resolves for users in a modern enough version of the stable channel.
Ship it!
…n new tab on the web (flutter/plugins#4221)
When using the
Linkwidget, it's theoretically possible to open the link in a new tab, e.g. by dragging the widget in the tab bar of modern browsers. In This case, up to now, an invalid route was formed, as the leading#from Flutters named routes is not included in the Anchor node'shref.List which issues are fixed by this PR. You must list at least one issue.
I'm not exactly sure whether it's possible to cover a behavior like drag outside of Flutter to a new tab in tests. As I don't think so, I left out such a test.
Pre-launch Checklist
dart format.)[shared_preferences]///).If you need help, consider asking for advice on the #hackers-new channel on Discord.