Habr hide cover image in spoiler

Hides cover image in spoiler; image is loaded on open.

  1. // ==UserScript==
  2. // @name Habr hide cover image in spoiler
  3. // @name:ru Хабр спрятать КДПВ в спойлер
  4. // @namespace habr_hide_cover_image
  5. // @version 1.1.2
  6. // @description Hides cover image in spoiler; image is loaded on open.
  7. // @description:ru Прячет КДПВ в спойлер; картинка загружается при открытии.
  8. // @author Dystopian
  9. // @license WTFPL
  10. // @match https://habr.com/*
  11. // @icon https://habr.com/favicon.ico
  12. // @grant none
  13. // ==/UserScript==
  14.  
  15. 'use strict';
  16.  
  17. const selectors = [
  18. 'div.tm-article-snippet__cover_cover.tm-article-snippet__cover:not(details div)',
  19. 'div.tm-article-snippet__cover.tm-article-snippet__cover_cover:not(details div)',
  20. 'div.article-formatted-body.article-formatted-body_version-1 a:not(details a)',
  21. ];
  22.  
  23. function hide(element) {
  24. const details = document.createElement('details');
  25. // details.className = 'spoiler';
  26. details.style.border = "1px dashed rgba(128, 128, 128, 0.5)";
  27. const summary = document.createElement('summary');
  28. summary.textContent = 'Hidden Image';
  29. element.parentNode.insertBefore(details, element);
  30. details.appendChild(summary);
  31. details.appendChild(element);
  32. details.addEventListener('toggle', () => {
  33. if (details.open) {
  34. details.querySelectorAll('img[data-src]:not([src])').forEach(img => {
  35. img.src = img.getAttribute('data-src');
  36. });
  37. }
  38. });
  39. }
  40. function check() {
  41. document.querySelectorAll('div.tm-article-body.tm-article-snippet__lead').forEach(parent => {
  42. selectors.forEach(selector => {
  43. parent.querySelectorAll(selector).forEach(element => {
  44. if (element.querySelector('img')) {
  45. element.querySelectorAll('img:not([data-src])').forEach(img => {
  46. img.setAttribute('data-src', img.src);
  47. img.removeAttribute('src');
  48. });
  49. hide(element);
  50. }
  51. });
  52. });
  53. parent.querySelectorAll('div.article-formatted-body.article-formatted-body_version-1 img:not(details img)').forEach(element => {
  54. if (!element.hasAttribute('data-src')) {
  55. element.setAttribute('data-src', element.src);
  56. element.removeAttribute('src');
  57. }
  58. hide(element);
  59. });
  60. });
  61. document.querySelectorAll('div.tm-post-snippet').forEach(parent => {
  62. parent.querySelectorAll('figure:not(details figure)').forEach(element => {
  63. if (element.querySelector('img')) {
  64. element.querySelectorAll('img:not([data-src])').forEach(img => {
  65. img.setAttribute('data-src', img.src);
  66. img.removeAttribute('src');
  67. });
  68. hide(element);
  69. }
  70. });
  71. });
  72. }
  73.  
  74. function ready(fn) {
  75. const { readyState } = document;
  76. if (readyState === 'loading') {
  77. document.addEventListener('DOMContentLoaded', () => {
  78. fn();
  79. });
  80. } else {
  81. fn();
  82. }
  83. }
  84.  
  85. ready(() => {
  86. check();
  87. const observer = new MutationObserver(() => {
  88. observer.disconnect();
  89. check();
  90. observer.observe(document.body, { childList: true, subtree: true });
  91. });
  92. observer.observe(document.body, { childList: true, subtree: true });
  93. });