vk.com mark as read

mark posts as read (помечает посты как прочитанные)

目前为 2017-03-03 提交的版本。查看 最新版本

// ==UserScript==
// @name        vk.com mark as read
// @namespace   limizin.userscripts
// @description mark posts as read (помечает посты как прочитанные)
// @include     https://vk.com*
// @version     1.1
// @grant       GM_setValue
// @grant       GM_getValue
// ==/UserScript==
(function () {
  postwall = document.getElementById('page_wall_posts');
  if (!postwall)
  return;
  if (!document.querySelector('style#usernameReadPost')) {
    stl = document.querySelector('head').appendChild(document.createElement('style'));
    stl.id = 'usernameReadPost';
    stl.innerHTML = '.usernameReadPost, .usernameReadPost ~ * {background-color: silver !important;}';
  } //----

  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('');
  }
  storageKey = 'usernameReadPost/' + hashCode(location.pathname)+hashCode(reverse(location.pathname));
  //top_shadow_post_id = window.localStorage.getItem(storageKey);
  top_shadow_post_id = GM_getValue(storageKey);
  //---
  function markRead() {
    sel = document.getSelection();
    if (!sel.isCollapsed) {
      var xpath = './ancestor::div[contains(@class, "post") and not(@id="page_wall_posts")]';
      var post = document.evaluate(xpath, sel.focusNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
      if (post) {
        post.className += ' usernameReadPost';
        //window.localStorage.setItem(storageKey, post.getAttribute('id'));
        GM_setValue(storageKey, post.getAttribute('id'));
        var prevPostsXpath = './preceding-sibling::div[contains(@class, "post")]';
        var prevPosts = document.evaluate(prevPostsXpath, post, null, XPathResult.ANY_TYPE, null);
        var prevPost = prevPosts.iterateNext();
        while (prevPost) {
          prevPost.className = prevPost.className.replace('usernameReadPost', '');
          prevPost = prevPosts.iterateNext();
        }
      }
    }
  }
  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);
    }
  }
  shadow = false;
  function shadowRead(event) {
    if (shadow || !top_shadow_post_id)
    return;
    var post = document.getElementById(top_shadow_post_id);
    if (post) {
      post.className += ' usernameReadPost';
      shadow = true;
      postwall.removeEventListener('DOMNodeInserted', shadowRead);
    }
  }
  function createButton(content, handler, title) {
    var btn = document.createElement('button');
    btn.textContent = content;
    btn.onclick = handler;
    btn.title = title;
    btn.style.backgroundColor = '#507299';
    btn.style.color = '#ffffff';
    btn.style.border = 'thin solid #C4C4C4';
    if (navigator.userAgent.toLowerCase().indexOf('firefox') > - 1) {
      btn.style.paddingBottom = '2px';
    }
    btn.style.cursor = 'pointer';
    return btn;
  }
  var buttonBlock = document.createElement('div');
  buttonBlock.style.display = 'inline';
  buttonBlock.style.marginLeft = '-60px';
  buttonBlock.style.marginRight = '7px';
  buttonBlock.style.marginTop = '10px';
  buttonBlock.style.float = 'left';
  //buttonBlock.style = 'margin-left: -60px; margin-right:7px; ';
  var scrollToReadBtn = createButton('>', scrollToRead, 'scroll to read');
  buttonBlock.appendChild(scrollToReadBtn);
  //mark read button
  var markReadBtn = createButton('+', markRead, 'mark as read');
  markReadBtn.style.borderLeft = 'none';
  buttonBlock.appendChild(markReadBtn);
  document.querySelector('div.head_nav_item').appendChild(buttonBlock);
  //post wall
  postwall.addEventListener('DOMNodeInserted', shadowRead);
  //run
  shadowRead(null);
}) ();