Better Stack Overflow

Replace time format and add share button to each answer

  1. // ==UserScript==
  2. // @name Better Stack Overflow
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.7
  5. // @description Replace time format and add share button to each answer
  6. // @author Landon Li
  7. // @match *://stackoverflow.com/questions/*
  8. // @match *://*.stackexchange.com/questions/*
  9. // @match *://superuser.com/questions/*
  10. // @match *://askubuntu.com/questions/*
  11. // @icon https://cdn.sstatic.net/Sites/stackoverflow/Img/favicon.ico
  12. // @grant none
  13. // ==/UserScript==
  14.  
  15. (function () {
  16. 'use strict';
  17.  
  18. function htmlToElement(html) {
  19. var template = document.createElement('template');
  20. html = html.trim(); // Never return a text node of whitespace as the result
  21. template.innerHTML = html;
  22. return template.content.firstChild;
  23. }
  24.  
  25. function arrayFromXPathResults(elements) {
  26. const array = Array.from({length: elements.snapshotLength}, (_, i) => elements.snapshotItem(i));
  27. return array;
  28. }
  29.  
  30. const replaceType1TimeSpan = async (span1) => { span1.innerText = span1.title };
  31. const replaceType2TimeSpan = async (span2) => { span2.innerText = span2.title.split(',')[0] };
  32. const addShareButton = async (div) => {
  33. var answerID = document.evaluate('./@id', div, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.value;
  34. var actionDiv = document.evaluate('./div[1]/div[1]/div[1]', div, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
  35. var shareLink = window.location.href.split('#')[0] + '#' + answerID;
  36. var shareDiv = htmlToElement('<div class="py6 mx-auto"><a href="#' + answerID + '" onclick="navigator.clipboard.writeText(\'' + shareLink + '\')">🔗</a></div>');
  37. actionDiv.appendChild(shareDiv);
  38. }
  39.  
  40. console.log('Replacing time format...');
  41. var type1TimeSpans = document.evaluate('//div[contains(@class,"user-action-time")]//span', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  42. arrayFromXPathResults(type1TimeSpans).forEach(async (span) => {
  43. await replaceType1TimeSpan(span);
  44. });
  45.  
  46. var type2TimeSpans = document.evaluate('//span[@class="comment-date"]//span', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  47. arrayFromXPathResults(type2TimeSpans).forEach(async (span) => {
  48. await replaceType2TimeSpan(span);
  49. });
  50.  
  51. console.log('Adding share buttons...');
  52. var answerDivs = document.evaluate('//div[@id="answers"]/div[contains(@id, "answer-")]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  53. arrayFromXPathResults(answerDivs).forEach(async (div) => {
  54. await addShareButton(div);
  55. });
  56.  
  57. })();