您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Infinite Scroll VOZ - Lướt voz.vn nhanh gọn như lướt facebook. https://github.com/ReeganExE/voz-infinite-scroll
// ==UserScript== // @name Infinite Scroll VOZ // @namespace https://voz.vn // @version 3.3.1846240259 // @description Infinite Scroll VOZ - Lướt voz.vn nhanh gọn như lướt facebook. https://github.com/ReeganExE/voz-infinite-scroll // @author Ninh Pham (ReeganExE), Nguyen Duy Tiep (green-leaves) // @match https://voz.vn/t/* // @grant GM_addStyle // ==/UserScript== GM_addStyle(` .hide {display: none} .show{display: block} .fixed-page { position: fixed; left: 13px; bottom: 20px; } .reply-form.hide .message-cell--main { display: none; } .reply-form { position: fixed; bottom: -800px; z-index: 100; border: solid 1px #616161; box-shadow: 1px 1px 10px 4px #585858; border-radius: 2px; -webkit-transition: bottom .2s ease-in-out; -moz-transition: bottom .2s ease-in-out; -o-transition: bottom .2s ease-in-out; transition: bottom .2s ease-in-out; } .reply-form .block-body { margin: 0; border: solid 1px #a5a5a5!important; } .reply-button { position: fixed; bottom: 30px; z-index: 100; right: 70px; } `); (function () { const PAGE_WRAPPER_SELECTOR = '.pageNav-main'; const POST_BODY_SELECTOR = '.js-replyNewMessageContainer'; const parser = new DOMParser(); const posts = document.querySelector(POST_BODY_SELECTOR); let currentPage = +getCurrentPage(); let lastPage = +getLastPage(); let isLoading = false; let threadId = ''; const PAGE_REG = /Page \d+/; const BUFFER_HEIGHT = 400; // Magic number, to load next page before reach the end. const loadingSpinHTML = '<div class="" style="width: 160px;margin: 0 auto;padding: 20px;text-align: center;color: white;">Loading... <img src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA=="/></div>'; const loadingSpin = document.createElement('div'); loadingSpin.innerHTML = loadingSpinHTML; loadingSpin.className = 'hide'; main({ getThreadId() { return location.pathname.match(/\/t\/.*\.(\d+)\/?/)[1]; } }); function main({ getThreadId }) { const pageNavWrappers = document.querySelectorAll(PAGE_WRAPPER_SELECTOR); if (pageNavWrappers.length) { pageNavWrappers[pageNavWrappers.length - 1].classList.add('fixed-page'); } // Reply form handleReplyForm(); function handleReplyForm() { const repyForm = document.querySelector('form.js-quickReply'); if (repyForm) { repyForm.classList.add('reply-form'); // Reply button const replyButton = htmlToElement(` <button type="button" class="button--primary button button--icon button--icon--reply reply-button"> <span class="button-text"> Ẩn/Hiện Reply </span> </button> `); const post = document.querySelector('.message.message--post.js-post.js-inlineModContainer'); repyForm.style.width = `${post.clientWidth}px`; let show = false; function hideReplyForm() { show = false; repyForm.style.bottom = '-800px'; } function showReplyForm() { show = true; repyForm.style.bottom = '40px'; } repyForm.addEventListener('keydown', (e) => { if (e.keyCode === 27) { hideReplyForm(); show = false; } }); replyButton.addEventListener('click', () => { show = !show; if (show) { showReplyForm(); } else { hideReplyForm(); } }); document.body.appendChild(replyButton); setTimeout(() => { jQuery(document).on('xf-click:before-click.XFQuoteClick', showReplyForm); }, 1000); } } if (posts) { const postsOffsetTop = getCoords(posts).top; threadId = getThreadId(); insertAfter(posts, loadingSpin); window.addEventListener('scroll', () => { if (window.scrollY + window.innerHeight + BUFFER_HEIGHT >= posts.offsetHeight + postsOffsetTop) { if (isLoadable()) { loadingSpin.className = 'show'; isLoading = true; loadThreadPage(threadId, ++currentPage, (loadedDoc) => { pushState(currentPage); posts.innerHTML += loadedDoc.querySelector(POST_BODY_SELECTOR).innerHTML; updatePageNavigator(loadedDoc); lastPage = getLastPage(loadedDoc); isLoading = false; loadingSpin.className = 'hide'; // Reintialize the events handler for quotes, reply, report, reaction XF.activate(posts); }); } } }); } } function pushState(currentPage) { let { title } = document; if (PAGE_REG.test(title)) { title = title.replace(PAGE_REG, `Page ${currentPage}`); } else { title = `${title} Page ${currentPage}`; } let [root] = location.href.split('/page-'); if (!root.endsWith('/')) { root += '/'; } root += `page-${currentPage}`; history.pushState({}, title, root + location.search); document.title = title; } function isLoadable() { return !isLoading && currentPage < lastPage; } function getCurrentPage() { const page = document.querySelector('.pageNav-main .pageNav-page--current'); return page ? Number(page.textContent.trim()) : 1; } function getLastPage(doc) { if (!doc) doc = document; const page = doc.querySelector('.pageNav-page:last-child a'); return page ? Number(page.textContent.trim()) : 1; } function updatePageNavigator(loadedDoc) { const pageNavs = document.querySelectorAll(PAGE_WRAPPER_SELECTOR); const newHtmlNav = loadedDoc.querySelector(PAGE_WRAPPER_SELECTOR).innerHTML; for (let i = 0; i < pageNavs.length; i++) { pageNavs[i].innerHTML = newHtmlNav; } } function getCoords(elem) { // crossbrowser version const box = elem.getBoundingClientRect(); const { body } = document; const docEl = document.documentElement; const scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop; const scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft; const clientTop = docEl.clientTop || body.clientTop || 0; const clientLeft = docEl.clientLeft || body.clientLeft || 0; const top = box.top + scrollTop - clientTop; const left = box.left + scrollLeft - clientLeft; return { top: Math.round(top), left: Math.round(left) }; } function loadThreadPage(threadId, pageNo, callback) { ajax('GET', `/t/ok.${threadId}/page-${pageNo}`, (xhr) => callback(parser.parseFromString(xhr.responseText, 'text/html'))); } function ajax(method, url, callback) { const xhr = new XMLHttpRequest(); xhr.open(method, url); xhr.send(null); xhr.onreadystatechange = function () { const DONE = 4; // readyState 4 means the request is done. const OK = 200; // status 200 is a successful return. if (xhr.readyState === DONE) { if (xhr.status === OK) { callback(xhr); } else { console.log(`Error: ${xhr.status}`); // An error occurred during the request. } } }; } function insertAfter(referenceNode, newNode) { referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); } /** * @param {String} HTML representing a single element * @return {Element} * @author https://stackoverflow.com/a/35385518/1099314 */ function htmlToElement(html) { const template = document.createElement('template'); html = html.trim(); // Never return a text node of whitespace as the result template.innerHTML = html; return template.content.firstChild; } })();