Несколько дней назад, @vconst написал пост «Верни трекер, Хабр! (С)» с воззваниями по поводу изменения функциональности трекера в новой версии Хабра.
У меня возникла идея, что используя только расширение браузера возможно реализовать трекер с фактически любой функциональностью.
В качестве Proof-of-Concept, я попробовал самую простую идею, добавить старую версию трекера в правый сайдбар. Всё получилось даже проще, чем казалось.
Исходный код скрипта
(function () { function injectTracker() { const MAX_TRACKS = 10; // To add the tracker as a first block on the right sidebar, change "false" to "true" const insertAsFirstBlock = false; // set "true" if you want to tract articles only with unseen comments const onlyWithUnseenComments = false; // styling const trackerBlockCss = `<style scoped> .post-info__title a { color: #444; } a[href*="#comments"] { color: #82a3b1; } a[href*="#first_unread"] { color: #cf0000; } span.tracker { position: absolute; right: 0; } span.remove-tracker { position: absolute; right: 0; display: none; } li:hover > .post-info__title span.remove-tracker { display: inline-block; color: #888; } .post-info__title:hover span.remove-tracker:hover { color: #444; } .tracker-refresh-icon { cursor: pointer; } .icon-anim { animation-name: rotate; animation-duration: 1s; animation-iteration-count: infinite; animation-timing-function: linear; animation-play-state: running; } </style>`; const deleteSvg = '<svg class="delete-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" style="vertical-align: middle;" height="16" width="16"><path d="m16.5 33.6 7.5-7.5 7.5 7.5 2.1-2.1-7.5-7.5 7.5-7.5-2.1-2.1-7.5 7.5-7.5-7.5-2.1 2.1 7.5 7.5-7.5 7.5ZM24 44q-4.1 0-7.75-1.575-3.65-1.575-6.375-4.3-2.725-2.725-4.3-6.375Q4 28.1 4 24q0-4.15 1.575-7.8 1.575-3.65 4.3-6.35 2.725-2.7 6.375-4.275Q19.9 4 24 4q4.15 0 7.8 1.575 3.65 1.575 6.35 4.275 2.7 2.7 4.275 6.35Q44 19.85 44 24q0 4.1-1.575 7.75-1.575 3.65-4.275 6.375t-6.35 4.3Q28.15 44 24 44Zm0-3q7.1 0 12.05-4.975Q41 31.05 41 24q0-7.1-4.95-12.05Q31.1 7 24 7q-7.05 0-12.025 4.95Q7 16.9 7 24q0 7.05 4.975 12.025Q16.95 41 24 41Zm0-17Z"/></svg>'; const refeshSvg = '<svg class="tracker-refresh-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" style="vertical-align: middle;" height="20" width="20" ><path d="M24 40q-6.65 0-11.325-4.675Q8 30.65 8 24q0-6.65 4.675-11.325Q17.35 8 24 8q4.25 0 7.45 1.725T37 14.45V8h3v12.7H27.3v-3h8.4q-1.9-3-4.85-4.85Q27.9 11 24 11q-5.45 0-9.225 3.775Q11 18.55 11 24q0 5.45 3.775 9.225Q18.55 37 24 37q4.15 0 7.6-2.375 3.45-2.375 4.8-6.275h3.1q-1.45 5.25-5.75 8.45Q29.45 40 24 40Z"/></svg>'; const oldTrackerBlock = animateRefreshIcon(); fetch('https://habr.com/ru/tracker/') .then(response => response.text()) .then(response => processTracker(response)); function processTracker(response) { const m = response.match(/<form[^>]+id="tracker_feed_form"[^>]*>(.*?)<\/form>/s); if (!m) return; const d = document.querySelector('.sidebar_right'); if (!d) return; oldTrackerBlock?.parentNode.removeChild(oldTrackerBlock); const parseDiv = document.createElement("div"); parseDiv.innerHTML = m[1]; const newDiv = addNewElement(d, 'div', 'default-block default-block_sidebar block-tracker', trackerBlockCss, insertAsFirstBlock); const headerDiv = addNewElement(newDiv, 'div', 'default-block__header', '<h3 class="default-block__header-title"><a href="https://habr.com/ru/tracker/" target="_blank">Tracker</a> <span class="tracker-refresh-btn" >' + refeshSvg + '</span></h3> '); headerDiv.querySelector('.tracker-refresh-btn').addEventListener('click', injectTracker); const newContent = addNewElement(newDiv, 'div', 'default-block__content'); const newUl = addNewElement(newContent, 'ul', 'content-list content-list_most-read'); let currentTrack = 0; [...parseDiv.querySelectorAll('table.tracker-table tr')].filter(el => { if (currentTrack >= MAX_TRACKS) return false; currentTrack += addTrack(el, newUl); }); if (currentTrack === 0) addNewElement(newContent, 'div', '', onlyWithUnseenComments ? 'No articles with new comments' : '<a href="https://habr.com/ru/tracker/" target="_blank">No articles to track</a>'); parseDiv.remove(); } function addTrack(el, newUl) { let firstTd = el.querySelector('td:nth-child(1)'); if (!firstTd) return 0; const trackerHtml = el.querySelector('td:nth-child(3)')?.innerHTML; if (onlyWithUnseenComments && !trackerHtml?.includes('+')) return 0; const newLi = addNewElement(newUl, 'li', 'content-list__item content-list__item_devided post-info'); const newTopDiv = addNewElement(newLi, 'div', 'tracker-stats-info'); addNewElement(newTopDiv, 'span', 'post_author', firstTd?.innerHTML.replaceAll('<a ', '<a target="_blank" ')); addNewElement(newTopDiv, 'span', 'tracker', trackerHtml.replaceAll('<a ', '<a target="_blank" ')); const newPost = addNewElement(newLi, 'div', 'post-info__title', el.querySelector('td:nth-child(2)')?.innerHTML.replaceAll('<a ', '<a target="_blank" ') + `<span class="remove-tracker" title="Remove from tracker">${deleteSvg}</span>`); newPost.querySelector('.remove-tracker').addEventListener('click', removeTracker); return 1; } function removeTracker(event) { const arctileEl = event.currentTarget.parentNode.querySelector('* > a'); if (!arctileEl) return; const m = arctileEl.getAttribute('href')?.match(/\/([0-9]+)\//); if (!m) return; const postId = m[1]; event.currentTarget.classList.add('icon-anim'); fetch('https://habr.com/json/tracker/feed/remove/', { method: 'POST', body: `post[${postId}]=on`, headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' } }).then(() => injectTracker()); } function addNewElement(parentElement, tageName, className, html, makeAsFirstChild) { const newEl = document.createElement(tageName); if (makeAsFirstChild) parentElement.insertBefore(newEl, parentElement.firstChild); else parentElement.appendChild(newEl); if (className) newEl.className = className; if (html) newEl.innerHTML = html; return newEl; } function animateRefreshIcon() { let oldTrackerBlock = document.querySelector('div.block-tracker'); if (oldTrackerBlock) document.querySelector('.tracker-refresh-icon')?.classList.add('icon-anim'); return oldTrackerBlock; } } injectTracker(); })();
Если вы используете Greasemonkey или подобное расширение, то можете добавить этот скрипт для сайта хабра и на каждой странице у вас будет новая секция «tracker».
Я использую кастомизированный HabrSanitizer и если вы также его поклонник и хотели бы добавить функциональность трекера к нему, то надо загрузить исходники к себе на локальный компьютер, добавить его в качестве локального расширения (Load Unpacked) и вставить код скрипта перед строчкой (на сегодня это строка 397)
const isOnPersonalPage = onPersonalPage(window.location.href);
Можно протестировать функциональность и без установки расширения. На любой странице хабра нужно открыть DevTools и вставить код этого скрипта в Console. Но конечно это единовременное изменение страницы и при навигации со страницы, трэкер блок будет удалён и на новой странице необходимо будет повторить процедуру ещё раз.
Ещё раз — это скрипт работает только для старой версии интерфейса хабра.
Если всё сделано правильно то вы увидете под блоком «Читают сейчас» новый блок, «Tracker».
Что-то типа:

Следующий шаг будет попробовать что-то типа этого для новой версии.
Единственная проблема, это то что продётся читать не одну дополнительную страницу, а десять или более. Так что чтобы не генерировать избыточную нагрузку, может быть Хабру имеет смысл не бороться с пользователями, а прислушаться и мигрировать старый трекер на новый интерфейс. Это должно быть довольно просто.
Всем удачных выходных!
ссылка на оригинал статьи https://habr.com/ru/post/699036/
Добавить комментарий