Veav Bork
Veav Bork

Reputation: 11

How do I properly iterate, match, and splice spans with getelementsbyclassname?

I'm trying to put together a thing that will add tooltips to a page whenever a word has a definition. I have partially succeeded in doing so. The thing: https://codepen.io/veav/pen/vYqdEdB

The setup is intended to grab spans from the page with a class of "check" and check if their content can be found in a set of keywords. If it finds a keyword, it splices a new span in place with a class of "tooltip", then opens the next "check" span to house the remaining content.

Right now, one of three things is happening at any given time: it only splices a tooltip onto the last match for a keyword, it only splices tooltips for the last keyword in the dictionary, or it splices tooltips into the meta text of a tooltip span, because a tooltip's text can potentially contain a keyword. The class "check" is intended to prevent this.

I know that this is 200% user error but I don't know the right questions to ask in order to fix my mistakes. Am I completely off-base with my approach?

const keywords = {
  "background": "pg 20. Your pilot`s background describes their life before they became a mech pilot.",
  "invoke": "pg 20. Outside of combat, you (or the GM) can invoke your pilot`s background to receive 1 ACCURACY or 1 DIFFICULTY on any skill check, if their background is relevant.",
  "ACCURACY": "pg 13. ACCURACY adds 1d6 to a roll. Multiple ACCURACY dice are a keep-highest roll. ACCURACY and DIFFICULTY cancel each other out on a 1:1 basis.",
  "DIFFICULTY": "pg 13. DIFFICULTY adds 1d6 to a roll. Multiple DIFFICULTY dice are a keep-highest roll. ACCURACY and DIFFICULTY cancel each other out on a 1:1 basis."
};

function tooltipper() {
  var spans = document.getElementsByClassName('check');
  for (var y in keywords) {
    for (var x of spans) {
      console.log('checking ' + y + ' against span ' + x.innerHTML + '...');
      var spantipper = inserttip(x, y);
      if (typeof spantipper !== 'undefined') {
        console.log('final before: ' + x.innerHTML);
        x.innerHTML = spantipper;
        console.log('final after: ' + x.innerHTML);
      } else {
        console.log(y + ' not found in span' + x.innerHTML.substr(0, 50) + '...');
      }
    }
  }
}

function inserttip(brick, keyword) {
  var bricktext = brick.innerHTML;
  var brickpost = '';
  var brickpre = brick.innerHTML;
  var match = brickpre.indexOf(keyword);
  var ogmatch = bricktext.indexOf(keyword);
  while (match != -1) {
    console.log(keyword + ' found')
    var brickopen = match;
    var brickclose = match + keyword.length;
    var remaining = brickpre.length - brickclose;
    brickpost += brickpre.substr(0, match);
    brickpost += '</span><span class="tooltip" data-tooltip="' + keywords[keyword] + '" data-tooltip-position="bottom">' + keyword + '</span><span class="check">';
    console.log('set: ' + brickpost)
    brickpre = brickpre.substr(brickclose, remaining);
    console.log('marched: ' + brickpre.substr(0, 50) + '...');
    match = brickpre.indexOf(keyword);
    if (match == -1) {
      console.log('end of matches for ' + keyword);
    }
  }
  if (ogmatch != -1) {
    brickpost += brickpre;
    return brickpost;
  }
}

Upvotes: 1

Views: 46

Answers (1)

Veav Bork
Veav Bork

Reputation: 11

With @Barmar's insight, it's not dumb if it works:

function tooltipper() {
  var spans = document.getElementsByClassName("check");
  for (var x of spans) {
    var step1 = x.innerHTML;
    for (var y in keywords) {
      var step0 = '%%'+y+'%%';
      step1 = step1.replaceAll(y, step0);
    }
    for (var y in keywords) {
      var step0 = '%%'+y+'%%';
      var step3 =
        '</span><span class="tooltip" data-tooltip="' +
        keywords[y] +
        '" data-tooltip-position="bottom">' +
        y +
        '</span><span class="check">';
      step1 = step1.replaceAll(step0, step3);
    }
    x.innerHTML = step1;
  }
}

There's still some residual nonsense if two definitions match on the same keyword (e.g. "invoke" and "invoked") but grammar isn't everything.

Upvotes: 0

Related Questions