Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Wykop - losowe położenie plusów
- // @namespace wykop-losowe-plusy
- // @version 1.1.0
- // @description Umieszcza plusy wpisów i komentarzy w losowych miejscach na mikroblogu, stronach wpisów i profilach użytkowników.
- // @match https://wykop.pl/*
- // @run-at document-idle
- // @grant none
- // ==/UserScript==
- (() => {
- 'use strict';
- const positions = ['author', 'content', 'actions', 'top-right', 'bottom-right'];
- const placements = new WeakMap();
- const observerOptions = {
- childList: true,
- subtree: true,
- attributes: true,
- attributeFilter: ['class'],
- };
- let scheduled = false;
- const style = document.createElement('style');
- style.textContent = `
- :is(.microblog, .entry-page, .profile-page) .tm-plus-item .tm-random-plus {
- display: inline-flex !important;
- flex: 0 0 auto !important;
- width: max-content !important;
- margin: 0 !important;
- transform: none !important;
- }
- :is(.microblog, .entry-page, .profile-page) .tm-plus-item .tm-plus-floating {
- position: absolute !important;
- inset: auto !important;
- left: var(--tm-plus-left) !important;
- top: var(--tm-plus-top) !important;
- z-index: 2;
- }
- :is(.microblog, .entry-page, .profile-page) .tm-plus-header {
- position: relative !important;
- }
- :is(.microblog, .entry-page, .profile-page) .tm-plus-author,
- :is(.microblog, .entry-page, .profile-page) .tm-plus-actions {
- flex-wrap: wrap !important;
- height: auto !important;
- }
- :is(.microblog, .entry-page, .profile-page) .tm-plus-actions {
- display: flex !important;
- }
- .profile-page .tm-plus-author > .tm-plus-slot {
- margin-inline-end: 8px;
- vertical-align: middle;
- }
- :is(.microblog, .entry-page, .profile-page) .tm-plus-slot {
- display: inline-block;
- flex: 0 0 auto;
- pointer-events: none;
- }
- :is(.microblog, .entry-page, .profile-page) .tm-plus-item .tm-plus-row {
- display: flex !important;
- align-items: center;
- margin: 8px 0 0 34px;
- }
- :is(.microblog, .entry-page, .profile-page) .tm-plus-slot.tm-plus-top-right,
- :is(.microblog, .entry-page, .profile-page) .tm-plus-slot.tm-plus-bottom-right {
- margin-inline-start: auto !important;
- }
- `;
- document.head.append(style);
- function placeVoting(item) {
- const voting = item.querySelector('.voting, .rating-box');
- const username = item.querySelector(':scope > header .username');
- const footer = item.querySelector(':scope > footer, :scope > .edit-wrapper > footer');
- if (!voting || !username || !footer) {
- return;
- }
- const author = username.closest('.tooltip-slot') || username;
- const actions = footer.querySelector(':scope > .actions > ul') || footer;
- item.classList.add('tm-plus-item');
- let placement = placements.get(item);
- if (!placement) {
- const position = positions[Math.floor(Math.random() * positions.length)];
- placement = { position, voting: null, slot: null };
- placements.set(item, placement);
- resizeObserver.observe(item);
- }
- if (placement.voting !== voting) {
- if (placement.voting) {
- resizeObserver.unobserve(placement.voting);
- }
- placement.voting = voting;
- resizeObserver.observe(voting);
- }
- voting.classList.add('tm-random-plus');
- if (placement.position === 'author') {
- author.parentElement.classList.add('tm-plus-author');
- }
- if (placement.position === 'actions' || placement.position === 'bottom-right') {
- actions.classList.add('tm-plus-actions');
- }
- if (!placement.slot?.isConnected) {
- const inActions = placement.position === 'actions' || placement.position === 'bottom-right';
- const slot = document.createElement(inActions && actions.tagName === 'UL' ? 'li' : 'span');
- slot.className = 'tm-plus-slot';
- slot.setAttribute('aria-hidden', 'true');
- placement.slot = slot;
- switch (placement.position) {
- case 'author':
- author.before(slot);
- break;
- case 'top-right':
- slot.classList.add('tm-plus-top-right');
- const headerRight = item.querySelector(':scope > header > .right') || author.parentElement;
- headerRight.append(slot);
- break;
- case 'content': {
- const row = document.createElement('div');
- row.className = 'tm-plus-row';
- row.append(slot);
- footer.before(row);
- break;
- }
- case 'bottom-right':
- slot.classList.add('tm-plus-bottom-right');
- actions.append(slot);
- break;
- case 'actions':
- actions.prepend(slot);
- break;
- }
- }
- // Oryginalny element pozostaje na miejscu, żeby nie zakłócać aktualizacji Vue
- item.querySelector(':scope > header').classList.add('tm-plus-header');
- voting.classList.add('tm-plus-floating');
- const parent = voting.offsetParent;
- if (!parent) {
- return;
- }
- const { slot } = placement;
- const votingRect = voting.getBoundingClientRect();
- slot.style.width = `${votingRect.width}px`;
- slot.style.height = `${votingRect.height}px`;
- if (!slot.getClientRects().length) {
- voting.classList.remove('tm-plus-floating');
- return;
- }
- const slotRect = slot.getBoundingClientRect();
- const parentRect = parent.getBoundingClientRect();
- const left = slotRect.left - parentRect.left - parent.clientLeft + parent.scrollLeft;
- const top = slotRect.top - parentRect.top - parent.clientTop + parent.scrollTop;
- voting.style.setProperty('--tm-plus-left', `${left}px`);
- voting.style.setProperty('--tm-plus-top', `${top}px`);
- }
- function updateVoting() {
- scheduled = false;
- if (!/^\/(?:mikroblog|wpis|ludzie)(?:\/|$)/.test(location.pathname)) {
- return;
- }
- observer.disconnect();
- try {
- const items = document.querySelectorAll(
- ':is(.microblog, .entry-page, .profile-page) .thread > .item, .profile-page .entry > article',
- );
- for (const item of items) {
- placeVoting(item);
- }
- } finally {
- observer.observe(document.body, observerOptions);
- }
- }
- function scheduleUpdate() {
- if (scheduled) {
- return;
- }
- scheduled = true;
- requestAnimationFrame(updateVoting);
- }
- const observer = new MutationObserver(scheduleUpdate);
- const resizeObserver = new ResizeObserver(scheduleUpdate);
- observer.observe(document.body, observerOptions);
- updateVoting();
- })();
Advertisement