Greasy Fork is available in English.

Steemit Post Vote Slider and Past Payout Monetizer

enables slider for steemians with at least 72SP, and allows monetizing posts after 7 days via comments!

// ==UserScript==
// @name         Steemit Post Vote Slider and Past Payout Monetizer
// @namespace    https://steemit.com/@alexpmorris
// @version      0.17
// @description  enables slider for steemians with at least 72SP, and allows monetizing posts after 7 days via comments!
// @author       @alexpmorris
// @source       https://github.com/alexpmorris/SteemitPostVoteSliderAndPastPayoutMonetizer
// @match        https://steemit.com/*
// @grant        none
// @require https://code.jquery.com/jquery-1.12.4.min.js
// @require https://code.jquery.com/ui/1.12.1/jquery-ui.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/notify/0.4.2/notify.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery-scrollTo/2.1.0/jquery.scrollTo.min.js
// @require https://greasyfork.org/scripts/6250-waitforkeyelements/code/waitForKeyElements.js?version=23756
// ==/UserScript==

// to avoid conflicts if using "Hide Resteems" (HR) with "Steemit Post Vote Slider and Past Payout Monetizer" (SPVS),
// TamperMonkey *must load* HR first (ie. "Settings -> Position" should be lower for HR than for SPVS)!

// For those with sub-100 SP, you must still use caution when voting more frequently,
// lest you receive the dreaded "Bandwidth Limit Exceeded" notification!  For more information:
// https://steemit.com/witness-category/@timcliff/new-accounts-don-t-have-enough-sp-to-fully-interact-with-the-blockchain-should-witnesses-update-the-max-block-size-discussion
// https://steemit.com/witness/@ausbitbank/ausbitbank-witness-update-17-7-17-sbd-interest-changed-to-1

(function() {
    'use strict';

    var minVests = 150000;  // approximately 72 SP
    var postCutOffDays = 6.25;  // 6.5 seems too close to 12hr "window"???
    var currentPostAgeInDays = 0;
    var altCommentElem = null;
    var altCommentProps = null;
    var altCommentState = null;
    var postAuthor = "";
    var altPostMode = false;
    var lastPathStr = "";
    var lastQueryStr = "";
    var totPosts = 0;
    var lastVoteTm = 0;
    var lastNotifyTm = 0;
    var lastChkTm = 0;

    window.FindReact = function(dom) {
        for (var key in dom) {
            if (key.startsWith("__reactInternalInstance$")) {
                var compInternals = dom[key]._currentElement;
                var compWrapper = compInternals._owner;
                var comp = compWrapper._instance;
                return comp;
            }
        }
        return null;
    };

    function triggerRefresh(cnt) {
        if ((cnt===null) || (cnt !== totPosts)) {
            totPosts = cnt;
            lastPathStr="";
        }
    }

    function urlCheckFunction() {
        if (lastPathStr !== location.pathname || lastQueryStr !== location.search ||
            lastPathStr === null || lastQueryStr === null) {
            var tickCountTm = new Date().getTime();
            if ((lastChkTm === 0) || (tickCountTm-lastChkTm < 750)) {  // allows a bit more time for AJAX responses to update DOM
                if (lastChkTm === 0) lastChkTm = tickCountTm;
                return;
            } else lastChkTm = 0;
            lastPathStr = location.pathname;
            lastQueryStr = location.search;
            updatePostVoteButtons();
        }
    }

    var steemitURLCheckTimer = setInterval (function() { urlCheckFunction(); }, 250);

    waitForKeyElements ("#posts_list", domCreateHooks);

    function domCreateHooks() {
        //to capture ajax additions to feeds
        var elem = $("#posts_list").parent();
        $(elem).unbind('DOMSubtreeModified.pvs');
        $(elem).on('DOMSubtreeModified.pvs', "div", function () {
            triggerRefresh($("#posts_list ul").length);
        });
        lastPathStr="";
    }

    $(document).click(function (event) {
        if (!$(event.target).parents("#tmpVoteSlider").length) {
            $("#tmpVoteSlider").remove();
        }
    });

    function updatePostVoteButtons() {

        currentPostAgeInDays = 0;
        altCommentElem = null;
        altCommentProps = null;
        altCommentState = null;
        postAuthor = "";

        $("#tmpVoteSlider").remove();

        $(".Voting__button-up svg g circle").attr('fill','rgb(255,255,200)');

        $(".PostFull .Voting__button-up").each( function() {
           var props = FindReact(this).props;
           postAuthor = props.author;
           if (currentPostAgeInDays === 0) {
               if (props.post_obj._root.nodes[3].nodes[1].entry[1] == "0.000 SBD") currentPostAgeInDays = -1; else {
                   var postDays = (new Date() - new Date(props.post_obj._root.nodes[8].nodes[2].entry[1])) / 86400000;
                   if (postDays > 0) currentPostAgeInDays = postDays;
               }
           }
        } );

        if (postAuthor === "") {
            $(".PostsList__summaries .Voting__button-up a").on("click",function(e) {
                return handle_vote_click(e, this);
            });
            console.log("SteemitPostVote: processNewPage [postSummary]");
            return;
        }
        console.log("SteemitPostVote: processNewPage [fullPost]");

        $(".PostFull .Voting__button-up a").on("click",function(e) {
            if (altCommentState !== null) altPostMode = true; else altPostMode = false;
            return handle_vote_click(e, this);
        });

        var tickCountTm = new Date().getTime();

        $(".Post_comments .Voting__button-up").each( function() {
           var state = FindReact(this).state;
           var props = FindReact(this).props;
           var isDeclinedPayout = (currentPostAgeInDays < 0) && (props.post_obj._root.nodes[3].nodes[1].entry[1] != "0.000 SBD");
           var isExpiredPayout = (currentPostAgeInDays > postCutOffDays);
           if ((altCommentState === null) && ((state.myVote === null) || (state.myVote === 0)) &&
               (props.author === postAuthor) && (isExpiredPayout || isDeclinedPayout) ) {
               var postDays = (new Date() - new Date(props.post_obj._root.nodes[8].nodes[2].entry[1])) / 86400000;
               if (postDays < postCutOffDays) {
                   altCommentElem = this;
                   altCommentState = state;
                   altCommentProps = props;
                   if ((tickCountTm-lastVoteTm > 2500) && (tickCountTm-lastNotifyTm > 2500)) {
                       lastNotifyTm = new Date().getTime();
                       var alertType = "";
                       if (isExpiredPayout) alertType = "POST EXPIRED"; else alertType = "DECLINED PAYOUT";
                       console.log("SteemitPostVote: "+alertType+", alternate comment target found!");
                       if (isExpiredPayout) alertType = "PostExpired"; else alertType = "PostDeclinedPayout";
                       $.notify(alertType+": Found Comment to UpVote Instead!",{globalPosition:"top left",className:"info"});
                   }
               }
           }
        } );
        $(".Post_comments .Voting__button-up a").on("click",function(e) {
            altPostMode = false;
            return handle_vote_click(e, this);
        });

        if ((currentPostAgeInDays > postCutOffDays) && (altCommentState === null)) {
            if ((tickCountTm-lastVoteTm > 2500) && (tickCountTm-lastNotifyTm > 2500)) {
                lastNotifyTm = new Date().getTime();
                console.log("SteemitPostVote: POST EXPIRED, no alternate targets found");
                //$.notify("PostExpired",{globalPosition:"top left",className:"info"});
            }
        }

    }

  function handle_vote_click(e, obj) {
      console.log("handle_vote_click [tryAltPostComment="+altPostMode+"]");

      var react_obj = obj;
      var retries = 0;
      while ((retries <= 2) && (!props || !props.vote)) {
          var state = FindReact(react_obj).state;
          var props = FindReact(react_obj).props;
          if (!props.vote) {
              retries++;
              react_obj = react_obj.offsetParent;
          }
      }

      if (props.net_vesting_shares < minVests) return true;

      e.stopPropagation();
      window.reactProps = props;
      window.reactState = state;

      $("#tmpVoteSlider").remove();

      //unvote
      if ((state.myVote !== null) && (state.myVote !== 0)) {
          //if alternate comment exists, scroll there instead
          if (altPostMode) {
              var postOverlayElem = $("#post_overlay");
              if ($(postOverlayElem).length === 0) $('html,body').scrollTo($(altCommentElem),100,{offset:-150}); else
                  $(postOverlayElem).scrollTo($(altCommentElem),100,{offset:-75});
              return false;
          }
          props.myVote = state.myVote;
          props.vote(0,props);
          lastVoteTm = new Date().getTime();
          //props.myVote = null;
          //state.myVote = 0;
          triggerRefresh();
          return false;
      }

      var newSlider = $('<div id="tmpVoteSlider" class="FoundationDropdown undefined dropdown-pane is-open"><div class="Voting__adjust_weight"><a href="#" class="confirm_weight" title="Upvote"><span class="Icon chevron-up-circle Icon_2x" style="display: inline-block; width: 2rem; height: 2rem;"><svg enable-background="new 0 0 33 33" version="1.1" viewBox="0 0 33 33" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="Chevron_Up_Circle"><circle cx="16" cy="16" r="15" stroke="#121313" fill="none"></circle><path d="M16.699,11.293c-0.384-0.38-1.044-0.381-1.429,0l-6.999,6.899c-0.394,0.391-0.394,1.024,0,1.414 c0.395,0.391,1.034,0.391,1.429,0l6.285-6.195l6.285,6.196c0.394,0.391,1.034,0.391,1.429,0c0.394-0.391,0.394-1.024,0-1.414 L16.699,11.293z" fill="#121313"></path></g></svg></span></a><div class="weight-display">0%</div><div class="rangeslider rangeslider-horizontal"><div class="rangeslider__fill" style="width: 44px;"></div><div class="rangeslider__handle" style="margin-left:10px;"></div></div><button class="Voting__adjust_weight_close close-button" type="button"><span aria-hidden="true" class="">×</span></button></div></div>');
      $(obj).parent().append(newSlider);

      if (localStorage.getItem('steemitVoteWeight') === null) localStorage.setItem('steemitVoteWeight',10000);
      var vw = Math.round(localStorage.getItem('steemitVoteWeight') / 100);
      $("#tmpVoteSlider").find('.weight-display').html(vw + "%");
      vw = vw / 0.5555555555555555556;
      $(".rangeslider__handle").css({left:vw+'px'});
      $(".rangeslider__fill").width(vw+15+'px');

      $(".close-button").on("click",function(e) { $("#tmpVoteSlider").remove(); e.stopPropagation(); triggerRefresh(); });

      $(".confirm_weight").on("click",function(e) {
          e.stopPropagation();
          var pctVote = Math.round(localStorage.getItem('steemitVoteWeight')/100);
          var useProps = reactProps;
          var alertType = "";
          if (altPostMode) {
              useProps = altCommentProps;
              altCommentState.showWeight = true;
              useProps.username = reactProps.username;
              useProps.loggedin = reactProps.loggedin;
              useProps.post_obj = reactProps.post_obj;
              if (currentPostAgeInDays > 0) alertType = "ExpiredPost"; else alertType = "DeclinedPayout";
              console.log("SteemitPostVote: Perform "+alertType+" UpVote ["+pctVote+"%]");
          } else console.log("SteemitPostVote: Perform UpVote ["+pctVote+"%]");
          var sliderParent = $("#tmpVoteSlider").parent();
          $("#tmpVoteSlider").remove();
          useProps.vote(pctVote*100,useProps);
          lastVoteTm = new Date().getTime();
          if (altPostMode) {
              var postOverlayElem = $("#post_overlay");
              if ($(postOverlayElem).length === 0) $('html,body').scrollTo($(altCommentElem),100,{offset:-150}); else
                  $(postOverlayElem).scrollTo($(altCommentElem),100,{offset:-75});
              $(altCommentElem).notify("UpVoted a Comment at "+pctVote+"%",{position:"top",className:"success"});
              if (currentPostAgeInDays > 0) alertType = "PostExpired"; else alertType = "PostDeclinedPayout";
              $.notify(alertType+": UpVoted a Comment at "+pctVote+"%",{globalPosition:"top left",className:"success"});
          } else $(sliderParent).notify("UpVoted at "+pctVote+"%",{position:"top",className:"success"});
          triggerRefresh();
          return false;
      });

      function slider_click(e, obj) {
          var parentOffset = $(obj).parent().offset();
          var x = e.pageX - parentOffset.left - 112;
          if (x < 1) x = 1;
          if (x > 180) x = 180;
          $(".rangeslider__fill").width(x+15+'px');
          var vw = Math.round(x*55.55555555555555556/100);
          $("#tmpVoteSlider").find('.weight-display').html(vw + "%");
          vw = vw / 0.5555555555555555556;
          $(".rangeslider__handle").css({left:vw-10+'px'});
          localStorage.setItem('steemitVoteWeight',Math.round(x*55.55555555555555556));
      }

      $('.rangeslider-horizontal').mousemove(function(e){
           if (e.buttons) slider_click(e, this);
      });

      $('.rangeslider-horizontal').click(function(e){
           slider_click(e, this);
      });

      $('.rangeslider__handle').draggable({
          axis: "x",
          cursor: "move",
          drag: function( event, ui ) {
              ui.position.top = 5;
              if (ui.position.left < 1) ui.position.left = 1;
              if (ui.position.left > 180) ui.position.left = 180;
              $(".rangeslider__fill").width(ui.position.left+15+'px');
              var vw = Math.round(ui.position.left*55.55555555555555556/100);
              $("#tmpVoteSlider").find('.weight-display').html(vw + "%");
          },
          start: function(event, ui) {
              var vw = Math.round(localStorage.getItem('steemitVoteWeight') / 55.55555555555555556);
              ui.position.left = vw;
              $(".rangeslider__fill").width(ui.position.left+15+'px');
          },
          stop: function(event, ui) {
              localStorage.setItem('steemitVoteWeight',Math.round(ui.position.left*55.55555555555555556));
          }
      });

      return false;

  }

})();