Avoid to generate a permalink for every clicked line number: migrate to web fragments
Summary:
Historically, when somebody visited a Paste or Diffusion `file` and clicked on a line number, we always constructed URIs in the format `file$45` as the link target for line number `45` in the line number column of document `file` (resp. `file$1-10` for lines 1-10), providing the ability to highlight one or several lines. Accessing this URI highlights the corresponding lines and automatically scrolls to the highlighted line(s) with a 60px top margin.
It is important to note that when `$45` is present in a URI, it is sent to the server (making a "permalink"), while `#45` would be not. So, a downside of using this permalink-based approach instead of standard `#` HTML anchor fragments ("web fragments") is that every URI obtained and shared around while clicking from the line number column in Paste and Diffusion file pages, that permalink `file$123` is technically a separate URI to be visited and downloaded compared to `file`. When you click on a line number and you share that permalink on a public comment, that permalink attracts crawlers, and they download that page again, even if crawlers already accessed that content. In an age of pirate AI trainers that scrape any permalink every second, it's better to adopt web fragments instead, so that they download your file once (or at least less often....), whatever the amount of comments you shared talking about lines.
As a solution:
* When clicking a single line, such as 123, generate a web fragment like `#L123` for the link target. This preserves line highlighting but vastly reduces the number of links a crawler could follow when it reaches such URIs, e.g., when a user mentions that line `#L123` from a comment.
* When clicking on multiple lines 123-124, also use web fragments like `#L123-124`.
* When receiving legacy visits to `$123` or `$L123-124`, it still works; we have not introduced link rot. However, if you visit these and if you click again on a different line, you get the new fragment-based URI.
Don't panic. Note that the previous situation was not extremely bad anyway, as the Paste or Diffusion did __not__ really allow a permalink to be found for each line anyway. A click was still needed to generate such permalink and a human being was still needed to share such permalink somewhere (e.g. a comment).
Note that this modification cannot replace all comments previously shared by human beings, and they probably shouldn't.
Note that Phorge cannot travel back in time, and we cannot obliviate crawlers to do not try to visit anymore old `$123` URIs. At least the promise is that your coworkers will not generate any more of these additional permalinks, and no link is broken.
See T15670
Closes T16100
Test Plan:
About the new feature:
* Go to http://phorge.localhost/P1, click on line number 11, see that highlighting still works and URL in the address bar becomes http://phorge.localhost/P1#L11 without a page reload
* Access URL http://phorge.localhost/P1#L13 and see that position scrolling by the browser works as expected
* Go to http://phorge.localhost/P1, click on line number 11 and drag to number 17, see that highlighting still works as before and URL in the address bar becomes http://phorge.localhost/P1#L11-17
* Go to http://phorge.localhost/P1#L11-17 directly, still works
* Go to http://phorge.localhost/P1#L17-11 (that is, first 17, then 11) and you just highlighted from line 11 to 17 successfully, like above, no nuclear crash
* Go to http://phorge.localhost/P1#LMIAAAO and really nothing special happens, no crash, just a nonsense web fragment
* Go to http://phorge.localhost/P1#L2-99999999999 and you highlight only the existing lines, without JavaScript burnout
About possible regressions:
* Access URL http://phorge.localhost/P1$9 and see that highlighting and position scrolling by the server-side JS still works as expected
* Access URL http://phorge.localhost/P1$9-16 and see that highlighting and position scrolling by the server-side JS still works as expected
* Access URL http://phorge.localhost/P1$16-9, same as above
* Access the above legacy URIs and click again on another line number, e.g. 2, and you get the new URIs with fragments (no silly things like `P1$9#2`, but just `P1#L2`)
----
For both, perform the same tests in a source code file rendered in Diffusion. Same results.
----
As additional test, you can define the new JavaScript functions in your browser console. E.g. copy-pasting this:
```javascript
var _parseLineNumber = function(vRaw) { ....
var parseMinMaxSelectedLineFromFragment = function(input) { ...
```
Then, test if JavaScript can recognize the fragment interval:
```
$ parseMinMaxSelectedLineFromFragment("L123")
Array [ 123, 123 ]
```
```
$ parseMinMaxSelectedLineFromFragment("L2-50")
Array [ 2, 50 ]
```
```
$ parseMinMaxSelectedLineFromFragment("L50-2")
Array [ 2, 50 ]
```
Also test some nonsense inputs, and they successfully crash:
```lang=javascript,counterexample
$ // Test nonsense line.
$ parseMinMaxSelectedLineFromFragment("LMIAO")
Uncaught Input fragment parts must be positive integer. Got: MIAO debugger eval code:11:70
_parseLineNumber debugger eval code:11
parseMinMaxSelectedLineFromFragment debugger eval code:42
```
```lang=javascript,counterexample
$ // Test nonsense zero line.
$ parseMinMaxSelectedLineFromFragment("L123-0")
Uncaught Input fragment parts must be positive integer. Got: 0 debugger eval code:11:70
_parseLineNumber debugger eval code:11
parseMinMaxSelectedLineFromFragment debugger eval code:43
```
```lang=javascript,counterexample
$ // Test nonsense negative line.
$ parseMinMaxSelectedLineFromFragment("L-123")
Uncaught Input fragment parts must be positive integer. Got: debugger eval code:11:70
_parseLineNumber debugger eval code:11
parseMinMaxSelectedLineFromFragment debugger eval code:42
```
Note: these crashes are __not__ shown to end-users while using Phorge. These exceptions are only for test plan lovers, and for developers.
So we recognize correct web fragments, and discard nonsense ones. Giving backward compatibility.
Reviewers: O1 Blessed Committers, aklapper, mainframe98
Reviewed By: O1 Blessed Committers, mainframe98
Subscribers: mainframe98, tobiaswiese, valerio.bozzolan, Matthew, Cigaryno
Maniphest Tasks: T16100
Differential Revision: https://we.phorge.it/D25569
authored by