[ Disclaimer, Create new user --- Wiki markup help, Install P99 ]
Difference between revisions of "MediaWiki:HuntingGuide.js"
From Project 1999 Wiki
		
		
		
| Line 61: | Line 61: | ||
| $('#numSpots').text(cleanedSpots.length); | $('#numSpots').text(cleanedSpots.length); | ||
| − | var filterSpots = function(filterLabel,  | + | var filterSpots = function(filterLabel, filter, filterData) { | 
| − |    var showUnfiltered = ! | + |    var showUnfiltered = !filter; | 
|    $('h4, .wikitable').toggle(showUnfiltered); |    $('h4, .wikitable').toggle(showUnfiltered); | ||
| Line 70: | Line 70: | ||
|      $('#levelFilter').val(''); |      $('#levelFilter').val(''); | ||
|    } else { |    } else { | ||
| − |      var rows =  | + |     var filteredSpots = cleanedSpots.filter(function(spot) { return filter(spot, filterData); }); | 
| + |      var rows = filteredSpots.map(function(spot) { return spot.$tr; }); | ||
|      var $resultsTbody = clearFilterResults(); |      var $resultsTbody = clearFilterResults(); | ||
|      $.each(rows, function(i, row) { |      $.each(rows, function(i, row) { | ||
| Line 80: | Line 81: | ||
| }; | }; | ||
| − | + | var filterByClass = function(spot, eqClass) { | |
| − | + |   var lowerCaseNotes = spot.notes.toLowerCase(); | |
| − | + |    var goodForPattern = new RegExp('good for [^\\.;]*?' + eqClass.toLowerCase()); | |
| − | var  | + |    var greatForPattern = new RegExp('great for [^\\.;]*?' + eqClass.toLowerCase()); | 
| − |    var  | + |   var isGood = lowerCaseNotes.match(goodForPattern); | 
| − | + |   var isGreat = lowerCaseNotes.match(greatForPattern); | |
| − | + |   return isGood || isGreat; | |
| − | + | }; | |
| − | + | ||
| − | + | var filterByLevel = function(spot, level) { | |
| − | + |   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); | ||
| + |   return minLevel <= level && maxLevel >= level; | ||
| + | }; | ||
| + | |||
| + | var filterByMonster = function(spot, monsterType) { | ||
| + |   var monsterPattern = new RegExp(monsterType); | ||
| + |   var lowerCaseMonsters = spot.monsters.toLowerCase(); | ||
| + |    var lowerCaseNotes = spot.notes.toLowerCase(); | ||
| + |   return lowerCaseMonsters.match(monsterPattern) || | ||
| + |          lowerCaseNotes.match(monsterPattern); | ||
| }; | }; | ||
| Line 98: | Line 110: | ||
|   * the "no filter" case (TODO: Make a separate handler/event binding for it) |   * the "no filter" case (TODO: Make a separate handler/event binding for it) | ||
|   */ |   */ | ||
| − | var  | + | var classFilterHandler = function(e) { | 
|    var eqClass = $(e.target).text(); |    var eqClass = $(e.target).text(); | ||
| − | + |    if (eqClass.trim().toLowerCase() === "no filter") filterSpots(e.target, null); | |
| − |    if (eqClass.trim().toLowerCase() === "no filter")  | + |    else filterSpots(e.target, filterByClass, eqClass); | 
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| } | } | ||
| + | |||
| + | /** | ||
| + |  * Filter out (hides) rows which aren't for the level the user entered | ||
| + |  */ | ||
| + | var levelFilterHandler = function () { | ||
| + |   var level = parseInt($('#levelFilter').val(), 10); | ||
| + |   filterSpots('#levelFilterLabel', level && filterByLevel, level); | ||
| + | }; | ||
| /** | /** | ||
|   * Filters out (hides) rows which don't involve the specified monster type |   * Filters out (hides) rows which don't involve the specified monster type | ||
|   */ |   */ | ||
| − | var  | + | var monsterFilterHandler = function(e) { | 
|    var monsterType = $(e.target).text().toLowerCase(); |    var monsterType = $(e.target).text().toLowerCase(); | ||
| − |    filterSpots(e.target,  | + |    filterSpots(e.target, filterByMonster, monsterType); | 
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| } | } | ||
| Line 138: | Line 144: | ||
|      if (!$table.find('tbody').children('tr:visible').length) $table.hide(); |      if (!$table.find('tbody').children('tr:visible').length) $table.hide(); | ||
|    }); |    }); | ||
| − |    // Hide the headings ( | + |    // Hide the headings | 
| − | + |   $('h4').hide(); | |
|    // Hide level range headers |    // Hide level range headers | ||
| − | |||
|    $('h4:first').next('.wikitable').show().find('tr:first').show(); |    $('h4:first').next('.wikitable').show().find('tr:first').show(); | ||
| } | } | ||
| Line 154: | Line 159: | ||
| // Bind event handlers | // Bind event handlers | ||
| − | $('.filterLink').click( | + | $('.filterLink').click(classFilterHandler); | 
| − | $('.monsterFilterLink').click( | + | $('.monsterFilterLink').click(monsterFilterHandler); | 
| − | $('#levelFilter').change( | + | $('#levelFilter').change(levelFilterHandler); | 
Revision as of 19:24, 14 November 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"/>');
// Create filter results table
var $filterResults = $('table.eoTable3.wikitable.sortable').eq(0).clone().hide();
var $headerRow = $('.hunting-guide-row:first').clone();
var clearFilterResults = function() {
  return $filterResults.empty()
                       .append($headerRow);
};
clearFilterResults();
$('h4:contains("Hunting Spots 1-4")').before($filterResults);
// 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.each(function (i, el) {
  var groupLevel = $(el).children('td:eq(1)').text();
  groupLevel = groupLevel.trim() === '-' ? null : groupLevel;
  var $tr = $(el);
  if ($tr.children('th').length) return; // Header row
  spots.push({
    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(),
    era: $tr.children('td:eq(6)').text(),
    image: $tr.children('td:eq(7)').text(),
    notes: $tr.children('td:eq(8)').text(),
    $tr:$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 filterSpots = function(filterLabel, filter, filterData) {
  var showUnfiltered = !filter;
  $('h4, .wikitable').toggle(showUnfiltered);
  $filterResults.toggle(!showUnfiltered);
  if (showUnfiltered) {
    $('#levelFilter').val('');
  } else {
    var filteredSpots = cleanedSpots.filter(function(spot) { return filter(spot, filterData); });
    var rows = filteredSpots.map(function(spot) { return spot.$tr; });
    var $resultsTbody = clearFilterResults();
    $.each(rows, function(i, row) {
      var $rowClone = $(row).clone();
      $resultsTbody.append($rowClone);
    });
  }
  selectFilter(filterLabel);
};
var filterByClass = function(spot, eqClass) {
  var lowerCaseNotes = spot.notes.toLowerCase();
  var goodForPattern = new RegExp('good for [^\\.;]*?' + eqClass.toLowerCase());
  var greatForPattern = new RegExp('great for [^\\.;]*?' + eqClass.toLowerCase());
  var isGood = lowerCaseNotes.match(goodForPattern);
  var isGreat = lowerCaseNotes.match(greatForPattern);
  return isGood || isGreat;
};
var filterByLevel = function(spot, level) {
  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);
  return minLevel <= level && maxLevel >= level;
};
var filterByMonster = function(spot, monsterType) {
  var monsterPattern = new RegExp(monsterType);
  var lowerCaseMonsters = spot.monsters.toLowerCase();
  var lowerCaseNotes = spot.notes.toLowerCase();
  return lowerCaseMonsters.match(monsterPattern) ||
         lowerCaseNotes.match(monsterPattern);
};
/**
 * 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 classFilterHandler = function(e) {
  var eqClass = $(e.target).text();
  if (eqClass.trim().toLowerCase() === "no filter") filterSpots(e.target, null);
  else filterSpots(e.target, filterByClass, eqClass);
}
/**
 * Filter out (hides) rows which aren't for the level the user entered
 */
var levelFilterHandler = function () {
  var level = parseInt($('#levelFilter').val(), 10);
  filterSpots('#levelFilterLabel', level && filterByLevel, level);
};
/**
 * Filters out (hides) rows which don't involve the specified monster type
 */
var monsterFilterHandler = function(e) {
  var monsterType = $(e.target).text().toLowerCase();
  filterSpots(e.target, filterByMonster, monsterType);
}
/**
 * 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').hide();
  // Hide level range headers
  $('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(classFilterHandler);
$('.monsterFilterLink').click(monsterFilterHandler);
$('#levelFilter').change(levelFilterHandler);
