SHARE
TWEET

Untitled

a guest Dec 3rd, 2019 77 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         Chaturbate Easy Tipping Fixed Version
  3. // @namespace    madTipper
  4. // @version      0.11
  5. // @author       omgmikey - fixed on 1/21/2018 by tblopgreg
  6. // @match        https://*.chaturbate.com/*
  7. // @grant        GM_getValue
  8. // @grant        GM_setValue
  9. // @license      MIT
  10. // @run-at       document-idle
  11. // @description Adds a new tipping popup and modifies the existing one
  12. // ==/UserScript==
  13.  
  14. var CB2_TipButtonText = "TRINKGELD SENDEN";
  15. var CB2_TipPopupHeaderText = "Trinkgeld senden"
  16. var CSS_GREY  = {'color': 'rgb(88,141,61)'};
  17. var CSS_WHITE = {'color': '#FFFFFF'};
  18. var CSS_BLACK = {'color': '#000000'};
  19.  
  20. var ID_PREFIX = 'madTipper'
  21. var CLASS_PREFIX = 'madTipper'
  22. var CLASS_INPUT = CLASS_PREFIX + '_input';
  23. var BROADCASTER = "";
  24. var TippingUrl;
  25. var isLegacy;
  26.  
  27. var HTML_IDS = {
  28.     'BUTTON': 'button',
  29.     'POPUP': 'popup',
  30.     'AMOUNT': 'amount',
  31.     'COUNT': 'count',
  32.     'INTERVAL': 'interval',
  33.     'VARIANCE_LOWER': 'variance_lower',
  34.     'VARIANCE_UPPER': 'variance_upper',
  35.  
  36.     'START': 'start',
  37.     'STOP': 'stop',
  38.     'TOTAL': 'total',
  39.     'ETA': 'eta'
  40. };
  41.  
  42. for (var key in HTML_IDS) {
  43.     HTML_IDS[key] = ID_PREFIX + '_' + HTML_IDS[key];
  44. }
  45.  
  46. function dragElement(elmnt, grabElement) {
  47.     var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  48.     if (grabElement) {
  49.         // if present, the header is where you move the DIV from:
  50.         grabElement.onmousedown = dragMouseDown;
  51.     } else {
  52.         // otherwise, move the DIV from anywhere inside the DIV:
  53.         elmnt.onmousedown = dragMouseDown;
  54.     }
  55.  
  56.     function dragMouseDown(e) {
  57.         e = e || window.event;
  58.         e.preventDefault();
  59.         // get the mouse cursor position at startup:
  60.         pos3 = e.clientX;
  61.         pos4 = e.clientY;
  62.         document.onmouseup = closeDragElement;
  63.         // call a function whenever the cursor moves:
  64.         document.onmousemove = elementDrag;
  65.     }
  66.  
  67.     function elementDrag(e) {
  68.         e = e || window.event;
  69.         e.preventDefault();
  70.         // calculate the new cursor position:
  71.         pos1 = pos3 - e.clientX;
  72.         pos2 = pos4 - e.clientY;
  73.         pos3 = e.clientX;
  74.         pos4 = e.clientY;
  75.         // set the element's new position:
  76.         elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
  77.         elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
  78.     }
  79.  
  80.     function closeDragElement() {
  81.         // stop moving when mouse button is released:
  82.         document.onmouseup = null;
  83.         document.onmousemove = null;
  84.     }
  85. }
  86.  
  87.  
  88. function getCookie(cname) {
  89.     var name = cname + "=";
  90.     var decodedCookie = decodeURIComponent(document.cookie);
  91.     var ca = decodedCookie.split(';');
  92.     for(var i = 0; i <ca.length; i++) {
  93.         var c = ca[i];
  94.         while (c.charAt(0) == ' ') {
  95.             c = c.substring(1);
  96.         }
  97.         if (c.indexOf(name) == 0) {
  98.             return c.substring(name.length, c.length);
  99.         }
  100.     }
  101.     return "";
  102. }
  103.  
  104.  
  105. function setCookie(cname, cvalue, exdays) {
  106.     var d = new Date();
  107.     d.setTime(d.getTime() + (exdays*24*60*60*1000));
  108.     var expires = "expires="+ d.toUTCString();
  109.     document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
  110. }
  111.  
  112. function applyCSSobjectToElement(element, cssObject) {
  113.     for (let key in cssObject) {
  114.         element.style[key] = cssObject[key];
  115.     }
  116. }
  117.  
  118.  
  119. var tipPopup = "";
  120. var tipButton = "";
  121. var buttonContainer = "nix";
  122. var tipsLeft = 0;
  123. var tipFunctionTimeout = null;
  124. var juration = loadJuration();
  125.  
  126. setTimeout(function initialize() {
  127.  
  128.     isLegacy = getCookie("cb_legacy") === "1"; // new Beta website of CB, with interactive fullscreen and that jazz
  129.     if (isLegacy) {
  130.          tipButton = document.querySelector("a.tip_button").parentElement;
  131.         buttonContainer = document.querySelector("div.tip_shell");
  132.         TippingUrl =  document.querySelector('.tip_popup form').action
  133.         tipPopup = document.querySelector('.overlay_popup.tip_popup');
  134.  
  135.  
  136.         tipPopupHeader = document.querySelector("div.tip_popup div.title")
  137.     }
  138.     else {
  139.         tipButton = document.querySelector(`[title="${CB2_TipButtonText}"]`);
  140.         buttonContainer = tipButton.parentElement;
  141.         buttonContainer.parentElement.style.width = "430px";
  142.         var broadcaster = JSON.parse(initialRoomDossier).broadcaster_username;
  143.         TippingUrl = "/tipping/send_tip/" + broadcaster + "/";
  144.  
  145.  
  146.         var divTags = document.getElementsByTagName("div");
  147.         var tipPopupHeader;
  148.  
  149.         for (var i = 0; i < divTags.length; i++) {
  150.             if (divTags[i].textContent == CB2_TipPopupHeaderText) {
  151.                 tipPopupHeader = divTags[i];
  152.                 break;
  153.             }
  154.         }
  155.  
  156.         if (tipPopupHeader) {
  157.             tipPopup = tipPopupHeader.parentElement
  158.         }
  159.  
  160.     }
  161.  
  162.  
  163.  
  164.     dragElement(tipPopup, tipPopupHeader);
  165.  
  166.  
  167.  
  168.     createTipperButton();
  169.     createTipperPopup();
  170.     injectCSS();
  171.  
  172.     loadPreviousSettings();
  173.     initializeButtonCallbacks();
  174.     updateTipperButton();
  175. }, 400);
  176.  
  177. function createTipperButton() {
  178.     buttonContainer.insertAdjacentHTML("beforeend", '<span id="madTipper_button" >MADTIPPER</span>');
  179. }
  180.  
  181. function updateTipperButton() {
  182.  
  183.     if (tipsLeft == 0) {
  184.         document.getElementById(HTML_IDS['BUTTON']).innerHTML = 'MAD TIPPER';
  185.         document.getElementById(HTML_IDS['BUTTON']).style.width = "80px";
  186.     }
  187.     else {
  188.         document.getElementById(HTML_IDS['BUTTON']).innerHTML = 'MAD TIPPER (' + tipsLeft + ')' ;
  189.         document.getElementById(HTML_IDS['BUTTON']).style.width = "120px";
  190.     }
  191. }
  192.  
  193. function createTipperPopup() {
  194.  
  195.     buttonContainer.insertAdjacentHTML("beforeend",
  196.                                        '<div class="overlay_popup" id="madTipper_popup">' +
  197.                                        '<div id="madTipper_popup_header" style="color: rgb(11, 93, 129); background-color: rgb(224, 224, 224); font-size: 15px; font-family: UbuntuBold, Helvetica, Arial, sans-serif; padding: 6px;">Mad Tipper</div>'+
  198.                                        '<table width="100%" border="0" cellspacing="0" cellpadding="0">' +
  199.                                        '<tbody>' +
  200.                                        '<tr>' +
  201.                                        '<div class="body">' +
  202.                                        '<form>' +
  203.                                        '<label>Amount per tip:</label><br >' +
  204.                                        '<input type="text" id="madTipper_amount" class="madTipper_input">' +
  205.                                        '<br />' +
  206.  
  207.                                        '<label>Number of tips:</label><br >' +
  208.                                        '<input type="text" id="madTipper_count" class="madTipper_input">' +
  209.                                        '<br /><hr />' +
  210.  
  211.                                        '<label>Interval:</label><br >' +
  212.                                        '<input type="text" id="madTipper_interval" class="madTipper_input">' +
  213.                                        '<br />' +
  214.  
  215.                                        '<label>Interval variance lower (optional):</label><br >' +
  216.                                        '<input type="text" id="madTipper_variance_lower" class="madTipper_input">' +
  217.                                        '<br />' +
  218.  
  219.                                        '<label>Interval variance upper (optional):</label><br >' +
  220.                                        '<input type="text" id="madTipper_variance_upper" class="madTipper_input">' +
  221.                                        '<br /><hr />' +
  222.  
  223.                                        'Total tip:  ' + '<a id="madTipper_total"></a>' +
  224.                                        '<br />' +
  225.                                        'Estimated duration:  ' + '<a id="madTipper_eta"></a>' +
  226.                                        '</form>' +
  227.                                        '<hr />' +
  228.                                        '<button id="madTipper_start">Start</button>' +
  229.                                        '<button id="madTipper_stop" disabled="disabled">Stop</button>' +
  230.                                        '</div>' +
  231.                                        '</td>' +
  232.                                        '</tr>' +
  233.                                        '</tbody>' +
  234.                                        '</table>' +
  235.                                        '</div>'
  236.                                       );
  237. }
  238.  
  239. function injectCSS() {
  240.  
  241.     var buttonBackgroundUrl =
  242.         'url("https://ssl-ccstatic.highwebmedia.com/images/btn-sprites2.gif?ac5eba7d5cf3") no-repeat right';
  243.  
  244.  
  245.     var buttonFontFamily =
  246.         'UbuntuMedium,Arial,Helvetica,sans-serif';
  247.  
  248.     var genericButtonCSS = {
  249.         'height':'21px',
  250.         'width':'100px',
  251.         'padding-left':'10px',
  252.         'marginRight':'10px',
  253.         'fontSize':'12px',
  254.         'textShadow':'1px 1px 0 #588d3d',
  255.         'color': '#FFFFFF'
  256.     };
  257.     genericButtonCSS['font-family'] = buttonFontFamily;
  258.     genericButtonCSS['background'] = buttonBackgroundUrl + ' -84px';
  259.  
  260.     var mainButtonCSS = {
  261.         position: "absolute",
  262.         marginRight: "10px",
  263.         fontSize: "12px",
  264.         textShadow: "rgb(88, 141, 61) 1px 1px 0px",
  265.         color: "rgb(255, 255, 255)",
  266.     }
  267.  
  268.     for (let key in genericButtonCSS) {
  269.         if (mainButtonCSS[key] === undefined) {
  270.             mainButtonCSS[key] = genericButtonCSS[key];
  271.         }
  272.     }
  273.  
  274.     console.log("Hallo");
  275.  
  276.  
  277.     if (isLegacy) {
  278.         document.getElementById(HTML_IDS['BUTTON']).classList.add(tipButton.classList[0])
  279.         document.getElementById(HTML_IDS['BUTTON']).style.left = parseInt(getComputedStyle(tipButton).left, 10) + parseInt(getComputedStyle(tipButton).width, 10) + "px";
  280.         document.getElementById(HTML_IDS['BUTTON']).style.lineHeight = 1.7;
  281.         document.getElementById(HTML_IDS['BUTTON']).style.color = "white";
  282.     }
  283.     else {
  284.         document.getElementById(HTML_IDS['BUTTON']).style.cssText = tipButton.style.cssText
  285.     }
  286.  
  287.     console.log("blablabla");
  288.  
  289.  
  290.     for (const element of document.getElementsByClassName(CLASS_INPUT)) {
  291.         element.style.width = "auto";
  292.         element.style.marginBottom = "10px" ;
  293.     };
  294.  
  295.  
  296.     document.getElementById(HTML_IDS['POPUP']).style.position = "absolute" ;
  297.     document.getElementById(HTML_IDS['POPUP']).style.zIndex = "auto" ;
  298.     document.getElementById(HTML_IDS['POPUP']).style.width = "280px" ;
  299.     document.getElementById(HTML_IDS['POPUP']).style.height = "367px";
  300.     document.getElementById(HTML_IDS['POPUP']).style.backgroundColor = "rgb(255, 255, 255)";
  301.     document.getElementById(HTML_IDS['POPUP']).style.border = "2px solid rgb(11, 93, 129)";
  302.     document.getElementById(HTML_IDS['POPUP']).style.borderRadius = "4px";
  303.     document.getElementById(HTML_IDS['POPUP']).style.color = "rgb(73, 73, 73)";
  304.     document.getElementById(HTML_IDS['POPUP']).style.top = "-340" ;
  305.     document.getElementById(HTML_IDS['POPUP']).style.left = "170" ;
  306.     document.getElementById(HTML_IDS['POPUP']).style.display = "none" ;
  307.     document.getElementById(HTML_IDS['POPUP']).style.fontFamily = "UbuntuRegular, Helvetica, Arial, sans-serif";
  308.  
  309.  
  310.  
  311.  
  312.     dragElement(document.getElementById(HTML_IDS['POPUP']), document.getElementById("madTipper_popup_header"))
  313.  
  314.  
  315.     applyCSSobjectToElement(document.getElementById(HTML_IDS['START']), genericButtonCSS)
  316.  
  317.     genericButtonCSS['background'] = buttonBackgroundUrl + ' -42px';
  318.  
  319.     delete genericButtonCSS['color'];
  320.  
  321.     applyCSSobjectToElement(document.getElementById(HTML_IDS['STOP']), genericButtonCSS)
  322.  
  323. }
  324.  
  325.  
  326.  
  327. function startTipping() {
  328.  
  329.     var err = verifyTipperFields();
  330.  
  331.     if (err) {
  332.         alert(err);
  333.         stopTipping();
  334.         return;
  335.     }
  336.  
  337.     saveCurrentSettings();
  338.  
  339.     document.getElementById(HTML_IDS['START']).disabled = true;
  340.     applyCSSobjectToElement(document.getElementById(HTML_IDS['START']), CSS_GREY) ;
  341.  
  342.     document.getElementById(HTML_IDS['STOP']).disabled = false
  343.     applyCSSobjectToElement(document.getElementById(HTML_IDS['STOP']), CSS_WHITE) ;
  344.  
  345.  
  346.     document.getElementById(HTML_IDS['STOP']);
  347.  
  348.  
  349.     for (const element of document.getElementsByClassName(CLASS_INPUT)) {
  350.         element.disabled = true;
  351.         applyCSSobjectToElement(element, CSS_GREY);
  352.     };
  353.  
  354.  
  355.     tipsLeft = getTipCount();
  356.  
  357.     /* we really want to send the first one immediately */
  358.     sendTip();
  359.  
  360.     if (tipsLeft > 0) {
  361.         chainQueueTips();
  362.     }
  363. }
  364.  
  365. function verifyTipperFields() {
  366.  
  367.     function isInt(value) {
  368.         var regex = /^[0-9]+$/;
  369.         return regex.test(String(value));
  370.     }
  371.  
  372.     function isDuration(value) {
  373.         try {
  374.             juration.parse(value);
  375.             return true;
  376.         }
  377.         catch(ex) {
  378.             return false;
  379.         }
  380.     }
  381.  
  382.     function isDurationOrEmpty(value) {
  383.         return value === '' || isDuration(value);
  384.     }
  385.  
  386.     if (!isInt(getTipAmountRaw()) || getTipAmount() <= 0) {
  387.         return 'Tip amount field should be a positive integer.';
  388.     }
  389.  
  390.     if (!isInt(getTipCountRaw()) || getTipCount() <= 0) {
  391.         return 'Tip count field should be a positive integer.';
  392.     }
  393.  
  394.     if (!isDuration(getTipInterval())) {
  395.         return 'Tip interval should contain a duration. E.g.: "2.5s", "1", "2min"';
  396.     }
  397.  
  398.     if (!isDurationOrEmpty(getVarianceLowerRaw()) || !isDurationOrEmpty(getVarianceUpperRaw())) {
  399.         return 'Variance fields should contain durations, or be left blank. E.g.: "", "2.5s"';
  400.     }
  401. }
  402.  
  403. function getSleepInterval() {
  404.  
  405.     var interval = juration.parse(getTipInterval());
  406.     var lower_bound = interval - getVarianceLower();
  407.     var upper_bound = interval + getVarianceUpper();
  408.  
  409.     return getRandomNumber(lower_bound, upper_bound) * 1000;
  410. }
  411.  
  412. function getRandomNumber(min, max) {
  413.  
  414.     return Math.random() * (max - min) + min;
  415. }
  416.  
  417. function chainQueueTips() {
  418.  
  419.     var sleepTime = getSleepInterval();
  420.  
  421.     tipFunctionTimeout = setTimeout(function() {
  422.         sendTip(chainQueueTips);
  423.     }, sleepTime);
  424. }
  425.  
  426. function sendTip(queueNextTipFn) {
  427.     var queryParams = {
  428.         'csrfmiddlewaretoken': getCookie('csrftoken'),
  429.         'tip_amount': getTipAmount(),
  430.         'source': 'theater',
  431.         'message': '',
  432.         'tip_room_type': 'public' // TODO: normally not static, used before was:  document.getElementById('id_tip_room_type').value
  433.     };
  434.  
  435.  
  436.  
  437.  
  438.     fetch(TippingUrl,
  439.           {
  440.         method: 'POST',
  441.         headers: {
  442.             'Content-Type': 'application/x-www-form-urlencoded',
  443.             'X-Requested-With': 'XMLHttpRequest'
  444.         },
  445.         body: Object.keys(queryParams).map(function(k) {
  446.             return encodeURIComponent(k) + '=' + encodeURIComponent(queryParams[k])
  447.         }).join('&')
  448.     })
  449.         .then(function (response) {
  450.         if (response.error) {
  451.             alert(response.error);
  452.             stopTipping();
  453.         }
  454.     })
  455.         .catch(function (error) {
  456.  
  457.         alert(response.error);
  458.         stopTipping();
  459.  
  460.     });
  461.  
  462.     updateTipsLeft();
  463.  
  464.     if (tipsLeft === 0) {
  465.         stopTipping();
  466.     }
  467.     else if (queueNextTipFn) {
  468.         queueNextTipFn();
  469.     }
  470. }
  471.  
  472. function updateTipsLeft() {
  473.  
  474.     tipsLeft--;
  475.     updateTipperButton();
  476. }
  477.  
  478. function stopTipping() {
  479.  
  480.     clearTimeout(tipFunctionTimeout);
  481.     tipFunctionTimeout = null;
  482.  
  483.     tipsLeft = 0;
  484.     updateTipperButton();
  485.  
  486.     document.getElementById(HTML_IDS['STOP']).disabled = true;
  487.     applyCSSobjectToElement(document.getElementById(HTML_IDS['STOP']), CSS_GREY);
  488.  
  489.     document.getElementById(HTML_IDS['START']).disabled = false;
  490.     applyCSSobjectToElement(document.getElementById(HTML_IDS['STOP']), CSS_WHITE);
  491.  
  492.  
  493.     for (const element of document.getElementsByClassName(CLASS_INPUT)) {
  494.         element.disabled = false;;
  495.         applyCSSobjectToElement(element, CSS_BLACK);
  496.     };
  497.  
  498.  
  499. }
  500.  
  501. function initializeButtonCallbacks() {
  502.  
  503.     var popup = document.getElementById(HTML_IDS['POPUP'])
  504.     var button = document.getElementById(HTML_IDS['BUTTON'])
  505.  
  506.     button.onclick = function(ev) {
  507.         if (popup.style.display !=="none") {
  508.             popup.style.display = "none";
  509.         }
  510.         else {
  511.             popup.style.display = "block";
  512.         }
  513.     };
  514.  
  515.     popup.onclick = function(ev) {
  516.         ev.stopPropagation();
  517.     };
  518.  
  519.     document.getElementById(HTML_IDS['START']).onclick =function() {
  520.         startTipping();
  521.         document.getElementById(HTML_IDS['POPUP']).style.display = "none";
  522.     };
  523.  
  524.     document.getElementById(HTML_IDS['STOP']).onclick = function() {
  525.         stopTipping();
  526.     };
  527.  
  528.     document.body.addEventListener("click", function(ev) {
  529.         if (ev.target.id != button.id) {
  530.             document.getElementById(HTML_IDS['POPUP']).style.display = "none";
  531.         }
  532.     });
  533.  
  534.     for (const element of document.getElementsByClassName(CLASS_INPUT)) {
  535.         element.onChange = ()=> {
  536.             calculateAndSetTotalTip();
  537.             calculateAndSetETA();
  538.         }
  539.  
  540.     };
  541. }
  542.  
  543. function calculateAndSetTotalTip() {
  544.  
  545.     var value = document.getElementById(HTML_IDS['AMOUNT']).value * document.getElementById(HTML_IDS['COUNT']).value;
  546.     document.getElementById(HTML_IDS['TOTAL']).innerHTML = value + ' tokens';
  547. }
  548.  
  549. function calculateAndSetETA() {
  550.  
  551.     var interval = juration.parse(document.getElementById(HTML_IDS['INTERVAL']).value);
  552.  
  553.     /* we're not counting the first tip */
  554.     var count = getTipCount() - 1;
  555.  
  556.     var variance_lower = getVarianceLower();
  557.     var variance_upper = getVarianceUpper();
  558.  
  559.     var eta = (interval + variance_upper - variance_lower) * count;
  560.     document.getElementById(HTML_IDS['ETA']).innerHTML = juration.stringify(eta, {'format': 'long', 'units': 2});
  561. }
  562.  
  563. function getTipAmount() {
  564.  
  565.     return parseInt(getTipAmountRaw());
  566. }
  567.  
  568. function getTipAmountRaw() {
  569.  
  570.     return document.getElementById(HTML_IDS['AMOUNT']).value;
  571. }
  572.  
  573. function getTipInterval() {
  574.  
  575.     return document.getElementById(HTML_IDS['INTERVAL']).value;
  576. }
  577.  
  578. function getTipCount() {
  579.  
  580.     return parseInt(getTipCountRaw());
  581. }
  582.  
  583. function getTipCountRaw() {
  584.  
  585.     return document.getElementById(HTML_IDS['COUNT']).value;
  586. }
  587.  
  588. function getVarianceLower() {
  589.  
  590.     return parseVariance(getVarianceLowerRaw());
  591. }
  592.  
  593. function getVarianceLowerRaw() {
  594.  
  595.     return document.getElementById(HTML_IDS['VARIANCE_LOWER']).value;
  596. }
  597.  
  598.  
  599. function getVarianceUpper() {
  600.  
  601.     return parseVariance(getVarianceUpperRaw());
  602. }
  603.  
  604. function getVarianceUpperRaw() {
  605.  
  606.     return document.getElementById(HTML_IDS['VARIANCE_UPPER']).value;
  607. }
  608.  
  609. function parseVariance(variance) {
  610.  
  611.     if (variance == '0') {
  612.         variance = 0;
  613.     }
  614.  
  615.     variance = variance || 0;
  616.  
  617.     if (variance != 0) {
  618.         variance = juration.parse(variance);
  619.     }
  620.  
  621.     return variance;
  622. }
  623.  
  624. function saveCurrentSettings() {
  625.  
  626.     GM_setValue('amount', getTipAmount());
  627.     GM_setValue('interval', getTipInterval());
  628.     GM_setValue('count', getTipCount());
  629.     GM_setValue('variance_lower', getVarianceLower());
  630.     GM_setValue('variance_upper', getVarianceUpper());
  631. }
  632.  
  633. function loadPreviousSettings() {
  634.  
  635.     var amount = GM_getValue('amount', 1);
  636.     document.getElementById(HTML_IDS['AMOUNT']).value = amount;
  637.  
  638.     var count = GM_getValue('count', 10);
  639.     document.getElementById(HTML_IDS['COUNT']).value = count;
  640.  
  641.     var interval = GM_getValue('interval', '1s');
  642.     document.getElementById(HTML_IDS['INTERVAL']).value = interval;
  643.  
  644.     var variance_lower = GM_getValue('variance_lower', '');
  645.     document.getElementById(HTML_IDS['VARIANCE_LOWER']).value = variance_lower;
  646.  
  647.     var variance_upper = GM_getValue('variance_upper', '');
  648.     document.getElementById(HTML_IDS['VARIANCE_UPPER']).value = variance_upper;
  649.  
  650.     calculateAndSetTotalTip();
  651.     calculateAndSetETA();
  652. }
  653.  
  654.  
  655. // Script ends here
  656. // Libs included because they're not on a popular cdn
  657.  
  658.  
  659. /*
  660.  * juration - a natural language duration parser
  661.  * https://github.com/domchristie/juration
  662.  *
  663.  * Copyright 2011, Dom Christie
  664.  * Licenced under the MIT licence
  665.  *
  666.  */
  667.  
  668. function loadJuration() {
  669.  
  670.     var UNITS = {
  671.         seconds: {
  672.             patterns: ['second', 'sec', 's'],
  673.             value: 1,
  674.             formats: {
  675.                 'chrono': '',
  676.                 'micro':  's',
  677.                 'short':  'sec',
  678.                 'long':   'second'
  679.             }
  680.         },
  681.         minutes: {
  682.             patterns: ['minute', 'min', 'm(?!s)'],
  683.             value: 60,
  684.             formats: {
  685.                 'chrono': ':',
  686.                 'micro':  'm',
  687.                 'short':  'min',
  688.                 'long':   'minute'
  689.             }
  690.         },
  691.         hours: {
  692.             patterns: ['hour', 'hr', 'h'],
  693.             value: 3600,
  694.             formats: {
  695.                 'chrono': ':',
  696.                 'micro':  'h',
  697.                 'short':  'hr',
  698.                 'long':   'hour'
  699.             }
  700.         },
  701.         days: {
  702.             patterns: ['day', 'dy', 'd'],
  703.             value: 86400,
  704.             formats: {
  705.                 'chrono': ':',
  706.                 'micro':  'd',
  707.                 'short':  'day',
  708.                 'long':   'day'
  709.             }
  710.         },
  711.         weeks: {
  712.             patterns: ['week', 'wk', 'w'],
  713.             value: 604800,
  714.             formats: {
  715.                 'chrono': ':',
  716.                 'micro':  'w',
  717.                 'short':  'wk',
  718.                 'long':   'week'
  719.             }
  720.         },
  721.         months: {
  722.             patterns: ['month', 'mon', 'mo', 'mth'],
  723.             value: 2628000,
  724.             formats: {
  725.                 'chrono': ':',
  726.                 'micro':  'm',
  727.                 'short':  'mth',
  728.                 'long':   'month'
  729.             }
  730.         },
  731.         years: {
  732.             patterns: ['year', 'yr', 'y'],
  733.             value: 31536000,
  734.             formats: {
  735.                 'chrono': ':',
  736.                 'micro':  'y',
  737.                 'short':  'yr',
  738.                 'long':   'year'
  739.             }
  740.         }
  741.     };
  742.  
  743.     var stringify = function(seconds, options) {
  744.  
  745.         if(!_isNumeric(seconds)) {
  746.             throw "juration.stringify(): Unable to stringify a non-numeric value";
  747.         }
  748.  
  749.         if((typeof options === 'object' && options.format !== undefined) && (options.format !== 'micro' && options.format !== 'short' && options.format !== 'long' && options.format !== 'chrono')) {
  750.             throw "juration.stringify(): format cannot be '" + options.format + "', and must be either 'micro', 'short', or 'long'";
  751.         }
  752.  
  753.         var defaults = {
  754.             format: 'short',
  755.             units: undefined
  756.         };
  757.  
  758.         var opts = _extend(defaults, options);
  759.  
  760.         var units = ['years', 'months', 'days', 'hours', 'minutes', 'seconds'], values = [];
  761.         var remaining = seconds;
  762.         var activeUnits = 0;
  763.         for(var i = 0, len = units.length;
  764.             i < len && (opts.units == undefined || activeUnits < opts.units);
  765.             i++) {
  766.             var unit = UNITS[units[i]];
  767.             values[i] = Math.floor(remaining / unit.value);
  768.             if (values[i] > 0 || activeUnits > 0)
  769.                 activeUnits++;
  770.  
  771.             if(opts.format === 'micro' || opts.format === 'chrono') {
  772.                 values[i] += unit.formats[opts.format];
  773.             }
  774.             else {
  775.                 values[i] += ' ' + _pluralize(values[i], unit.formats[opts.format]);
  776.             }
  777.             remaining = remaining % unit.value;
  778.         }
  779.         var output = '';
  780.         for(i = 0, len = values.length; i < len; i++) {
  781.             if(values[i].charAt(0) !== "0" && opts.format != 'chrono') {
  782.                 output += values[i] + ' ';
  783.             }
  784.             else if (opts.format == 'chrono') {
  785.                 output += _padLeft(values[i]+'', '0', i==values.length-1 ? 2 : 3);
  786.             }
  787.         }
  788.         return output.replace(/\s+$/, '').replace(/^(00:)+/g, '').replace(/^0/, '');
  789.     };
  790.  
  791.     var parse = function(string) {
  792.  
  793.         // returns calculated values separated by spaces
  794.         for(var unit in UNITS) {
  795.             for(var i = 0, mLen = UNITS[unit].patterns.length; i < mLen; i++) {
  796.                 var regex = new RegExp("((?:\\d+\\.\\d+)|\\d+)\\s?(" + UNITS[unit].patterns[i] + "s?(?=\\s|\\d|\\b))", 'gi');
  797.                 string = string.replace(regex, function(str, p1, p2) {
  798.                     return " " + (p1 * UNITS[unit].value).toString() + " ";
  799.                 });
  800.             }
  801.         }
  802.  
  803.         var sum = 0,
  804.             numbers = string
  805.         .replace(/(?!\.)\W+/g, ' ')                       // replaces non-word chars (excluding '.') with whitespace
  806.         .replace(/^\s+|\s+$|(?:and|plus|with)\s?/g, '')   // trim L/R whitespace, replace known join words with ''
  807.         .split(' ');
  808.  
  809.         for(var j = 0, nLen = numbers.length; j < nLen; j++) {
  810.             if(numbers[j] && isFinite(numbers[j])) {
  811.                 sum += parseFloat(numbers[j]);
  812.             } else if(!numbers[j]) {
  813.                 throw "juration.parse(): Unable to parse: a falsey value";
  814.             } else {
  815.                 // throw an exception if it's not a valid word/unit
  816.                 throw "juration.parse(): Unable to parse: " + numbers[j].replace(/^\d+/g, '');
  817.             }
  818.         }
  819.         return sum;
  820.     };
  821.  
  822.     // _padLeft('5', '0', 2); // 05
  823.     var _padLeft = function(s, c, n) {
  824.         if (! s || ! c || s.length >= n) {
  825.             return s;
  826.         }
  827.  
  828.         var max = (n - s.length)/c.length;
  829.         for (var i = 0; i < max; i++) {
  830.             s = c + s;
  831.         }
  832.  
  833.         return s;
  834.     };
  835.  
  836.     var _pluralize = function(count, singular) {
  837.         return count == 1 ? singular : singular + "s";
  838.     };
  839.  
  840.     var _isNumeric = function(n) {
  841.         return !isNaN(parseFloat(n)) && isFinite(n);
  842.     };
  843.  
  844.     var _extend = function(obj, extObj) {
  845.         for (var i in extObj) {
  846.             if(extObj[i] !== undefined) {
  847.                 obj[i] = extObj[i];
  848.             }
  849.         }
  850.         return obj;
  851.     };
  852.  
  853.     var juration = {
  854.         parse: parse,
  855.         stringify: stringify,
  856.         humanize: stringify
  857.     };
  858.  
  859.     return juration;
  860. };
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top