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 ]

MediaWiki:PigParse.js

From Project 1999 Wiki
Jump to navigation Jump to search

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/**
 * PigParse Auction Tracker Integration
 * Replaces the old Special:AuctionTracker with live data from PigParse API.
 * Loaded via MediaWiki:Common.js
 */
(function () {
  'use strict';

  var PIGPARSE_PROXY = '/pigparse-proxy.php';
  var PIGPARSE_DETAIL_URL = 'https://pigparse.azurewebsites.net/ItemDetails/';
  var SERVERS = ['Blue', 'Green'];

  // Find the AuctionTracker placeholder on the page
  // The Itempage template outputs {{Special:AuctionTracker/ItemName}} which renders as
  // a link to the (missing) special page. Find it and replace with our widget.
  var $aucLink = $('a[href*="Special:AuctionTracker"]');
  if (!$aucLink.length) return;

  // Extract item name from the link
  var href = $aucLink.attr('href') || '';
  var itemName = decodeURIComponent(href.split('AuctionTracker/')[1] || '').replace(/_/g, ' ');
  if (!itemName) return;

  // Replace the link with our container, floated right next to the item box
  var $container = $('<div id="pigparse-tracker" style="float:right; width:320px; margin: 0 0 12px 16px; clear:right;"></div>');

  // Remove the AuctionTracker link/text
  var $linkParent = $aucLink.parent();
  $aucLink.remove();
  // Clean up empty paragraph left behind
  if ($linkParent.is('p') && $.trim($linkParent.text()) === '') {
    $linkParent.remove();
  }

  // Insert before the item box
  var $itemBox = $('.itemtopbg').first();
  if ($itemBox.length) {
    $itemBox.before($container);
  } else {
    // Fallback: put at top of content
    $('.mw-parser-output').prepend($container);
  }

  // Build the tracker UI
  var buildTrackerHtml = function (itemName) {
    return '<div class="auctrackerbox" style="border: 1px solid #aaa; padding: 8px; margin: 8px 0; background: #f9f9f9;">' +
      '<div style="font-weight: bold; margin-bottom: 6px;">Auction Prices (via <a href="https://pigparse.azurewebsites.net" target="_blank">PigParse</a>)</div>' +
      '<div class="tabs" style="margin-bottom: 6px;">' +
      SERVERS.map(function (s, i) {
        return '<span class="pigparse-tab' + (i === 0 ? ' selected' : '') + '" ' +
          'data-server="' + s + '" ' +
          'style="cursor:pointer; padding: 4px 12px; margin-right: 4px; ' +
          'border: 1px solid #aaa; border-bottom: none; display: inline-block; ' +
          'background: ' + (i === 0 ? '#fff' : '#eee') + ';">' + s + '</span>';
      }).join('') +
      '</div>' +
      SERVERS.map(function (s, i) {
        return '<div class="pigparse-server-data" data-server="' + s + '" ' +
          'style="display: ' + (i === 0 ? 'block' : 'none') + ';">' +
          '<div class="pigparse-loading" style="color: #888;">Loading ' + s + ' data...</div>' +
          '</div>';
      }).join('') +
      '</div>';
  };

  $container.html(buildTrackerHtml(itemName));

  // Tab switching
  $container.on('click', '.pigparse-tab', function () {
    var server = $(this).data('server');
    $container.find('.pigparse-tab').css('background', '#eee').removeClass('selected');
    $(this).css('background', '#fff').addClass('selected');
    $container.find('.pigparse-server-data').hide();
    $container.find('.pigparse-server-data[data-server="' + server + '"]').show();
  });

  var formatPrice = function (price) {
    if (!price && price !== 0) return '<span style="color:#999;">unlisted</span>';
    if (price === 0) return '<span style="color:#999;">unlisted</span>';
    return price.toLocaleString() + 'pp';
  };

  var timeAgo = function (dateStr) {
    if (!dateStr) return 'never';
    var now = new Date();
    var then = new Date(dateStr);
    var days = Math.floor((now - then) / (1000 * 60 * 60 * 24));
    if (days === 0) return 'today';
    if (days === 1) return '1 day ago';
    if (days < 30) return days + ' days ago';
    if (days < 365) return Math.floor(days / 30) + ' months ago';
    return Math.floor(days / 365) + '+ years ago';
  };

  var renderSummary = function (data, server) {
    var eqId = data.eQitemId;
    var detailLink = PIGPARSE_DETAIL_URL + eqId;

    var html = '<table class="wikitable" style="font-size: 90%; width: 100%;">';
    html += '<tr><th colspan="3" style="text-align:center;">WTS Summary (' + server + ')</th></tr>';

    if (data.totalWTSLast90DaysCount === 0 && data.totalWTSLastYearCount === 0) {
      html += '<tr><td colspan="3" style="text-align:center; color:#999;">No WTS data available</td></tr>';
    } else {
      html += '<tr><th>Period</th><th>Avg Price</th><th>Listings</th></tr>';
      if (data.totalWTSLast30DaysCount > 0)
        html += '<tr><td>Last 30 days</td><td>' + formatPrice(data.totalWTSLast30DaysAverage) + '</td><td>' + data.totalWTSLast30DaysCount + '</td></tr>';
      if (data.totalWTSLast90DaysCount > 0)
        html += '<tr><td>Last 90 days</td><td>' + formatPrice(data.totalWTSLast90DaysAverage) + '</td><td>' + data.totalWTSLast90DaysCount + '</td></tr>';
      if (data.totalWTSLast6MonthsCount > 0)
        html += '<tr><td>Last 6 months</td><td>' + formatPrice(data.totalWTSLast6MonthsAverage) + '</td><td>' + data.totalWTSLast6MonthsCount + '</td></tr>';
      if (data.totalWTSLastYearCount > 0)
        html += '<tr><td>Last year</td><td>' + formatPrice(data.totalWTSLastYearAverage) + '</td><td>' + data.totalWTSLastYearCount + '</td></tr>';
      html += '<tr><td colspan="3" style="font-size:85%; color:#666;">Last seen: ' + timeAgo(data.lastWTSSeen) + '</td></tr>';
    }

    html += '</table>';
    return html;
  };

  var renderRecentSellers = function (detailData) {
    if (!detailData || !detailData.items || !detailData.items.length) return '';

    var wts = detailData.items.filter(function (a) { return a.u === 0; });
    if (!wts.length) return '';

    // Sort by date descending, take most recent 10
    wts.sort(function (a, b) { return new Date(b.t) - new Date(a.t); });
    var recent = wts.slice(0, 10);

    var html = '<table class="wikitable" style="font-size: 85%; width: 100%; margin-top: 4px;">';
    html += '<tr><th>Seller</th><th>Price</th><th>When</th></tr>';

    recent.forEach(function (entry) {
      var player = detailData.players[String(entry.i)] || '?';
      html += '<tr><td>' + player + '</td><td>' + formatPrice(entry.p) + '</td><td>' + timeAgo(entry.t) + '</td></tr>';
    });

    html += '</table>';
    return html;
  };

  // Fetch data for each server
  SERVERS.forEach(function (server) {
    var $serverDiv = $container.find('.pigparse-server-data[data-server="' + server + '"]');

    // Fetch summary
    $.getJSON(PIGPARSE_PROXY + '?server=' + server + '&item=' + encodeURIComponent(itemName))
      .done(function (data) {
        var html = renderSummary(data, server);
        var detailLink = PIGPARSE_DETAIL_URL + data.eQitemId;

        // Also fetch recent sellers
        $.getJSON(PIGPARSE_PROXY + '?server=' + server + '&item=' + encodeURIComponent(itemName) + '&detail=1')
          .done(function (detailData) {
            html += renderRecentSellers(detailData);
            html += '<div style="font-size: 85%; margin-top: 4px;"><a href="' + detailLink + '" target="_blank">View full history on PigParse →</a></div>';
            $serverDiv.html(html);
          })
          .fail(function () {
            html += '<div style="font-size: 85%; margin-top: 4px;"><a href="' + detailLink + '" target="_blank">View full history on PigParse →</a></div>';
            $serverDiv.html(html);
          });
      })
      .fail(function () {
        $serverDiv.html('<div style="color:#999;">Item not found on ' + server + '</div>');
      });
  });
})();