agentOfChaos / Banana-O-meter

// ==UserScript==
// @name        Banana-O-meter
// @namespace   chaos
// @description Add a nifty scroll distance meter to your 9gag navbar
// @include     http://9gag.com/*
// @version     1.3
// @license     MIT
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_registerMenuCommand
// ==/UserScript==

// helper function for displaying float numbers
function precision(numfloat, pow10)
{
  return Math.round(numfloat * pow10) / pow10;
}
function log_man(num)
{
  var scaled_val;
  var unit = "";
  var pten = Math.log10(num);
  if (pten > 12)
    {
      scaled_val = num / Math.pow(10,12);
      unit = "T";
    }
  else if (pten > 9)
    {
      scaled_val = num / Math.pow(10,9);
      unit = "G";
    }
  else if (pten > 6)
    {
      scaled_val = num / Math.pow(10,6);
      unit = "M";
    }
  else if (pten > 3)
    {
      scaled_val = num / Math.pow(10,3);
      unit = "K";
    }
  else
    {
      scaled_val = num;
    }
  return [scaled_val,unit];
}

// our main class
function ScrollMeter () {
  this.partial_distance = 0;  // both distances are expressed in pixels
  this.global_distance = 0;
  this.prevScroll = 0;
  this.currScroll = 0;
  this.MPP = 0;  // meters per pixel
  this.monitor_height = 0;  // monitor height in _centimeters_
  this.pixel_height = 0;  // monitor height in pixels
  this.unit = "m";
}

// class methods are declared next
ScrollMeter.prototype.init = function() {
    this.global_distance = GM_getValue("global_distance",0);
    console.log("banana-o-meter: loaded distance " + this.global_distance + " pixels");
    this.unit = GM_getValue("measure_unit","m");
    this.calculateMPP();
    this.setupIndicator();
    this.updateIndicator();
  };
ScrollMeter.prototype.saveDistance = function() {
    temp_run = this.global_distance + this.partial_distance;
    GM_setValue("global_distance",temp_run);
  };
ScrollMeter.prototype.calculateMPP = function() {
    this.monitor_height = GM_getValue("monitor_height",19.5);
    this.pixel_height = window.screen.height;
    this.MPP = (this.monitor_height / 100) / this.pixel_height;
  };
ScrollMeter.prototype.convertMeasure = function(rawpixel) {
  var factor;
  if (this.unit == "m")
    {
      factor = 1;
    }
  else if (this.unit == "b")
    {
      factor = 100 / 15;  // average banana size = 15 Cm
    }
  human_readable = log_man(rawpixel * this.MPP * factor);
  return precision(human_readable[0], 10) + human_readable[1] + this.unit;
};
// eyecandy stuff is managed by those two functions
ScrollMeter.prototype.setupIndicator = function() {
    //hb = document.getElementsByClassName("nav-menu")[0];
  hb = document.getElementsByClassName("headbar-items")[0];
    ul = hb.getElementsByTagName("ul")[0];
    indicator = document.createElement("li");
    indicator.innerHTML = "<a name=\"blahblah\"><span class=\"label\" id=\"bananacounter\">9999</span></a>";
    ul.appendChild(indicator);
  };
ScrollMeter.prototype.updateIndicator = function() {
    temp_run = this.global_distance + this.partial_distance;
    document.getElementById("bananacounter").innerHTML = this.convertMeasure(temp_run);
  };
// core functionality of the script
ScrollMeter.prototype.runstep = function() {
    // distance updating
    this.currScroll = window.scrollY;
    if (this.currScroll > this.prevScroll)
      {
        this.partial_distance += (this.currScroll - this.prevScroll);
        this.prevScroll = this.currScroll;
        this.updateIndicator();
        this.saveDistance();
      }
  };
// functions that directly interact with the user
ScrollMeter.prototype.resetCount = function() {
  var conf = confirm("Are you sure?");
  if (conf === true)
    {
      this.global_distance = 0;
      this.partial_distance = 0;
      this.updateIndicator();
      this.saveDistance();
    }
};
ScrollMeter.prototype.setMonitorSize = function() {
  var newsize = prompt("Please write your screen's height expressed in centimeters",this.monitor_height.toString());
  if (newsize !== null)
    {
      this.monitor_height = Number(newsize);
      GM_setValue("monitor_height",this.monitor_height);
      this.calculateMPP();
      this.updateIndicator();
    }
};
ScrollMeter.prototype.setUnit = function(unit) {
  this.unit = unit;
  GM_setValue("measure_unit",unit);
  this.updateIndicator();
};
function suppressWakeUp()
{
  // safer way:
  unsafeWindow.GAG.PageController.idlePopupCountdown();
  // over aggressive way:
  //unsafeWindow.GAG.OverlayController.hideOverlay(unsafeWindow.GAG.OverlayController.selectors.OVERLAY_COMPONENT_IDLE_POPUP, !0);
}

// instantiate class and run initialization
var smeter = new ScrollMeter();
smeter.init();
// exports a basic control panel for the user
GM_registerMenuCommand("Reset 9gag total distance",function(){smeter.resetCount();});
GM_registerMenuCommand("Set bananameter screen height parameter",function(){smeter.setMonitorSize();});
GM_registerMenuCommand("Set default distance unit: meter",function(){smeter.setUnit("m");});
GM_registerMenuCommand("Set default distance unit: banana",function(){smeter.setUnit("b");});

// periodically check and update scroll progress
window.setInterval(function() {smeter.runstep();},100);
// aggressive way to stop that stupid "wake up" popup
window.setInterval(function() {suppressWakeUp();},2000);