<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.seculargames.org/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AItemCategorySearch.js</id>
	<title>MediaWiki:ItemCategorySearch.js - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.seculargames.org/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AItemCategorySearch.js"/>
	<link rel="alternate" type="text/html" href="https://wiki.seculargames.org/index.php?title=MediaWiki:ItemCategorySearch.js&amp;action=history"/>
	<updated>2026-07-29T05:22:15Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.45.3</generator>
	<entry>
		<id>https://wiki.seculargames.org/index.php?title=MediaWiki:ItemCategorySearch.js&amp;diff=45800&amp;oldid=prev</id>
		<title>imported&gt;Loramin at 21:28, 7 January 2018</title>
		<link rel="alternate" type="text/html" href="https://wiki.seculargames.org/index.php?title=MediaWiki:ItemCategorySearch.js&amp;diff=45800&amp;oldid=prev"/>
		<updated>2018-01-07T21:28:53Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;/**&lt;br /&gt;
 * For any questions or comments on this code contact Loramin via the forum Private Message system.&lt;br /&gt;
 *&lt;br /&gt;
 * NOTE: This code would be shorter/simpler/easier to read if it was in ES6 instead of ES5, but&lt;br /&gt;
 *       since I can&amp;#039;t guarantee that every user will have ES6 support (and since I didn&amp;#039;t want to&lt;br /&gt;
 *       bother with Babel for something so small) I chose to use the (old/ugly) ES5 syntax.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// URL on the wiki where we can get all of the categories&lt;br /&gt;
var categoriesUrl =&lt;br /&gt;
  &amp;#039;http://wiki.project1999.com/index.php?title=Special:Categories&amp;amp;offset=&amp;amp;limit=500&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Fetches all of the available categories in the wiki&lt;br /&gt;
 */&lt;br /&gt;
var getCategories = function() {&lt;br /&gt;
  return $.get(categoriesUrl)&lt;br /&gt;
    .then(function(html) {&lt;br /&gt;
      var categories = $(html).find(&amp;#039;.mw-spcontent li a&amp;#039;).map(function(i, link) {&lt;br /&gt;
        return $(link).text();&lt;br /&gt;
      });&lt;br /&gt;
      return $.makeArray(categories);&lt;br /&gt;
    })&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Function for retrieving all item names from a single page (which one is determined by &amp;quot;fromItem&amp;quot;&lt;br /&gt;
 * for a provided category&lt;br /&gt;
 * @param {string} category - an item category, with or without &amp;quot;Category:&amp;quot; (eg. &amp;quot;Fashion: Leather&amp;quot;)&lt;br /&gt;
 * @param fromItem - the item to start the pagination from (eg. &amp;quot;Impskin Gloves&amp;quot; would skip all&lt;br /&gt;
 *                   items from before &amp;quot;Impskin Gloves&amp;quot; and start the page on &amp;quot;Impskin Gloves&amp;quot;.&lt;br /&gt;
 * @returns {Promise} - when this promise is resolved it will return an object with two&lt;br /&gt;
 *          properties:&lt;br /&gt;
 *            - items - the item names from the page&lt;br /&gt;
 *            - nextItem - the &amp;quot;fromItem&amp;quot; to get the next page (if any)&lt;br /&gt;
 */&lt;br /&gt;
var getItemsInCategoryPage = function(category, fromItem) {&lt;br /&gt;
  // Add &amp;quot;Category:&amp;quot; (unless the provided category already starts with it)&lt;br /&gt;
  if (!category.startsWith(&amp;#039;Category:&amp;#039;)) category = &amp;#039;Category:&amp;#039; + category;&lt;br /&gt;
&lt;br /&gt;
  // Build the URL&lt;br /&gt;
  var url = &amp;#039;http://wiki.project1999.com/index.php?title=&amp;#039; + encodeURI(category);&lt;br /&gt;
&lt;br /&gt;
  // Add a &amp;quot;frompage&amp;quot; parameter if we&amp;#039;re trying to get any page other than the first&lt;br /&gt;
  if (fromItem) url += &amp;#039;&amp;amp;pagefrom=&amp;#039; + encodeURI(fromItem);&lt;br /&gt;
&lt;br /&gt;
  // Go get the page&lt;br /&gt;
  return $.get(url)&lt;br /&gt;
    .then(function(html) {&lt;br /&gt;
      // jQuery-ify the returned HTML&lt;br /&gt;
      var $html = $(html);&lt;br /&gt;
&lt;br /&gt;
      // Extract all of the &amp;lt;a&amp;gt; tags that look like: &amp;lt;li&amp;gt;&amp;lt;a&amp;gt;Some Item&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
      var $links = $html.find(&amp;#039;li:not(#f-list li):not(.pBody li) a&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
      // Map (and return) the item titles from within all of the links&lt;br /&gt;
      var itemNames = $links.map(function(i, link) {&lt;br /&gt;
        // Extract title&lt;br /&gt;
        return $(link).attr(&amp;#039;title&amp;#039;);&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      // jQuery overwrites the native &amp;quot;map&amp;quot; function with its own, which returns a jQuery object&lt;br /&gt;
      // (even when there isn&amp;#039;t a single jQuery object or HTML element in the return value)&lt;br /&gt;
      // This fixes that.&lt;br /&gt;
      itemNames = $.makeArray(itemNames);&lt;br /&gt;
&lt;br /&gt;
      // Grab the href of the first &amp;quot;next 200&amp;quot; link&lt;br /&gt;
      var nextHref = $html.find(&amp;#039;a:contains(&amp;quot;next 200&amp;quot;)&amp;#039;).eq(0).attr(&amp;#039;href&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
      // Extract the next item (if any)&lt;br /&gt;
      var match = nextHref &amp;amp;&amp;amp; nextHref.match(/pagefrom=(.*?)#/);&lt;br /&gt;
&lt;br /&gt;
      // Figure out if there is a nextItem (and if not return null instead of causing an error)&lt;br /&gt;
      var nextItem = match ? match[1] : null;&lt;br /&gt;
&lt;br /&gt;
      // Return results&lt;br /&gt;
      return { itemNames: itemNames, nextItem: nextItem };&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var showNormalCursor = function() {&lt;br /&gt;
  $(&amp;#039;body&amp;#039;).css({ cursor: &amp;#039;default&amp;#039;});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
var showWaitCursor = function() {&lt;br /&gt;
  $(&amp;#039;body&amp;#039;).css({ cursor: &amp;#039;wait&amp;#039;});&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var getItemsInCategoryPages = function(category, nextItem, itemNames) {&lt;br /&gt;
  // Change the cursor to let the user know they need to wait&lt;br /&gt;
  showWaitCursor();&lt;br /&gt;
&lt;br /&gt;
  // Go get all the items (and the next item) for the next page (or first page on first iteration)&lt;br /&gt;
  return getItemsInCategoryPage(category, nextItem)&lt;br /&gt;
    .then(function(result) {&lt;br /&gt;
      // Combine any itemNames from previous iterations with this one&lt;br /&gt;
      itemNames = (itemNames || []).concat(result.itemNames);&lt;br /&gt;
&lt;br /&gt;
      if (result.nextItem) {&lt;br /&gt;
        // If there is a next item, get the items from a page that starts with it as the &amp;quot;pagefrom&amp;quot;&lt;br /&gt;
        return getItemsInCategoryPages(category, result.nextItem, itemNames);&lt;br /&gt;
      } else {&lt;br /&gt;
        // otherwise return what we have (and restore the cursor to normal)&lt;br /&gt;
        showNormalCursor();&lt;br /&gt;
        return itemNames;&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Helper function for finding items in array &amp;quot;left&amp;quot; which are also present in array &amp;quot;right&amp;quot;&lt;br /&gt;
 */&lt;br /&gt;
var findIntersection = function(left, right) {&lt;br /&gt;
  return left.filter(function(item) { // return all of the items in left ...&lt;br /&gt;
    return right.includes(item);      // ... which are also items in right&lt;br /&gt;
  });&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This is the main function which powers the entire page.  It takes 2-3 categories (if 0-1 are&lt;br /&gt;
 * provided it throws an error), looks up all items in those categories, and then returns only the&lt;br /&gt;
 * items which are present in all of those categories.&lt;br /&gt;
 */&lt;br /&gt;
var findCategoryIntersections = function(category1, category2, category3) {&lt;br /&gt;
  return Promise.all([&lt;br /&gt;
    getItemsInCategoryPages(category1), // go get the items in category 1&lt;br /&gt;
    getItemsInCategoryPages(category2) // and the ones in category 2&lt;br /&gt;
  ])&lt;br /&gt;
    .then(function(results) {&lt;br /&gt;
      // Figure out which items are in both categories&lt;br /&gt;
      var intersectionOf1And2 = findIntersection(results[0], results[1]);&lt;br /&gt;
&lt;br /&gt;
      // If there&amp;#039;s a third category ...&lt;br /&gt;
      if (category3) {&lt;br /&gt;
        // Go get its items and then return ...&lt;br /&gt;
        return getItemsInCategoryPages(category3)&lt;br /&gt;
          .then(function(category3Results) {&lt;br /&gt;
            // ... the interesection between those items and the previous interesection of #1 and #2&lt;br /&gt;
            return findIntersection(intersectionOf1And2 , category3Results);&lt;br /&gt;
          });&lt;br /&gt;
      }&lt;br /&gt;
      // Otherwise just return the intersection of #1 and #2&lt;br /&gt;
      return intersectionOf1And2;&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// &amp;quot;onCLick&amp;quot;&lt;br /&gt;
var handleSearchClick = function(e) {&lt;br /&gt;
  // Determine which categories the user picked&lt;br /&gt;
  var category1 = $(&amp;#039;#category1&amp;#039;).val();&lt;br /&gt;
  var category2 = $(&amp;#039;#category2&amp;#039;).val();&lt;br /&gt;
  var category3 = $(&amp;#039;#category3&amp;#039;).val();&lt;br /&gt;
&lt;br /&gt;
  // Yell at them if they didn&amp;#039;t pick at least two&lt;br /&gt;
  if (!category1 || !category2) return alert(&amp;#039;Please select at least two categories&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
  // Let them know to wait while go do the search&lt;br /&gt;
  showWaitCursor();&lt;br /&gt;
  findCategoryIntersections(category1, category2, category3)&lt;br /&gt;
    .then(function(results) {&lt;br /&gt;
      // Convert the results ([&amp;#039;itemA&amp;#039;, &amp;#039;itemB&amp;#039;, ...]) into &amp;lt;li&amp;gt;&amp;lt;a&amp;gt;item&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt; HTML&lt;br /&gt;
      var resultsHtml = results.map(function(item) {&lt;br /&gt;
        return &amp;#039;&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;http://wiki.project1999.com/&amp;#039; + item + &amp;#039;&amp;quot;&amp;gt;&amp;#039; + item + &amp;#039;&amp;lt;/a&amp;gt;&amp;#039;;&lt;br /&gt;
      });&lt;br /&gt;
      // Add the results HTML to the page and set the cursor back to normal&lt;br /&gt;
      $(&amp;#039;#results&amp;#039;).html(resultsHtml.join(&amp;#039;&amp;#039;));&lt;br /&gt;
      showNormalCursor();&lt;br /&gt;
    });&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
// &amp;quot;onLoad&amp;quot;&lt;br /&gt;
showWaitCursor();  // Start the page off with the loading cursor, since we need to fetch categories&lt;br /&gt;
getCategories()&lt;br /&gt;
  .then(function(categories) {&lt;br /&gt;
    // Convert the categories ([&amp;#039;categoryA&amp;#039;, &amp;#039;categoryB&amp;#039;, ...]) into &amp;lt;option&amp;gt;category&amp;lt;/option&amp;gt; HTML&lt;br /&gt;
    var categoryOptions = &amp;#039;&amp;lt;option&amp;gt;&amp;lt;/option&amp;gt;&amp;#039; + categories.map(function(category) {&lt;br /&gt;
      return &amp;#039;&amp;lt;option value=&amp;quot;&amp;#039; + category + &amp;#039;&amp;quot;&amp;gt;&amp;#039; + category + &amp;#039;&amp;lt;/option&amp;gt;&amp;#039;;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    // Fill all three category selectors with the category options&lt;br /&gt;
    $(&amp;#039;#category1Cell&amp;#039;).html(&amp;#039;&amp;lt;select id=&amp;quot;category1&amp;quot;&amp;gt;&amp;#039; + categoryOptions + &amp;#039;&amp;lt;/select&amp;gt;&amp;#039;);&lt;br /&gt;
    $(&amp;#039;#category2Cell&amp;#039;).html(&amp;#039;&amp;lt;select id=&amp;quot;category2&amp;quot;&amp;gt;&amp;#039; + categoryOptions + &amp;#039;&amp;lt;/select&amp;gt;&amp;#039;);&lt;br /&gt;
    $(&amp;#039;#category3Cell&amp;#039;).html(&amp;#039;&amp;lt;select id=&amp;quot;category3&amp;quot;&amp;gt;&amp;#039; + categoryOptions + &amp;#039;&amp;lt;/select&amp;gt;&amp;#039;);&lt;br /&gt;
&lt;br /&gt;
    // Add the search button and results UL to the page (the wiki won&amp;#039;t let us do it without JS)&lt;br /&gt;
    $(&amp;#039;#controlsPlaceholder&amp;#039;)&lt;br /&gt;
      .html(&amp;#039;&amp;lt;button id=&amp;quot;searchCategories&amp;quot;&amp;gt;Search&amp;lt;/button&amp;gt;&amp;#039;)&lt;br /&gt;
      .after(&amp;#039;&amp;lt;h2&amp;gt;Search Results&amp;lt;/h2&amp;gt;&amp;lt;ul id=&amp;quot;results&amp;quot;&amp;gt;&amp;lt;/ul&amp;gt;&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
    // Bind the search button to its handler and set the cursor back to normal (the page is ready)&lt;br /&gt;
    $(&amp;#039;#searchCategories&amp;#039;).click(handleSearchClick);&lt;br /&gt;
    showNormalCursor();&lt;br /&gt;
  });&lt;/div&gt;</summary>
		<author><name>imported&gt;Loramin</name></author>
	</entry>
</feed>