您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
mark posts as read (помечает посты как прочитанные)
当前为
// ==UserScript== // @name vk.com mark as read // @namespace limizin.userscripts // @description mark posts as read (помечает посты как прочитанные) // @include https://vk.com* // @version 2.1 // @grant GM_setValue // @grant GM_getValue // ==/UserScript== (function() { var postwall = document.getElementById('page_wall_posts'); if (!postwall) return; globals = {}; globals.firefox = navigator.userAgent.toLowerCase().indexOf('firefox'); globals.postwall = postwall; globals.storageKey = 'usernameReadPost/' + hashCode(location.pathname) + hashCode(reverse(location.pathname)); globals.top_shadow_post_id = GM_getValue(globals.storageKey); globals.shadowMark = false; globals.maxAutoscrollPosts = 100; globals.autoscrolling = false; if (!document.querySelector('style#usernameReadPost')) { var head = document.querySelector('head'); stl = head.appendChild(document.createElement('style')); stl.id = 'usernameReadPost'; stl.innerHTML = '.usernameReadPost, .usernameReadPost ~ * {background-color: silver !important;} .usernameReadBtn {background-color: #507299; color: #ffffff; border: thin solid #C4C4C4; cursor: pointer;} .usernameReadPostBtn {top:0; right:0; position: absolute;}'; } var buttonBlock = document.createElement('div'); buttonBlock.style.display = 'inline'; buttonBlock.style.marginLeft = '-38px'; buttonBlock.style.marginRight = '7px'; buttonBlock.style.marginTop = '10px'; buttonBlock.style.float = 'left'; var scrollToReadBtn = createButton('>', scrollToRead, 'scroll to read'); scrollToReadBtn.style.width = '30px'; globals.scrollButton = scrollToReadBtn; buttonBlock.appendChild(scrollToReadBtn); document.querySelector('div.head_nav_item').appendChild(buttonBlock); //add buttons ol load _addButtons(document.querySelectorAll('div.wall_posts > div.post')); //shadow posts on load if (globals.top_shadow_post_id) { var post = document.getElementById(globals.top_shadow_post_id); if (post) { post.classList.add('usernameReadPost'); globals.shadowMark = true; } } //wall observer observer = new MutationObserver(onWallChange); var config = { attributes: false, childList: true, characterData: false }; observer.observe(globals.postwall, config); function onWallChange(mutations) { var newPosts = new Array(); mutations.forEach(function(mutation) { if (mutation.type != 'childList') return; if (mutation.addedNodes) { for (i = 0; i < mutation.addedNodes.length; i++) { var post = mutation.addedNodes[i]; if (post.classList.contains('no_posts')) continue; newPosts.push(post); } } }); if (newPosts) { _addButtons(newPosts); _shadowSubloadedPosts(newPosts); if (globals.autoscrolling) { scrollToRead(null); } } } function scrollToRead(event) { var post = document.querySelector('div.usernameReadPost'); if (post) { var postYOffset = post.offsetTop; var median = window.innerHeight / 2; var scrollTo = postYOffset - median; if (scrollTo < 0) { scrollTo = 0; } window.scrollTo(0, scrollTo); changeSrollState(false); } else { if (globals.maxAutoscrollPosts >= globals.postwall.childElementCount) { changeSrollState(true); var prevPostsBtn = document.getElementById('wall_more_link'); if (prevPostsBtn) { prevPostsBtn.click(); } } else { alert(globals.maxAutoscrollPosts + ' posts was scrolled. Read post not found.'); changeSrollState(false); } } } function changeSrollState(start) { if (start) { globals.autoscrolling = true; globals.scrollButton.textContent = '!'; globals.scrollButton.click = null; } else { globals.autoscrolling = false; globals.scrollButton.textContent = '>'; globals.scrollButton.click = scrollToRead; } } function _shadowSubloadedPosts(posts) { if (globals.shadowMark || !globals.top_shadow_post_id) { return; } for (var i = 0; i < posts.length; ++i) { var post = posts[i]; var postId = post.getAttribute('id'); if (postId == globals.top_shadow_post_id) { post.classList.add('usernameReadPost'); globals.shadowMark = true; break; } } } function markSelectedAsRead(event) { var xpath = './ancestor::div[contains(@class, "post") and not(@id="page_wall_posts")]'; var post = document.evaluate(xpath, event.currentTarget, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; if (post) { GM_setValue(globals.storageKey, post.getAttribute('id')); var prevPostsXpath = './preceding-sibling::div[contains(@class, "usernameReadPost")]'; var prevPosts = document.evaluate(prevPostsXpath, post, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0; i < prevPosts.snapshotLength; i++) { var prevPost = prevPosts.snapshotItem(i); prevPost.classList.remove('usernameReadPost'); } post.classList.add('usernameReadPost'); } } function _addButtons(posts) { for (var i = 0; i < posts.length; ++i) { var post = posts[i]; var btn = createButton('+', markSelectedAsRead, 'mark as read'); btn.classList.add('usernameReadPostBtn'); post.appendChild(btn); } } /////////// utils /////////// function hashCode(value) { var hash = 0; if (value.length == 0) return hash; for (i = 0; i < value.length; i++) { char = value.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash & hash; // Convert to 32bit integer } return hash; } function reverse(value) { return value.split('').reverse().join(''); } function xpathResultToArray(xpathResult) { var nodes = new Array(); var nextNode = xpathResult.iterateNext(); while (nextNode) { nodes.push(nextNode); nextNode = xpathResult.iterateNext(); } return nodes; } function createButton(content, handler, title) { var btn = document.createElement('button'); btn.textContent = content; btn.onclick = handler; btn.title = title; btn.className = 'usernameReadBtn'; if (globals.firefox) { btn.style.paddingBottom = '2px'; } return btn; } })();