Race Filter

Filter out long, private or priced races.

目前為 2019-09-04 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Race Filter
// @namespace    http://cryosis.co/
// @version      0.2
// @description  Filter out long, private or priced races.
// @author       Cryosis7
// @match        https://www.torn.com/loader.php?sid=racing
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// ==/UserScript==

const RACE_LENGTH = ['all', 'long', 'short'];
const PASSWORD = ['all', 'protected', 'public'];

$(window).load(function () {
  var filters = GM_getValue('filters', {
    'raceLength': 'all',
    'passwordProtected': 'all',
    'minimumFee': '',
    'maximumFee': ''
  })
  var enabledFilters = GM_getValue('enabledFilters', {
    'raceLength': false,
    'passwordProtected': false,
    'joinFee': false
  });

  addStyles();
  createObserver();

  /**
   * Creates an observer that is triggered when the 'custom events' race tab is clicked.
   */
  function createObserver() {
    const raceContainer = $('#racingAdditionalContainer')[0];
    var observer = new MutationObserver(function (mutations) {
      for (let mutation of mutations) {
        let customEventsWrap = $(mutation.addedNodes).filter('.custom-events-wrap');
        if ($(customEventsWrap).length > 0) {
          $(mutation.addedNodes).filter('#racingAdditionalContainer').remove();
          drawFilterBar(customEventsWrap);
          filterRaces();
        }
      }
    });

    observer.observe(raceContainer, {
      childList: true
    });
  }

  /**
   * Applies the filters to the race list and hides any race that does not meet the criteria
   */
  function filterRaces() {
    let raceList = $('.events-list').children().not('.clear');
    $(raceList).each((index, race) => {
      let showRace = true;
      let checkboxes = $(".filter-container").find("input:checked");

      $(checkboxes).each((i, x) => {
        if (showRace) {
          switch (x.name) {
            case 'raceLength':
              if ((filters.raceLength === 'long' && race.className === '')
                || (filters.raceLength === 'short' && race.className === 'long-time'))
                showRace = false;
              break;
            case 'passwordProtected':
              if ((filters.passwordProtected === 'protected' && race.className !== 'protected')
                || (filters.passwordProtected === 'public' && race.className === 'protected'))
                showRace = false;
              break;
            case 'joinFee':
              let joinFee = $(race).find('.fee').text().replace(/\D/g, "");
              if ((filters.minimumFee != "" && parseInt(joinFee) < parseInt(filters.minimumFee))
                || (filters.maximumFee != "" && parseInt(joinFee) > parseInt(filters.maximumFee)))
                showRace = false;
              break;
          }
        }
      });

      if (showRace) $(race).show();
      else $(race).hide();
    });
  }

  /**
   * Draws the filter bar and adds it
   * @param {HTMLDivElement} customEventsWrap
   * The parent element that contains all the races. 
   */
  function drawFilterBar(customEventsWrap) {
    let filterBar = $(`
      <div class="filter-container m-top10">
        <div class="title-gray top-round">Select Filters</div>
        
        <div class="cont-gray p10 bottom-round">
          <button class="torn-btn right filter-button">Filter</button>
        </div>
      </div>`);

    addListboxes(filterBar);
    $(customEventsWrap).before(filterBar);

    // Adding a checkbox listener to disable/enable the filters.
    $(filterBar).find('input[type=checkbox]').change(function () {
      $('.filter-button').click();
    });

    // Adding a listbox listener to update when changed.
    $(filterBar).find('select').change(function () {
      ($(`input[type=checkbox][name=${this.name}]`).prop('checked', true))
      $('.filter-button').click();
    });

    // Adding a listener to the filter button.
    $('.filter-button').click(function () {
      $("input[type='checkbox']").each(function (index) {
        if ($(this).prop('checked')) {
          switch (this.name) {
            case 'raceLength':
            case 'passwordProtected':
              filters[this.name] = $(`select[name='${this.name}']`).val().toLowerCase();
              break;
            case 'joinFee':
              filters.minimumFee = $('input[name="minimumFee"]').val().replace(/\D/g, "");
              filters.maximumFee = $('input[name="maximumFee"]').val().replace(/\D/g, "");
              break;
          }
        }
      });

      for (let filterKey in enabledFilters)
        enabledFilters[filterKey] = $('.filter-container').find(`input[name="${filterKey}"]`).prop('checked');

      GM_setValue('filters', filters);
      GM_setValue('enabledFilters', enabledFilters);
      filterRaces();
    });
    fillFilters();
  }

  /**
   * Fills out the filter bar with the filters
   */
  function fillFilters() {
    let filterContainer = $(".filter-container");

    for (let filterKey in filters) {
      let domFilter = $(filterContainer).find(`[name="${filterKey}"]`);
      domFilter.eq(0).val(filters[filterKey]);
    }

    for (let filterKey in enabledFilters) {
      if (enabledFilters[filterKey]) 
            $(filterContainer).find(`input[name="${filterKey}"]`).prop('checked', true);
    }
  }

  /**
   * Adds the listboxes and their options to the filterbar.
   * @param {FilterBarElement} filterBar 
   * The filterbar that is being created
   */
  function addListboxes(filterBar) {
    let lengthElement = $(`
    <span style="padding-right: 15px">
      <label style="padding-right: 5px">Race Length</label>
      <select class="listbox" name="raceLength"></select>
      <input type="checkbox" name="raceLength" style="transform:translateY(25%)"/>
    </span>`
    );
    RACE_LENGTH.forEach(x => {
      $(lengthElement).children(".listbox").append(`<option value=${x}>${x[0].toUpperCase() + x.substr(1)}</option>`);
    });
    $(filterBar).children(".cont-gray").append(lengthElement);

    let passwordElement = $(`
    <span style="padding-right: 15px">
      <label style="padding-right: 5px">Password</label>
      <select class="listbox" name="passwordProtected"></select>
      <input type="checkbox" name="passwordProtected" style="transform:translateY(25%)"/>
    </span>`
    );
    PASSWORD.forEach(x => {
      $(passwordElement).children(".listbox").append(`<option value=${x}>${x[0].toUpperCase() + x.substr(1)}</option>`);
    });
    $(filterBar).children(".cont-gray").append(passwordElement);
    
    $(filterBar).children(".cont-gray").append($(`
    <span style="padding-right: 15px">
      Minimum: $
      <input type="text" name="minimumFee" size="4" style="margin-right:5px; padding: 2px"></select>
      Maximum: $
      <input type="text" name="maximumFee" size="4" style="margin-right: 5px; padding: 2px"></select>
      <input type="checkbox" name="joinFee" style="transform:translateY(25%)"/>
    </span>`
    ));
  }

  /**
   * Adds some CSS styling required for the filter box.
   */
  function addStyles() {
    GM_addStyle(`
    .textbox {
      padding: 5px;
      border: 1px solid #ccc;
      width: 74px;
      text-align: left;
      height: 14px;
    }
    `);
  }
});

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址