Guest User

Wykop - losowe położenie plusów

a guest
Oct 15th, 2026
7
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.69 KB | None | 0 0
  1. // ==UserScript==
  2. // @name Wykop - losowe położenie plusów
  3. // @namespace wykop-losowe-plusy
  4. // @version 1.0.0
  5. // @description Umieszcza plusy wpisów i komentarzy w losowych miejscach na mikroblogu i stronach pojedynczych wpisów.
  6. // @match https://wykop.pl/*
  7. // @run-at document-idle
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (() => {
  12. 'use strict';
  13.  
  14. const positions = ['author', 'content', 'actions', 'top-right', 'bottom-right'];
  15. const placements = new WeakMap();
  16. const observerOptions = {
  17. childList: true,
  18. subtree: true,
  19. attributes: true,
  20. attributeFilter: ['class'],
  21. };
  22. let scheduled = false;
  23.  
  24. const style = document.createElement('style');
  25. style.textContent = `
  26. :is(.microblog, .entry-page) .item .voting.tm-random-plus {
  27. display: inline-flex !important;
  28. flex: 0 0 auto !important;
  29. width: max-content !important;
  30. margin: 0 !important;
  31. transform: none !important;
  32. }
  33.  
  34. :is(.microblog, .entry-page) .item .voting.tm-plus-floating {
  35. position: absolute !important;
  36. inset: auto !important;
  37. left: var(--tm-plus-left) !important;
  38. top: var(--tm-plus-top) !important;
  39. z-index: 2;
  40. }
  41.  
  42. :is(.microblog, .entry-page) .tm-plus-header {
  43. position: relative !important;
  44. }
  45.  
  46. :is(.microblog, .entry-page) .tm-plus-author,
  47. :is(.microblog, .entry-page) .tm-plus-actions {
  48. flex-wrap: wrap !important;
  49. height: auto !important;
  50. }
  51.  
  52. :is(.microblog, .entry-page) .tm-plus-slot {
  53. display: inline-block;
  54. flex: 0 0 auto;
  55. pointer-events: none;
  56. }
  57.  
  58. :is(.microblog, .entry-page) .tm-plus-row {
  59. display: flex;
  60. align-items: center;
  61. margin: 8px 0 0 34px;
  62. }
  63.  
  64. :is(.microblog, .entry-page) .tm-plus-row-right {
  65. justify-content: flex-end;
  66. }
  67.  
  68. :is(.microblog, .entry-page) .tm-plus-slot.tm-plus-top-right {
  69. margin-inline-start: auto !important;
  70. }
  71. `;
  72. document.head.append(style);
  73.  
  74. function placeVoting(item) {
  75. const voting = item.querySelector('.voting');
  76. const username = item.querySelector(':scope > header .username');
  77. const footer = item.querySelector(':scope > footer');
  78.  
  79. if (!voting || !username || !footer) {
  80. return;
  81. }
  82.  
  83. let placement = placements.get(item);
  84.  
  85. if (!placement) {
  86. const position = positions[Math.floor(Math.random() * positions.length)];
  87. placement = { position, voting: null, slot: null };
  88. placements.set(item, placement);
  89. resizeObserver.observe(item);
  90. }
  91.  
  92. if (placement.voting !== voting) {
  93. if (placement.voting) {
  94. resizeObserver.unobserve(placement.voting);
  95. }
  96.  
  97. placement.voting = voting;
  98. resizeObserver.observe(voting);
  99. }
  100.  
  101. voting.classList.add('tm-random-plus');
  102.  
  103. if (placement.position === 'author') {
  104. username.parentElement.classList.add('tm-plus-author');
  105. }
  106.  
  107. if (placement.position === 'actions') {
  108. footer.classList.add('tm-plus-actions');
  109. }
  110.  
  111. if (!placement.slot?.isConnected) {
  112. const slot = document.createElement('span');
  113. slot.className = 'tm-plus-slot';
  114. slot.setAttribute('aria-hidden', 'true');
  115. placement.slot = slot;
  116.  
  117. switch (placement.position) {
  118. case 'author':
  119. username.before(slot);
  120. break;
  121.  
  122. case 'top-right':
  123. slot.classList.add('tm-plus-top-right');
  124. username.parentElement.append(slot);
  125. break;
  126.  
  127. case 'content':
  128. case 'bottom-right': {
  129. const row = document.createElement('div');
  130. row.className = 'tm-plus-row';
  131. row.append(slot);
  132.  
  133. if (placement.position === 'bottom-right') {
  134. row.classList.add('tm-plus-row-right');
  135. footer.after(row);
  136. } else {
  137. footer.before(row);
  138. }
  139.  
  140. break;
  141. }
  142.  
  143. case 'actions':
  144. footer.prepend(slot);
  145. break;
  146. }
  147. }
  148.  
  149. // Oryginalny element pozostaje na miejscu, żeby nie zakłócać aktualizacji Vue
  150. item.querySelector(':scope > header').classList.add('tm-plus-header');
  151. voting.classList.add('tm-plus-floating');
  152.  
  153. const parent = voting.offsetParent;
  154.  
  155. if (!parent) {
  156. return;
  157. }
  158.  
  159. const { slot } = placement;
  160. const votingRect = voting.getBoundingClientRect();
  161. slot.style.width = `${votingRect.width}px`;
  162. slot.style.height = `${votingRect.height}px`;
  163.  
  164. const slotRect = slot.getBoundingClientRect();
  165. const parentRect = parent.getBoundingClientRect();
  166. const left = slotRect.left - parentRect.left - parent.clientLeft + parent.scrollLeft;
  167. const top = slotRect.top - parentRect.top - parent.clientTop + parent.scrollTop;
  168.  
  169. voting.style.setProperty('--tm-plus-left', `${left}px`);
  170. voting.style.setProperty('--tm-plus-top', `${top}px`);
  171. }
  172.  
  173. function updateVoting() {
  174. scheduled = false;
  175.  
  176. if (!/^\/(?:mikroblog|wpis)(?:\/|$)/.test(location.pathname)) {
  177. return;
  178. }
  179.  
  180. observer.disconnect();
  181.  
  182. try {
  183. const items = document.querySelectorAll(':is(.microblog, .entry-page) .thread > .item');
  184.  
  185. for (const item of items) {
  186. placeVoting(item);
  187. }
  188. } finally {
  189. observer.observe(document.body, observerOptions);
  190. }
  191. }
  192.  
  193. function scheduleUpdate() {
  194. if (scheduled) {
  195. return;
  196. }
  197.  
  198. scheduled = true;
  199. requestAnimationFrame(updateVoting);
  200. }
  201.  
  202. const observer = new MutationObserver(scheduleUpdate);
  203. const resizeObserver = new ResizeObserver(scheduleUpdate);
  204.  
  205. observer.observe(document.body, observerOptions);
  206. updateVoting();
  207. })();
  208.  
Advertisement
Comments
  • User was banned
Add Comment
Please, Sign In to add comment