medium-helper

a simple Medium helper to improve reading experience.

  1. // ==UserScript==
  2. // @name medium-helper
  3. // @namespace https://github.com/taseikyo
  4. // @version 0.1.1
  5. // @icon https://cdn-static-1.medium.com/_/fp/icons/favicon-rebrand-medium.3Y6xpZ-0FSdWDnPM3hSBIA.ico
  6. // @description a simple Medium helper to improve reading experience.
  7. // @author Lewis Tian (https://github.com/taseikyo)
  8. // @match https://*.medium.com/*
  9. // @match https://blog.sourcerer.io/*
  10. // @match https://articles.microservices.com/*
  11. // @match https://towardsdatascience.com/*
  12. // @grant MIT
  13. // ==/UserScript==
  14.  
  15. "use strict";
  16. /**
  17. *
  18. * Copyright (c) 2019 Lewis Tian. Licensed under the MIT license.
  19. * @authors Lewis Tian (taseikyo@gmail.com)
  20. * @date 2019-07-30 10:39:19
  21. * @link https://github.com/taseikyo
  22. * @desc a simple Medium helper to improve reading experience:
  23. * 1. expand the reading area (728 -> 960)
  24. * 2. add a table of contents (hide/show according to scroll bar height)
  25. * 3. customize your own settings
  26. *
  27. */
  28. var CONFIG = {
  29. maxWidth: 960,
  30. likeBoxLeftFloat: 5,
  31. tocTop: 20,
  32. tocRight: 0,
  33. scrollTopShow: 300,
  34. scrollBottomHide: 1600,
  35. highlightedStart: 150,
  36. delay: 500
  37. };
  38. var main = function () {
  39. var root = document.querySelector('#root');
  40. if (root == null) {
  41. return;
  42. }
  43. var article = root.children[0].querySelector('article');
  44. if (article == null) {
  45. return;
  46. }
  47. // hand or bookmark
  48. var likeBox = article.nextSibling;
  49. // maybe there is a picture on the top of text, so we select the last node
  50. var section = article.querySelector('div').querySelector('section');
  51. var textBody = section.children[section.children.length - 1].children[0];
  52. likeBox.setAttribute('style', "left: -" + CONFIG.likeBoxLeftFloat + "% ");
  53. textBody.setAttribute('style', "max-width: " + CONFIG.maxWidth + "px !important");
  54. for (var _i = 0, _a = textBody.children; _i < _a.length; _i++) {
  55. var i = _a[_i];
  56. if (i.nodeName === 'h1' || i.nodeName === 'H1') {
  57. toc(textBody);
  58. break;
  59. }
  60. }
  61. setTimeout(delayHighlight, CONFIG.delay);
  62. };
  63. /**
  64. * add toc of the article
  65. *
  66. * @node: the arcile text div
  67. */
  68. var toc = function (node) {
  69. var anchorRoot = document.createElement('div');
  70. anchorRoot.className = 'BlogAnchor';
  71. var p = document.createElement('p');
  72. var a = document.createElement('a');
  73. a.href = '#';
  74. a.innerText = 'Table of contents';
  75. p.appendChild(a);
  76. anchorRoot.appendChild(p);
  77. var anchorBody = document.createElement('div');
  78. anchorBody.className = 'AnchorContent';
  79. anchorBody.id = 'AnchorContent';
  80. for (var _i = 0, _a = node.children; _i < _a.length; _i++) {
  81. var i = _a[_i];
  82. if (i.nodeName === 'h1' || i.nodeName === 'H1') {
  83. var li = document.createElement('li');
  84. var a_1 = document.createElement('a');
  85. a_1.href = "#" + i.id;
  86. a_1.innerText = i.innerText;
  87. li.appendChild(a_1);
  88. li.setAttribute('style', 'list-style-type: none; padding-right: 10px;');
  89. anchorBody.appendChild(li);
  90. }
  91. }
  92. var line = document.createElement('hr');
  93. anchorRoot.appendChild(line);
  94. anchorRoot.appendChild(anchorBody);
  95. // set style
  96. p.setAttribute('style', 'font-weight: bold; font-size: 1.2em;');
  97. anchorRoot.setAttribute('style', "position: fixed; right: " + CONFIG.tocRight + "%; top: " + CONFIG.tocTop + "%; background: #f4f7f9; padding: 10px; line-height: 180%;");
  98. document.getElementsByTagName('body')[0].appendChild(anchorRoot);
  99. anchorRoot.style.visibility = 'hidden';
  100. window.addEventListener('scroll', function (evt) {
  101. var scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
  102. if (scrollTop >= document.body.clientHeight - CONFIG.scrollBottomHide) {
  103. anchorRoot.style.visibility = 'hidden';
  104. }
  105. else if (scrollTop >= CONFIG.scrollTopShow) {
  106. anchorRoot.style.visibility = 'visible';
  107. }
  108. else {
  109. anchorRoot.style.visibility = 'hidden';
  110. }
  111. });
  112. };
  113. /**
  114. * set highlight text style
  115. * add margin according CONFIG
  116. */
  117. var delayHighlight = function () {
  118. var root = document.querySelector('#root');
  119. var article = root.children[0].querySelector('article');
  120. if (article == null) {
  121. return;
  122. }
  123. var highlightedBox = article.querySelector('aside');
  124. if (highlightedBox) {
  125. for (var _i = 0, _a = highlightedBox.children; _i < _a.length; _i++) {
  126. var x = _a[_i];
  127. x.querySelector('h4').setAttribute('style', "margin-inline-start: " + CONFIG.highlightedStart + "px; !important;");
  128. }
  129. }
  130. };
  131. // https://greatest.deepsurf.us/zh-CN/scripts/12877-字体样式美化/
  132. var pretty = function () {
  133. var css = document.createElement('style');
  134. var text = document.createTextNode('a:hover{color: #39F !important; text-shadow:-5px 3px 18px #39F !important; -webkit-transition: all 0.3s ease-out;}; a{-webkit-transition: all 0.3s ease-out;};*{text-decoration:none!important;font-weight:500!important;}*:not(i):not([class*="hermit"]):not([class*="btn"]):not([class*="button"]):not([class*="ico"]):not(i){font-family: "Microsoft Yahei", "Microsoft Yahei" !important; }*{text-shadow:0.005em 0.005em 0.025em #999999 !important;}');
  135. css.appendChild(text);
  136. document.getElementsByTagName('head')[0].appendChild(css);
  137. };
  138. pretty();
  139. main();