This is a wiki for a reason. Anyone can contribute. If you see something that is inaccurate or can be improved, don't ask that it be fixed--just improve it.
[ Disclaimer, Create new user --- Wiki markup help, Install P99 ]

Difference between revisions of "MediaWiki:HuntingGuide.js"

From Project 1999 Wiki
Jump to: navigation, search
Line 47: Line 47:
 
   $('#filterResults').toggle(!!filteringFunction);
 
   $('#filterResults').toggle(!!filteringFunction);
 
   if (filteringFunction) {
 
   if (filteringFunction) {
     var rows = cleanedSpots.map(filteringFunction);
+
     var rows = $.map(cleanedSpots, filteringFunction);
 
     var $resultsTbody = $('#filterResults').show().find('tbody').empty();
 
     var $resultsTbody = $('#filterResults').show().find('tbody').empty();
 
     $.each(rows, function(i, row) {
 
     $.each(rows, function(i, row) {

Revision as of 01:00, 4 July 2019

// Basic DOM manipulation onReady (since the wiki won't let us add <input> tags in the wiki text
$('#levelFilterPlaceholder').replaceWith('<input id="levelFilter" style="width:30px"/>');

// Get jQuery object of every row in the hunting guide (because all of the filter functions need it)
var $rows = $('.wikitable tbody tr');

/**
 * Build a in-memory data object with the data parsed from each row (which will tell us which
 * levels/classes should be shown for any filter).
 * @example a "spot" created by this function for critters in Butcherblock Mountains: {
 *   soloLevel: '04-06',
 *   groupLevel: '03-05',
 *   zone: 'Butcherblock Mountains',
 *   area: 'Greater Faydark zoneline',
 *   monsters: 'Assorted Critters	',
 *   xpMod: '100%',
 *   notes: '',
 *   $tr: *a jQuery object pointing to the <tr> that all this data originally came from*
 * }
 */
var spots = $rows.map(function (i, el) {
  var groupLevel = $(el).children('td:eq(1)').text();
  groupLevel = groupLevel.trim() === '-' ? null : groupLevel;
  var $tr = $(el);
  return {
    soloLevel: $tr.children('td:eq(0)').text(),
    groupLevel,
    zone: $tr.children('td:eq(2)').text(),
    area: $tr.children('td:eq(3)').text(),
    monsters: $tr.children('td:eq(4)').text(),
    xpMod: $tr.children('td:eq(5)').text(),
    notes: $tr.children('td:eq(6)').text() || '',
    $tr
  }
});

// Clear garbage entries (wish I had ES6 filter ..)
var cleanedSpots = [];
$.each(spots, function (i, spot) {
  if (spot.soloLevel && spot.zone) cleanedSpots.push(spot);
});

$('#numSpots').text(cleanedSpots.length);

var filter = function(filterLabel, filteringFunction) {
  $('h4, .wikitable').toggle(!filteringFunction);
  $('#filterResults').toggle(!!filteringFunction);
  if (filteringFunction) {
    var rows = $.map(cleanedSpots, filteringFunction);
    var $resultsTbody = $('#filterResults').show().find('tbody').empty();
    $.each(rows, function(i, row) {
      $resultsTbody.append($(row).clone());
    });
  } else {
    $('#levelFilter').val('');
  }
  selectFilter(filterLabel);
};

/**
 * Filter out (hides) rows which aren't for the level the user entered
 */
var filterForLevel = function () {
  var level = parseInt($('#levelFilter').val(), 10);
  filter('#levelFilterLabel', level && function(i, spot) {
    var levelRangeText = spot.$tr.children('td:first').text();
    var splitLevelRanges = levelRangeText.split('-');
    var minLevel = parseInt(splitLevelRanges[0], 10);
    var maxLevel = parseInt(splitLevelRanges[1] || splitLevelRanges[0], 10);
    if (minLevel <= level && maxLevel >= level) return spot.$tr;
  });
};

/**
 * Filters out (hides) rows which aren't specifically "good for" the clicked class; also handles
 * the "no filter" case (TODO: Make a separate handler/event binding for it)
 */
var filterForClass = function(e) {
  var eqClass = $(e.target).text();

  if (eqClass.trim().toLowerCase() === "no filter") {
    filter(e.target, null);
  } else {
    filter(e.target, function(spot) {
      var lowerCaseNotes = spot.notes.toLowerCase();
      if (!lowerCaseNotes.match(new RegExp(`good for [^\\.;]*?${eqClass.toLowerCase()}`)) &&
          !lowerCaseNotes.match(new RegExp(`great for [^\\.;]*?${eqClass.toLowerCase()}`))) return;
      return spot.$tr;
    });
  }
}

/**
 * Filters out (hides) rows which don't involve the specified monster type
 */
var filterForMonsterType = function(e) {
  var monsterType = $(e.target).text().toLowerCase();
  filter(e.target, function(i, spot) {
    var lowerCaseMonsters = spot.monsters.toLowerCase();
    if (!lowerCaseMonsters.match(new RegExp(`${monsterType}[s\W\s]`))) return;
    return spot.$tr;
  })
}

/**
 * Hides the table headers and level range headings for level ranges that have been completely
 * filtered out
 */
var hideHeaders = function () {
  // If anything got hidden by previous filters, show it (because this filter might not hide it)
  $('.wikitable, h4').show();
  // Hide the tables
  $('.wikitable').each(function(i, table) {
    var $table = $(table);
    if (!$table.find('tbody').children('tr:visible').length) $table.hide();
  });
  // Hide the headings (<h4> elements)

  // Hide level range headers
  $('h4').hide();
  $('h4:first').next('.wikitable').show().find('tr:first').show();
}

/**
 * Visually marks the currently-used filter with an underline
 */
var selectFilter = function (target) {
  $('.filterLink, .monsterFilterLink, #levelFilterLabel').css({textDecoration: ''});
  $(target).css({textDecoration: 'underline'});
}

// Bind event handlers
$('.filterLink').click(filterForClass);
$('.monsterFilterLink').click(filterForMonsterType);
$('#levelFilter').change(filterForLevel);