Help with Incremental Cloze Reveal

I found the card template for incremental cloze reveal (which reveals the cloze upon clicking on the cloze bracket). Is there a way to rehide the cloze upon clicking on the cloze bracket again? Could someone modify this code for me?

Here is the code.

Card Front Side

<script>
var logDiv = null;
function log(s) {
  if (logDiv == null) {
    logDiv = document.createElement("div");
    logDiv.id = 'log_debug';
    logDiv.style = 'position:absolute;left:0;top:0;z-index:-2;color:grey;font-size:small';
    document.body.append(logDiv);
  }
  logDiv.insertAdjacentHTML('beforeend', s + '<br/>');
}
/*
function logSizes() {
  let ovl = document.getElementById('tap_overlay');
  let rect = ovl.getBoundingClientRect();
  let vp = window.visualViewport;
  log(`ovl: ${rect.width.toFixed(2)},${rect.height.toFixed(2)} vp: ${vp.width.toFixed(2)},${vp.height.toFixed(2)}`);
}
*/


function getCardNumber() {
  clz = document.body.className;
  const regex = /card(\d+)/gm;
  let m;

  if ((m = regex.exec(clz)) !== null) {
    return m[1];
  } else {
    console.error("Cannot find cardN class of body element!");
    return "0";
  }
}

function getClozes(str, cardNumber) {
  const regex = new RegExp(`\{\{c${cardNumber}::(.*?)(\}\}|::.*?\}\})`, 'gm')
  //console.log(regex);
	let m;
  const clozes = [];
	while ((m = regex.exec(str)) !== null) {
		// This is necessary to avoid infinite loops with zero-width matches
		if (m.index === regex.lastIndex) {
			regex.lastIndex++;
		}
		m.forEach((match, groupIndex) => {
			//console.log(`Found match, group ${groupIndex}: ${match}`);
     if (groupIndex == 1) {
				clozes.push(match);
			}
		});
	}
  return clozes;
}

function clickHandler(e){
   //console.log(`${e.target.tagName}(${e.target.id})`);
   const tt = e.target
   if ( tt instanceof HTMLElement &&
       ( tt.id === 'qa' || 
         tt.tagName === 'HTML' ||
         tt.tagName === 'LI' ||
         tt.tagName === 'I' )) {
     //log('reveal');
     revealNextCloze();
   }
}


var elements;
var clozes;
var revealed = [];

function revealCloze(i) {
  if (!revealed[i]) {
    elements[i].innerHTML = clozes[i];
    revealed[i] = true;
  }
}

function revealNextCloze() {
  firstUnrevealed = revealed.findIndex ( el => !el );
  //log(firstUnrevealed);
  if (firstUnrevealed != -1) {
    revealCloze(firstUnrevealed);
  } 
}

onUpdateHook.push(function() {
  //console.log(`inside update hook`);

	var text = document.getElementById("rawText").innerHTML ;
	//console.log(text);
	clozes = getClozes(text, getCardNumber());
  //console.log(clozes);
	
	elements = document.querySelectorAll(".cloze");

  if (clozes.length != elements.length) {
    console.error("Inconsistent cound of clozes found in original note text and in the card!");
    return;
  }
  elements.forEach((el, i) => {
    el.addEventListener('click', e => {
      revealCloze(i);
      //log(i);
    })
  });
  revealed.length = elements.length;
  revealed.fill(false);
  
  window.addEventListener('click', clickHandler);

});

</script>
<script id="rawText" type="text/plain">
{{Text}}
</script>
{{cloze:Text}}

Card Back Side

<script>
  window.removeEventListener('click', clickHandler);
</script>
{{cloze:Text}}<br>
{{Extra}}


Credit to this person for the code:

foenixx

Native cloze card with incremental reveal - AnkiWeb

You have a function that gets called onclick named revealCloze(i);. This same function could also hide the cloze again. For that you would:

  • add an if statement checking if the .cloze had been revealed,
  • change the cloze’s text back to what it was before revealing and
  • then declare that the cloze is not revealed anymore:
function revealCloze(i) {
  if (!revealed[i]) {
    elements[i].innerHTML = clozes[i];
    revealed[i] = true;
  } else if (revealed[i]) {
    elements[i].innerHTML = "[...]";
    revealed[i] = false;
  }
}
2 Likes

Yes!!! Thank you so much for the help!!!

1 Like

So following up on this, I am wondering if this is possible:

Suppose you have a list of cloze items

  • {{c1::A}}
  • {{c1::B}}
  • {{c1::C}}
  • {{c1::D}}
  • {{c1::E}}

Is there a way to reveal a single cloze bracket and keep it revealed till the next time the c1 cloze is shown again, meaning that it doesn’t reset every time I review a different card:question: And of course a way to manually reset the brackets again…

  • A
  • […]
  • […]
  • […]
  • […]

That would be extremely helpful!

So you have this list of clozes in the same card?

So if I understand this correctly, you’d like to review cloze Card 1, reveal a c1 cloze in that card, then grade yourself and review another Card 2. When you then return to Card 1, you’d like the already revealed cloze to still be revealed.

If I understood that correctly then there’s not much I can help with, since I do not have enough knowledge to achive the desired result. Probably best if you open a new topic for that so that someone more knowledgeable can have a look.

Yes exactly. Thanks for your consideration. I will open a new topic. :+1:

Edit: Now solved with just a tiny bit of problem.

It’s generally not necessary to open another topic to continue talking about the same thing. :+1:t4:

Normally I’d agree but in this case I don’t think it’s the same thing.

The topic here basically was “How to re-hide clozes with incremental cloze reveal”.
The follow-up question was “How to show clozes and make it persist during reviews.”

I get that they are somewhat related but at the same time they are quite different. Maybe the minimum information principle is too ingrained in my brain though.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.