The Web Design Group

... Making the Web accessible to all.

Welcome Guest ( Log In | Register )

 
Reply to this topicStart new topic
> Link to fragment - Help please
eagertoknow
post Jan 15 2024, 03:19 AM
Post #1





Group: Members
Posts: 6
Joined: 15-January 24
Member No.: 29,116



Not sure if this is the right place to ask this, but here goes:
I want to create a link to a specific text fragment of a web page that I highlight, so the user won't have to scroll through a potentially lengthy document and search for the fragment I want him to read. Instead, the page should scroll directly to the fragment.
I know there are various browser extensions like "Link to Fragment" and others that allegedly do the job, but they don't work for me (using Brave). They all rely on defining the fragment using the first and the last few words embedded in the generated link (using :~: after the hash sign).
However, someone knows a better way, and it works every time.
In one of his articles, he links to this, highlighted in the article: "the U.S. economy rose 4.24 times, the EU rose 3.90 times, and China rose 21.83 times, during that period from 1980 till 2022".
And here is the link he generated:
CODE

https://archive.is/rJfIP#selection-1183.224-1183.300

Going there will scroll the page to the fragment and highlight it.
The part up until the hash mark is just the address of the entire page he archived using archive.is.
The interesting part is what follows, starting with #selection.
It obviously identifies the start and end of the fragment.
I have never seen nor do I understand this syntax, and I have dug up all I could about fragments and linking to them.
The author seems to use direct coordinates without the need to embed text in the generated link. He didn't tell me how he does it, except "I select the fragment, move the cursor to the address bar, and copy the link from there." I don't know what browser he is using.
To put it differently: Why does the above link work, and what do the parameters mean?
Any help greatly appreciated.
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
coothead
post Jan 15 2024, 05:09 AM
Post #2


Advanced Member
****

Group: Members
Posts: 206
Joined: 12-January 23
From: chertsey, a small town 25 miles south west of london, england
Member No.: 28,743



QUOTE(eagertoknow @ Jan 15 2024, 09:19 AM) *

Any help greatly appreciated.



It appears to be done with javascript.

Embedded JavaScript from archive.is/rJfIP#selection-1183.224-1183.300
CODE

function showDivShare() {
  updateShareLinks();
  document.getElementById("DIVSHARE").style.display="block";
  return false;
}
function updateShareLinks() {
  var shortlink = "http://archive.is/rJfIP";
  var re = new RegExp(shortlink.replace(".", "\.") + "(#selection-[0-9.-]+)?");
  var adr = document.location.hash.match(/(selection-\d+\.\d+-\d+\.\d+)/);
  document.getElementById("SHARE_SHORTLINK").value = document.getElementById("SHARE_SHORTLINK").value.replace(re, adr ? shortlink + document.location.hash : shortlink);
  document.getElementById("SHARE_MARKDOWN" ).value = document.getElementById("SHARE_MARKDOWN" ).value.replace(re, adr ? shortlink + document.location.hash : shortlink);
  document.getElementById("SHARE_HTMLCODE" ).value = document.getElementById("SHARE_HTMLCODE" ).value.replace(re, adr ? shortlink + document.location.hash : shortlink);
  document.getElementById("SHARE_WIKICODE" ).value = document.getElementById("SHARE_WIKICODE" ).value.replace(re, adr ? shortlink + document.location.hash : shortlink);
}
function findXY(obj) {
  var cur = {x:0, y:0};
  while (obj && obj.offsetParent) {
    cur.x += obj.offsetLeft; // todo: + webkit-transform
    cur.y += obj.offsetTop; // todo: + webkit-transform
    obj = obj.offsetParent;
  }
  return cur;
}
function findXY2(obj, textpos) { // it could reset selection
  if (obj.nodeType==3) {
    var parent = obj.parentNode;
    var text = document.createTextNode(obj.data.substr(0, textpos));
    var artificial = document.createElement("SPAN");
    artificial.appendChild(document.createTextNode(obj.data.substr(textpos)));
    parent.insertBefore(text, obj);
    parent.replaceChild(artificial, obj);
    var y = findXY(artificial);
    parent.removeChild(text);
    parent.replaceChild(obj, artificial);
    return y;
  } else {
    return findXY(obj);
  }
}
var prevhash = "";
function scrollToHash() {
  if (document.location.hash.replace(/^#/, "")==prevhash.replace(/^#/, ""))
    return;
  prevhash = document.location.hash;
  if (document.location.hash.match(/#[0-9.]+%/)) {
    var p = parseFloat(document.location.hash.substring(1));
    if (0 < p && p < 100 /*&& p%5 != 0*/) {
      var content = document.getElementById("CONTENT")
      var y = findXY(content).y + (content.offsetHeight)*p/100;
      window.scrollTo(0, y-16);
    }
  }

  var adr = document.location.hash.match(/selection-(\d+)\.(\d+)-(\d+)\.(\d+)/);
  if (adr) {
    var pos=0,begin=null,end=null;
    function recur(e) {
      if (e.nodeType==1) pos = (pos&~1)+2;
      if (e.nodeType==3) pos = pos|1;
      if (pos==adr[1]) begin=[e, adr[2]];
      if (pos==adr[3]) end  =[e, adr[4]];
      for (var i=0; i<e.childNodes.length; i++)
        recur(e.childNodes[i]);
      if (e.childNodes.length>0 && e.lastChild.nodeType==3)
        pos = (pos&~1)+2;
    }
    var content = document.getElementById("CONTENT");
    recur(content.childNodes[content.childNodes[0].nodeType==3 ? 1 : 0]);
    if (begin!=null && end!=null) {
      window.scrollTo(0, findXY2(begin[0], begin[1]).y-8);

      if (window.getSelection) {
        var sel = window.getSelection();
        sel.removeAllRanges();
        var range = document.createRange();
        range.setStart(begin[0], begin[1]);
        range.setEnd  (  end[0],   end[1]);
        sel.addRange(range);
      } else if (document.selection) { // IE
      }
    }
  }
}
window.onhashchange = scrollToHash;
var initScrollToHashDone = false;
function initScrollToHash() {
  if (!initScrollToHashDone) {
    initScrollToHashDone = true;
    scrollToHash();
  }
}
window.onload = initScrollToHash;
setTimeout(initScrollToHash, 500); /* onload can be delayed by counter code */

//document.onselectionchange = /* only webkit has working document.onselectionchange */
document.onmousedown = document.onmouseup = function(e) {
  var newhash = "";
  if (window.getSelection) {
    var sel=window.getSelection();
    if (!sel.isCollapsed) {
      var pos=0,begin=[0,0],end=[0,0];
      var range=sel.getRangeAt(0);
      function recur(e) {
        if (e.nodeType==1) pos = (pos&~1)+2;
        if (e.nodeType==3) pos = pos|1;
        if (range.startContainer===e) begin=[pos, range.startOffset];
        if (range.endContainer  ===e) end  =[pos, range.endOffset  ];
        for (var i=0; i<e.childNodes.length; i++)
          recur(e.childNodes[i]);
        if (e.childNodes.length>0 && e.lastChild.nodeType==3)
          pos = (pos&~1)+2;
      }

      var content = document.getElementById("CONTENT");
      recur(content.childNodes[content.childNodes[0].nodeType==3 ? 1 : 0]);
      if (begin[0]>0 && end[0]>0) {
        newhash = "selection-"+begin[0]+"."+begin[1]+"-"+end[0]+"."+end[1];
      }
    }
  } else if (document.selection) { // IE
  }

  try {
    var oldhash = location.hash.replace(/^#/, "");
    if (oldhash != newhash) {
      prevhash = newhash; /* avoid firing window.onhashchange and scrolling */
      if (history.replaceState) {
        history.replaceState('', document.title, newhash.length>0 ? '#'+newhash : window.location.pathname);
      } else {
        if (newhash.length>0) location.hash = newhash;
      }
    }
  } catch(e) {
  }
};

var _tmr = window._tmr || (window._tmr = []);
_tmr.push({id: ""+63*44843, type: "pageView", start: (new Date()).getTime()});
(function (d, w, id) {
  if (d.getElementById(id)) return;
  var ts = d.createElement("script"); ts.type = "text/javascript"; ts.async = true; ts.id = id;
  ts.src = (d.location.protocol == "https:" ? "https:" : "http:") + "//top-fwz1.mail.ru/js/code.js";
  var f = function () {var s = d.getElementsByTagName("script")[0]; s.parentNode.insertBefore(ts, s);};
  if (w.opera == "[object Opera]") { d.addEventListener("DOMContentLoaded", f, false); } else { f(); }
})(document, window, "topmailru-code");
document.cookie="_ga=GA1.2.661111166."+Math.floor((new Date()).getTime()/1000)+";expires="+(new Date((new Date()).getTime()+2*60*60*1000)).toUTCString()+";path=/";




coothead
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
Christian J
post Jan 15 2024, 08:17 AM
Post #3


.
********

Group: WDG Moderators
Posts: 9,661
Joined: 10-August 06
Member No.: 7



Maybe I missed something in the OP, but normally no javascript is required: https://htmlhelp.com/faq/html/links.html#named-anchor

To highlight the content fragment, you can use the CSS :target pseudo-class: https://developer.mozilla.org/en-US/docs/Web/CSS/:target
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
coothead
post Jan 15 2024, 08:53 AM
Post #4


Advanced Member
****

Group: Members
Posts: 206
Joined: 12-January 23
From: chertsey, a small town 25 miles south west of london, england
Member No.: 28,743



QUOTE(Christian J @ Jan 15 2024, 02:17 PM) *

Maybe I missed something in the OP



Yes, you got that right. IPB Image

If you take a casual glance at the code that I posted
you will notice that it manipulates/creates a hash for
a particular section of the content.

My minor knowledge of javaScript does not allow me
to elucidate any further than that. IPB Image


coothead
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
Christian J
post Jan 15 2024, 10:34 AM
Post #5


.
********

Group: WDG Moderators
Posts: 9,661
Joined: 10-August 06
Member No.: 7



QUOTE(coothead @ Jan 15 2024, 02:53 PM) *

If you take a casual glance at the code that I posted
you will notice that it manipulates/creates a hash for
a particular section of the content.

Oh, site visitors are able to create hash URLs by highlighting arbitrary content? Yes, that sounds like javascript is required.
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
eagertoknow
post Jan 15 2024, 01:31 PM
Post #6





Group: Members
Posts: 6
Joined: 15-January 24
Member No.: 29,116



QUOTE(coothead @ Jan 15 2024, 08:53 AM) *

QUOTE(Christian J @ Jan 15 2024, 02:17 PM) *

Maybe I missed something in the OP



Yes, you got that right. IPB Image

If you take a casual glance at the code that I posted
you will notice that it manipulates/creates a hash for
a particular section of the content.

My minor knowledge of javaScript does no[/code]t allow me
to elucidate any further than that. IPB Image


coothead

coothead,
Thank you very much for the quick response.
It is actually a bit over my head: what I am looking for is not how to code it (I couldn't...) but what the syntax means (and how I could create such links from a browser myself). The browser understands it, yet I haven't encountered this syntax before.

Christian J,
Thanks for the input. However, with this syntax there seems to be no need for an anchor: the person whose link I quoted (or rather his browser) can create such links to fragments seemingly anywhere on a web page. Also, cautiously "nudging" the parameter value will grow/shrink the selection the link takes you to. It won't take just any change: at certain values the browser will just discard it and display the page as if the hash part weren't there.
For example:
CODE
https://archive.ph/Cr9Bn#selection-245.141-287.1

If you modify the first parameter to 245.144, the selection will indeed start 3 characters later.

This post has been edited by eagertoknow: Jan 15 2024, 01:33 PM
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
Christian J
post Jan 15 2024, 07:01 PM
Post #7


.
********

Group: WDG Moderators
Posts: 9,661
Joined: 10-August 06
Member No.: 7



QUOTE(eagertoknow @ Jan 15 2024, 07:31 PM) *

Christian J,
Thanks for the input. However, with this syntax there seems to be no need for an anchor: the person whose link I quoted (or rather his browser) can create such links to fragments seemingly anywhere on a web page.

Without looking too close on the script, I assume it creates an HTML element start tag with an ID attribute value at the start of the selected text, and also changes the URL hash value accordingly. Maybe a matching end tag of said HTML element is also added at the end of the selected text, so it will appear highlighted (though if the selected content spans say multiple text paragraphs or other block-level elements this might require some convoluted markup).
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
pandy
post Jan 15 2024, 09:48 PM
Post #8


🌟Computer says no🌟
********

Group: WDG Moderators
Posts: 20,733
Joined: 9-August 06
Member No.: 6



That's very neat! If it could be made into a bookmarklet that would be very useful.
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
eagertoknow
post Jan 15 2024, 11:57 PM
Post #9





Group: Members
Posts: 6
Joined: 15-January 24
Member No.: 29,116



QUOTE(Christian J @ Jan 15 2024, 07:01 PM) *

QUOTE(eagertoknow @ Jan 15 2024, 07:31 PM) *

Christian J,
Thanks for the input. However, with this syntax there seems to be no need for an anchor: the person whose link I quoted (or rather his browser) can create such links to fragments seemingly anywhere on a web page.

Without looking too close on the script, I assume it creates an HTML element start tag with an ID attribute value at the start of the selected text, and also changes the URL hash value accordingly. Maybe a matching end tag of said HTML element is also added at the end of the selected text, so it will appear highlighted (though if the selected content spans say multiple text paragraphs or other block-level elements this might require some convoluted markup).

The page to link to is not under Visitor's control. Whatever happens is done dynamically on his computer only. To sum it up, this is what happens:
Step 1: Visitor opens an arbitrary web page on the Internet. All he can do is read the page, he cannot edit the code.
Step 2: Visitor drags the mouse over part of that web page (selects that fragment)
Step 3: MIRACLE HAPPENS
Step 4: Visitor's address bar has the fragment reference like the one in my example, ready to be copied anywhere, for example into the text of an offline Word file on Visitor's computer)

"MIRACLE" seems to be an additional kind of fragment link, requiring no advance preparation (like an anchor) to be first made on the visited page. Browsers understand this syntax and scroll to the selection, so this must be part of the HTML standard, yet I have not seen this described anywhere I looked. If MIRACLE was some browser extension doing some coding, both the reader and the target site should have it for it to work, but they don't have it. It seems to be the easiest, most natural way of creating deep links.
I have no idea what the two values of the dot-separated value pairs identify in "#selection-245.141-287.1", apart from the fact the they must be start and end identifiers.
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
Christian J
post Jan 16 2024, 07:35 AM
Post #10


.
********

Group: WDG Moderators
Posts: 9,661
Joined: 10-August 06
Member No.: 7



QUOTE(eagertoknow @ Jan 16 2024, 05:57 AM) *

Step 1: Visitor opens an arbitrary web page on the Internet. All he can do is read the page, he cannot edit the code.

To work on arbitrary pages the script must exist in the visitor's browser, as an extension or bookmarklet. I don't know if any browser has a readymade functionality like this, but it sounds like a way better tool than most of the bloat they keep adding.

QUOTE
If MIRACLE was some browser extension doing some coding, both the reader and the target site should have it for it to work

I think only the browser or the site needs it. For example, the extension may generate an ID (and selected text) in the HTML on the page based on the URL hash, then "redirect" to the selected section of the page.

QUOTE
I have no idea what the two values of the dot-separated value pairs identify in "#selection-245.141-287.1", apart from the fact the they must be start and end identifiers.

It seems 245 and 287 in your example are HTML elements (you can even select images) while 141 and 1 are characters in text nodes in those elements (no idea what that means when you select an image though).

Try selecting say the first and and second character of a text paragraph, and you should get something like "#selection-xxx.0-xxx-1" in the URL hash.
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
pandy
post Jan 16 2024, 10:13 AM
Post #11


🌟Computer says no🌟
********

Group: WDG Moderators
Posts: 20,733
Joined: 9-August 06
Member No.: 6



I can only follow snips of the script. It seems that it first get the location of the selection in pixels (offsetLeft, offsetTop). But I don't follow how it makes that into something more useable.

User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
eagertoknow
post Jan 16 2024, 11:45 AM
Post #12





Group: Members
Posts: 6
Joined: 15-January 24
Member No.: 29,116



QUOTE(Christian J @ Jan 16 2024, 07:35 AM) *

QUOTE(eagertoknow @ Jan 16 2024, 05:57 AM) *

Step 1: Visitor opens an arbitrary web page on the Internet. All he can do is read the page, he cannot edit the code.

To work on arbitrary pages the script must exist in the visitor's browser, as an extension or bookmarklet. I don't know if any browser has a readymade functionality like this, but it sounds like a way better tool than most of the bloat they keep adding.

QUOTE
If MIRACLE was some browser extension doing some coding, both the reader and the target site should have it for it to work

I think only the browser or the site needs it. For example, the extension may generate an ID (and selected text) in the HTML on the page based on the URL hash, then "redirect" to the selected section of the page.

QUOTE
I have no idea what the two values of the dot-separated value pairs identify in "#selection-245.141-287.1", apart from the fact the they must be start and end identifiers.

It seems 245 and 287 in your example are HTML elements (you can even select images) while 141 and 1 are characters in text nodes in those elements (no idea what that means when you select an image though).

Try selecting say the first and and second character of a text paragraph, and you should get something like "#selection-xxx.0-xxx-1" in the URL hash.


Just based on gut feeling, I think web sites would not do this footwork to serve fragments (too much hassle, especially on busy sites), they'd be more likely to leave this to the visitor.
Treating "miracle" like a black box and nudging values up and down, I found this for 245.141-262.0 (notation: "#selection-A.B-C.D"):
"A", "C" -- the most sensitive parts: increasing/decreasing it by just 1 will cause the remote site to discard the # part (and select nothing).
"B" -- increment/decrement by 1 moves the beginning of the selection by 1 character
"D" -- same as "B", but for the end of the selection

This post has been edited by eagertoknow: Jan 16 2024, 11:48 AM
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
eagertoknow
post Jan 16 2024, 11:47 AM
Post #13





Group: Members
Posts: 6
Joined: 15-January 24
Member No.: 29,116



QUOTE(pandy @ Jan 16 2024, 10:13 AM) *

I can only follow snips of the script. It seems that it first get the location of the selection in pixels (offsetLeft, offsetTop). But I don't follow how it makes that into something more useable.

If it counts in pixels, wouldn't the numbers in the examples be too small?
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
pandy
post Jan 16 2024, 03:26 PM
Post #14


🌟Computer says no🌟
********

Group: WDG Moderators
Posts: 20,733
Joined: 9-August 06
Member No.: 6



It isn't that that shows up in the URLs. But the script seems to start with the pixel position.
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
Christian J
post Jan 16 2024, 06:17 PM
Post #15


.
********

Group: WDG Moderators
Posts: 9,661
Joined: 10-August 06
Member No.: 7



QUOTE(pandy @ Jan 16 2024, 04:13 PM) *

I can only follow snips of the script. It seems that it first get the location of the selection in pixels (offsetLeft, offsetTop). But I don't follow how it makes that into something more useable.

Seems the function scrollToHash() uses offsetTop to scroll down on the page (I assumed above the browser would scroll down automatically to the ID with the hash value, not why the script uses javascript scrolling instead). Didn't see what offsetLeft is used for at a quick glance either. unsure.gif
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
pandy
post Jan 16 2024, 08:38 PM
Post #16


🌟Computer says no🌟
********

Group: WDG Moderators
Posts: 20,733
Joined: 9-August 06
Member No.: 6



It's there. I don't think the pixel position is used when a user goes to the fragment. I think it's earlier, when the scripts finds the fragment. But there should be other ways, no? What do I know?
CODE

function findXY(obj) {
  var cur = {x:0, y:0};
  while (obj && obj.offsetParent) {
    cur.x += obj.offsetLeft; // todo: + webkit-transform
    cur.y += obj.offsetTop; // todo: + webkit-transform
    obj = obj.offsetParent;
  }
  return cur;
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
Christian J
post Jan 17 2024, 01:48 PM
Post #17


.
********

Group: WDG Moderators
Posts: 9,661
Joined: 10-August 06
Member No.: 7



QUOTE(pandy @ Jan 17 2024, 02:38 AM) *

It's there.

Yes, looks like scrollToHash() calls functions findXY() and findXY2().
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
eagertoknow
post Jan 18 2024, 11:29 AM
Post #18





Group: Members
Posts: 6
Joined: 15-January 24
Member No.: 29,116



QUOTE(Christian J @ Jan 17 2024, 01:48 PM) *

QUOTE(pandy @ Jan 17 2024, 02:38 AM) *

It's there.

Yes, looks like scrollToHash() calls functions findXY() and findXY2().

Christian J, pandy,
Thank you very much for looking into this.
I finally know where it works:
Where it works: archive.vn, archive.is (there might be others). Steps:
1. archive a page at either of these and open the archived copy, or just use the following sample URL and click out of the selection so nothing is selected.
CODE
https://archive.vn/XYi5x#selection-3253.0-3263.125

2. Drag your cursor over any part of the page -- as soon as you let go of the left button, the link to the fragment appears in the address bar, ready to be copied anywhere.

This syntax only works at those archival sites.
Archiving a page and selecting part of it will generate the working fragment link in the address bar, but it will only work on the archived page.
Opening the actual (non-archive) page, adding the #selection part to the end of the URL, and reloading the page doesn't work.
So it's not a standard syntax generally understood by browsers, as I assumed.
Still it would be nice to know how it works.
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post
pandy
post Jan 18 2024, 05:51 PM
Post #19


🌟Computer says no🌟
********

Group: WDG Moderators
Posts: 20,733
Joined: 9-August 06
Member No.: 6



Yes, it's all in the script. That archive site embeds it at the end of BODY when the page is archived. It also changes this line so it reflects the URL of the archived page.

CODE
var shortlink = "http://archive.vn/XYi5x";


If you click a link in http://archive.vn/XYi5x so you go to another archived page the line above will also change to reflect the current URL.
User is offlinePM
Go to the top of the page
Toggle Multi-post QuotingQuote Post

Reply to this topicStart new topic
2 User(s) are reading this topic (2 Guests and 0 Anonymous Users)
0 Members:

 



- Lo-Fi Version Time is now: 27th April 2024 - 07:14 AM