Advertisement
shdon

GreaseMonkey user script to display HN comments side by side with the linked article

Jun 25th, 2024 (edited)
748
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 5.69 KB | Source Code | 0 0
  1. // ==UserScript==
  2. // @name        HN side-by-side
  3. // @namespace   https://www.shdon.com/
  4. // @description Show Hacker News linked articles and comments side by side.
  5. // @include     https://news.ycombinator.com/*
  6. // @run-at      document-end
  7. // @version     1.0.4
  8. // @grant       none
  9. // ==/UserScript==
  10. var sxs = {
  11.     "vpw" : window.innerWidth,
  12.     "resizing" : false
  13. };
  14.  
  15. function sxs_mousedown (event)
  16. {
  17.     event.stopPropagation ();
  18.     event.preventDefault ();
  19.     sxs.vpw = window.innerWidth;
  20.     sxs.resizing = true;
  21. }
  22.  
  23. function sxs_mousemove (event)
  24. {
  25.     if (!sxs.resizing) return;
  26.     event.stopPropagation ();
  27.     event.preventDefault ();
  28.    
  29.     //Calculate position
  30.     var x = event.clientX;
  31.     var pct = x * 100.0 / sxs.vpw;
  32.    
  33.     //Adjust elements accordingly
  34.     document.getElementById ('sxs-site').style.flexBasis = pct + '%';
  35.     document.getElementById ('sxs-hn').style.flexBasis = (100.0 - pct) + '%';
  36. }
  37.  
  38. function sxs_mouseup (event)
  39. {
  40.     if (!sxs.resizing) return;
  41.     event.stopPropagation ();
  42.     event.preventDefault ();
  43.     sxs.resizing = false;
  44. }
  45.  
  46. function sxs_add_styles ()
  47. {
  48.     //Don't allow double running
  49.     if (document.getElementById ('sxs-styles')) return;
  50.    
  51.     //Create style
  52.     var css = document.createElement ('STYLE');
  53.     css.id = 'sxs-styles';
  54.     css.type = 'text/css';
  55.     css.innerHTML = `
  56.         html:has(#sxs-site) { height: 100vh; margin: 0; overflow: hidden; padding: 0; width: 100vw; }
  57.         body:has(#sxs-site) { display: flex; flex-direction: row; height: 100vh; margin: 0; overflow: hidden; padding: 0; width: 100vw; }
  58.         #sxs-site { border: 0; flex: 1 1 50%; }
  59.         #sxs-divider { background: #CCC; border-inline: 1px solid #000; cursor: ew-resize; flex: 0 0 4px; overflow: visible; position: relative; }
  60.         .sxs-link { display: inline-block; font-size: 80%; font-weight: bold; margin-left: 1ex; }
  61.         #sxs-site ~ center { flex: 1 1 50%; margin: 0; overflow: auto; padding: 8px; }
  62.         #sxs-close { background: #CCC; border: 1px solid #111; border-radius: 50%; color: #111; height: 1.5em; left: 50%; line-height: 1.5em; position: absolute; text-align: center; top: 8px; transform: translateX(-50%); transition: background 0.5s ease; width: 1.5em; z-index: 1; }
  63.         #sxs-close:hover { background: #EEE; }
  64.         @media (prefers-color-scheme: dark) {
  65.             #sxs-divider { background: #222; border-color: #EEE; }
  66.             #sxs-close { background: #222; border-color: #EEE; color: #FFF; }
  67.             #sxs-close:hover { background: #444; }
  68.         }
  69.     `;
  70.     document.head.append (css);
  71. }
  72.  
  73. function sxs_activate ()
  74. {
  75.     //Don't allow double running
  76.     if (document.getElementById ('sxs-site')) return;
  77.    
  78.     //Get the URL
  79.     var sxs_url = document.querySelector('.titleline a').href;
  80.    
  81.     //Create a divider
  82.     var div = document.createElement ('DIV');
  83.     div.id = 'sxs-divider';
  84.     div.addEventListener ('mousedown', sxs_mousedown);
  85.     document.body.prepend (div);
  86.    
  87.     //Create the iframe
  88.     var ifr = document.createElement ('IFRAME');
  89.     ifr.id = 'sxs-site';
  90.     ifr.scrolling = 'auto';
  91.     ifr.src = sxs_url;
  92.     document.body.prepend (ifr);
  93.    
  94.     //Place the main HN comments side by side
  95.     var hn = document.body.querySelector (':scope > center');
  96.     hn.id = 'sxs-hn';
  97.    
  98.     //Divider event handlers
  99.     sxs.vpw = window.innerWidth;
  100.     sxs.resizing = false;
  101.    
  102.     //Add a close button
  103.     var closer = document.createElement ('A');
  104.     closer.id = 'sxs-close';
  105.     closer.innerHTML = '×';
  106.     closer.href = '#0';
  107.     closer.addEventListener ('click', function (event)
  108.     {
  109.         event.stopPropagation ();
  110.         event.preventDefault ();
  111.         sxs_deactivate ();
  112.     });
  113.     div.append (closer);
  114. }
  115.  
  116. function sxs_deactivate ()
  117. {
  118.     document.getElementById ('sxs-site').remove ();
  119.     document.getElementById ('sxs-divider').remove ();
  120.     document.getElementById ('sxs-close').remove ();
  121. }
  122.  
  123. (function ()
  124. {
  125.     //Only on suitable pages
  126.     var curpage = window.location.pathname;
  127.    
  128.     //Make sure styles are available
  129.     sxs_add_styles ();
  130.    
  131.     //Append SxS link to overview pages
  132.     if ([ '/', '/news', '/newest', '/past', '/show' ].indexOf (curpage) >= 0)
  133.     {
  134.         //Don't allow double running
  135.         if (document.querySelectorAll ('.sxs-link').length) return;
  136.        
  137.         //Find all titles
  138.         var titles = document.querySelectorAll ('.titleline');
  139.         titles.forEach (function (elem)
  140.         {
  141.             //Get information for link
  142.             var tr = elem.closest ('tr.athing[id]');
  143.            
  144.             //Check for a link to HN itself
  145.             var a = elem.querySelector (':scope a');
  146.             if (a.attributes['href'].nodeValue.substr (0, 8) === 'item?id=') return;
  147.            
  148.             //Create a side-by-side link
  149.             var link = document.createElement ('A');
  150.             link.className = 'sxs-link';
  151.             link.innerHTML = 'SxS';
  152.             link.href = 'https://news.ycombinator.com/item?sxs=1&id=' + encodeURIComponent (tr.id);
  153.             elem.append (link);
  154.         });
  155.     }
  156.    
  157.     //Include an iframe on the page
  158.     var search = window.location.search.substr (1).split ('&');
  159.     if (curpage == '/item')
  160.     {
  161.         if (!document.querySelectorAll ('.sxs-link').length)
  162.         {
  163.             //Allow activation after the fact
  164.             var title = document.querySelector ('.titleline');
  165.             var tr = title.closest ('tr.athing[id]');
  166.            
  167.             //Check for a link to HN itself
  168.             var a = title.querySelector (':scope a');
  169.             if (a.attributes['href'].nodeValue.substr (0, 8) === 'item?id=') return;
  170.            
  171.             //Create a side-by-side link
  172.             var link = document.createElement ('A');
  173.             link.className = 'sxs-link';
  174.             link.innerHTML = 'SxS';
  175.             link.href = '#0';
  176.             link.addEventListener ('click', function (event)
  177.             {
  178.                 event.stopPropagation ();
  179.                 event.preventDefault ();
  180.                 sxs_activate ();
  181.             });
  182.             title.append (link);
  183.         }
  184.        
  185.         if (search.indexOf ('sxs=1') >= 0)
  186.         {
  187.             //Activation by URL parameter
  188.             sxs_activate ();
  189.         }
  190.        
  191.         document.body.addEventListener ('mousemove', sxs_mousemove);
  192.         document.body.addEventListener ('mouseup', sxs_mouseup);
  193.     }
  194. })();
  195.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement