tftv keyboard shortcuts

Adds keyboard shortcuts for navigating forum pages on teamfortress.tv

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name        tftv keyboard shortcuts
// @namespace   Lense
// @description Adds keyboard shortcuts for navigating forum pages on teamfortress.tv
// @include     /^https?://(www\.)?teamfortress.tv/.*/
// @version     0.5.4
// @grant       none
// ==/UserScript==

// Toggle highlighting of focused post. With this off, there are no visual changes.
var focus_highlight = true;

/*
 * Style post with a highlight
 */
function focus_post(post) {
  if(!focus_highlight) {
    return;
  }
  post.style.background = "#fff";
  post.style.boxShadow = "1px 1px 8px";
  post.style.zIndex = "1";
}

/*
 * Reset style to normal
 */
function unfocus_post(post) {
  post.style.background = "";
  post.style.boxShadow = "";
  post.style.zIndex = "";
}

/*
 * Helper function to scroll to post by id
 */
function goto_post(id) {
  unfocus_post(document.getElementById(prev_post_id));
  prev_post_id = id;

  var post = document.getElementById(id);
  post.scrollIntoView();
  // Show upper border
  window.scrollBy(0,-1);
  // Highlight the current post
  focus_post(post);
}

/*
 * Update styles on plus/minus frag and send the http request
 * id is the post id
 * frag_action is either plus or minus
 */
function frag(id, frag_action) {
  var btn_container = document.querySelector('.post-frag-container[data-post-id="'+id+'"]');
  var type;
  if(btn_container.classList.contains("self")) {
    // This post doesn't actually have frags; it's the OP.
    type = "thread";
    btn_container = document.querySelector('.thread-frag-container' + (type=="post" ? '[data-'+type+'-id="'+id+'"]' : ''));
  } else {
    type = "post";
  }

  // Most of this is ripped+modified from tftv js
  var frag_status = btn_container.attributes["data-frag-status"].value;
  if(frag_status == 'neutral' && frag_action == 'plus' || frag_status == 'minused' && frag_action == 'minus')
    var diff = 1;
  if(frag_status == 'neutral' && frag_action == 'minus' || frag_status == 'plused' && frag_action == 'plus')
    var diff = -1;
  if(frag_status == 'minused' && frag_action == 'plus')
    var diff = 2;
  if(frag_status == 'plused' && frag_action == 'minus')
    var diff = -2;
  var frag_count_container = type=="post" ? btn_container.firstElementChild : btn_container.querySelector("#thread-frag-count");
  var new_frag_count = parseInt(frag_count_container.textContent, 10) + diff;
  frag_count_container.textContent = new_frag_count;
  if(type == "post") {
    btn_container.children[0].classList.remove("positive");
    btn_container.children[0].classList.remove("negative");
    btn_container.children[0].classList.remove("neutral");
    btn_container.children[0].classList.add(new_frag_count > 0 ? "positive" : (new_frag_count < 0 ? "negative" : "neutral"));
  }

  if(frag_status == 'plused' && frag_action == 'plus' || frag_status == 'minused' && frag_action == 'minus')
    new_status = 'neutral';
  if(frag_action == 'plus' && frag_status !== 'plused')
    new_status = 'plused';
  if(frag_action == 'minus' && frag_status !== 'minused')
    new_status = 'minused';
  btn_container.setAttribute("data-frag-status", new_status);

  var plus_classes = btn_container.querySelector("." + type + "-frag-btn.plus").classList;
  var minus_classes = btn_container.querySelector("." + type + "-frag-btn.minus").classList;
  if(frag_action == "plus") {
    if(plus_classes.contains("clicked")) {
      plus_classes.remove("clicked");
    } else {
      plus_classes.add("clicked");
    }
    minus_classes.remove("clicked");
  } else {
    if(minus_classes.contains("clicked")) {
      minus_classes.remove("clicked");
    } else {
      minus_classes.add("clicked");
    }
    plus_classes.remove("clicked");
  }

  var xmlhttp = new XMLHttpRequest();
  xmlhttp.onreadystatechange = function() {
    if(xmlhttp.readyState == XMLHttpRequest.DONE) {
      if(xmlhttp.status != 200) {
        alert('VOTE NOT SENT');
      }
    }
  }
  xmlhttp.open("POST", '/' + type + '/frag/' + (type=="post" ? id : btn_container.attributes["data-thread-id"].value) + '/' + frag_action, true);
  xmlhttp.send();
}

/*
 * Find the number of pages in the thread
 */
var pageList = document.querySelectorAll(".mod-page:not(.mod-to-top):not(.mod-to-bottom)");
var lastPage = pageList.length > 0 ? parseInt(pageList[pageList.length - 1].textContent) : 1;

var posts = document.querySelectorAll(".post");
focus_post(posts[0]);
var cur_post_index = 0;
var prev_post_id = posts[0].id;

/*
 * Handle keypresses
 */
document.onkeypress = function(e) {
  // Not entirely sure why this is useful, but it can't break anything that isn't already broken
  e = e || window.event;
  // Ignore keypresses in text boxes, but allow if nothing or a link is selected
  if(e.target.nodeName != "BODY" && e.target.nodeName != "A") {
    // Got keypress, but it's probably in a textbox, so ignore it
    return;
  }

  // Current page number
  var page = window.location.search == "" || parseInt(window.location.search.match("page=([0-9]*)")[1]);

  switch(e["key"]) {
    /*
     * Pages (left/right)
     */
    case "d":
      if(page != lastPage) {
        page = (page+1).toString();
        window.location.search = "?page=" + page;
      }
      break;
    case "a":
      if(page != 1) {
        page = (page-1).toString();
        window.location.search = "?page=" + page;
      }
      break;
    case "D":
      if(page != lastPage) {
        window.location.search = "?page=" + lastPage.toString();
      }
      break;
    case "A":
      if(page != 1) {
        window.location.search = "?page=1";
      }
      break;
    /*
     * Posts (up/down)
     */
    case "w":
      if(cur_post_index > 0) {
        cur_post_index--;
      }
      goto_post(posts[cur_post_index].id);
      break;
    case "s":
      if(cur_post_index < posts.length - 1) {
        cur_post_index++;
      }
      goto_post(posts[cur_post_index].id);
      break;
    case "W":
      cur_post_index = 0;
      goto_post(posts[cur_post_index].id);
      break;
    case "S":
      cur_post_index = posts.length - 1;
      goto_post(posts[cur_post_index].id);
      break;
    /*
     * Frags (+/-)
     */
    case "q":
      frag(posts[cur_post_index].id.slice(8), "plus");
      break;
    case "e":
      frag(posts[cur_post_index].id.slice(8), "minus");
      break;
  }};