Card Name Similarity Tool

by skibulk

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/umd/string-similarity.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.0/papaparse.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/browser/bundle.umd.min.js"></script>
<h1>Card Name Similarity Tool</h1>
<p><b>Purpose:</b> Enter a list of proposed names and it will be compared to <a href=''>this list of printed names</a>. Any duplicate and/or similar names will be shown below.</p>
<p><b>Whole-Name Similarity:</b> Similarity scores will be calculated for every combination of proposed name and printed name. The proposed names will be sorted and listed below, with the highest scores shown to their left. Click any score to view relevant matches. Each match will have a score shown to its left, indicating the similarity of the printed name to the proposed name.</p>
<p><b>Single-Word Similarity:</b> Every word in the proposed names will also compared to every word in the printed names. The number of similar words will be indicated in parentheses. Click any word to view its matches. Each match will have a score shown to its left, indicating the similarity of the underlined printed word to the proposed word.</p>
<div id="status">
  <p><b>Loading printed names...</b></p>
</div>
<h2>Proposed Names</h2>
<p>Enter each name on a separate line, or click the button to use example names (this will overwrite anything entered beforehand).</p>
<p><button disabled>Use Examples Names</button></p>
<textarea id="input" rows="10" disabled></textarea>
<h2>Results</h2>
<div id="results"></div>

CSS

html, body {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: Arial,Helvetica Neue,Helvetica,sans-serif;
}

body {
  padding: 20px;
  margin: 0 auto;
  max-width: 600px;
  overflow-y: scroll;
}

button {
  margin: 0 5px;
  padding: 5px 10px;
}

textarea {
  width: 100%;
}

button[disabled], textarea[disabled]{
  background: #ddd;
  color: #666;
}

#results {
  margin: 30px 0;
}

.result {
  margin-bottom: 15px;
}

.result-name {
   user-select: none;
}

.result span {
  padding: 5px 10px;
  border-radius: 999px;
  display: inline-block;
}

.best {
  border: 1px solid black;
  background: black;
  color: white;
}

.score {
  border: 1px solid black;
}

.result .miss {
  padding: 5px;
}

.hit {
  border: 1px solid black;
}

.result-details {
  margin: 20px 0;
}

.result-details p {
  margin: 5px 0;
}

.ref {
  color: gray;
}

JavaScript

/*
Card Name Similarity Tool
©2021 White Wizard Games LLC

"Source" data is loaded from Google Sheets.

"Input" data is entered by the user.

sourceUnits and inputUnits are objects that represent a single row or line of data from the sources and input, respectively.

Note: If a proposed word matches multiple words in a single printed name, the printed name will appear multiple times in the matches list. For example, "tark" matches both DARK and STAR in "Pirates of the Dark Star", so Pirates will be listed twice.

For Future Consideration:
Add manual "exclude sets" textbox - easier
Add checkboxes to disable card sets - harder
Show expansion names in matches
Highlight last clicked "parent" result
Check proposal list against itself?
Spell Check? https://jsfiddle.net/skibulk/ztkLemoc/
Word Stemming?
POS Tagger to filter adverbs, etc? (Parts of Speech)
*/

(function() {
  "use strict";

  console.clear();
  //console.log(getRatings('The', ['Tho', 'he']));

  var i, j, k, l;

  // jQuery-wrapped DOM References
  var $status = $('#status');
  var $button = $('button');
  var $input = $('textarea');
  var $results = $("#results");

  // DOM Status
  var prevInput = '';
  var prevDetails = null;

  // Source Links
  // To target a specific sheet in a spreadsheet: https://adamlofting.com/1098/new-google-sheets-publishing-a-single-worksheet-to-the-web-as-csv/
  var sources = [ //
    {
      "game": "SR",
      "url": "https://docs.google.com/spreadsheets/d/e/2PACX-1vTej7j-F2ljLeBrR6VTaaFbq6f2lHBfcymkLFpmTlQc7dNFuq1s8Goo-yUBpcq8R_kFRBymkc1vRb-W/pub?gid=0&single=true&output=csv",
    },
    {
      "game": "HR",
      "url": "https://docs.google.com/spreadsheets/d/e/2PACX-1vSp3V_jrlxAwE5zZFG_t87J3Y6T3vchWH8dHFaYS9ZDeb15Fk1E1Ch-kF9iYcpphZQuUfxKvZwD7JpV/pub?output=csv",
    },
  ];

  // Current loading position
  var sourcesIndex = 0;

  /*
	sourceUnit = {
  	game: "HR",
    index: 0,
    rawName: "Mighty Dragon",
    name: "mighty dragon"
  }
  */

  var sourceUnitsByOrder =...