Closet For Anki [Official support]

Thank you for your reply.

The issue is a little more complicated however.

In order to generate a cloze overlapping list with 10 items you need to configure the card type to generate 10 cards, one for each cloze.

When using the same card type only entering 5 items, it will also generate 10 cards. The last 5 cards will only show:

Question





on both sides.

I am looking for a way to not generate these specific cards, where there is no cloze operator ([[chx::), where x is the number matching with the card position in the card type.

Basically, the card type should generate 5 cards if ch1:: to ch5:: are used in the awnser field, an 10 cards if ch1 to ch10 are used.

Well, you still need to use conditional card creation.

Please read my previous answer again. The video should be helpful too, I included a timestamp to the relevant part. Also, see the chapter on Conditional Replacement in the Anki manual.


Closet automatically fills fields whose names end with a number if you use the cloze shortcut.

  • create c1 → cmds1 is filled
  • create c2 → cmds2 is filled

The main purpose of these cmds fields is to either be empty (no card created) or filled (card created) → conditional card creation.

This means that with a correctly set up template, only as many cards will be created as cmds fields are filled.

Oh wow, completly overlook that. I knew about conditional card creation, but not of the cmds functionality of closet. That’s awesome.

Edit: After looking into it, it appears the filling of the cmds fields only happens automatically for adding new cards and using the cloze-shortcut, right?

Is there a way how this can be automated for editing cards? In my brief testing, when editing cards as in removing or adding clozes, the automation doesn’t work.

Removing clozes: the corresponging cmds-field stays “active”.
Adding clozes: Works for adding new clozes with the shortcut, but not if I am using the hinding cloze (ch)

Do you have any ideas on that?

It only works for the shortcuts. Otherwise there’d have to be constant parsing going on with every keystroke.

Any way it could be updated when you edit a card and close the edit window (update once) or when a card is edited in the browser?

Thanks for all your help guys!

That’s unfortunately not possible. It think for best experience you should try to use the shortcuts if possible.

For the way I intend to use closet that is not possible, but thank you for your time, both of you. :slight_smile:

Is there a way to set up Closet so that I can combine the features of image occlusion and incremental reveal? I have a lot of tree diagrams I need to learn and my idea is to occlude each step of the diagram, and make it so that it only reveals the rectangle that I click on. Ideally this would all be on one card rather than multiple cards

Currently, the way to set up the add on is the same as the video on youtube?

I’m not able to make it work.

Update 02.08.21: This should work with arbitrary card indices.

I don’t know why closetPromise.then() didn’t work when I first tried it, but it seems to work reliably now that I’ve tried it again. The following script has to be inserted into the Closet setup, but only on the front template (check out the sample note type with Asset Manager to see how I did that with an HTML snippet):

closetPromise.then(() => {

    if ((rect = document.querySelector(".closet-rect.is-active")) != null) incrementalIO(rect)

    function incrementalIO(first) {
        for (rect of document.querySelectorAll(".closet-rect.is-active")) {
            rect.classList.remove("is-active")
        }
        activate(first)
    }

    function activate(rect) {
        rect.classList.add("is-active")
        rect.addEventListener("click", reveal)
    }

    function reveal() {
        this.classList.remove("is-front")
        this.classList.add("is-back")
        if ((next = this.nextElementSibling) != null) {
            activate(next)
        }
    }
})
How to create the notes

While adding new occlusion rectangles, hold Alt to keep the index at 1. That way only one card will be created.

e.g.:

[#!occlusions [[rect1::141,197,360,92]]
[[rect1::326,484,175,88]]
[[rect1::263,781,282,63]]
[[rect1::725,540,302,71]]
[[rect1::772,190,348,58]]
[[rect2::29,416,68,241]]
[[rect2::107,886,275,56]]
[[rect2::458,886,321,54]]
[[rect2::1044,884,114,49]]
[[rect3::392,34,453,63]] #]

Showcase

Kooha-2021-07-18-14_21_02


Update 02.08.21: Keeping this question here for legacy purposes
@hengiesel I would love to know how to execute scripts like this one directly after Closet. Is there a way to access a promise and use .then()? Using setTimeout() feels hacky :slight_smile:

1 Like

Your showcase is perfect for what I am trying to do, but I can’t make it happen. When I add the script (along with the Java condition) it doesn’t change anything. It writes it into the template, but nothing changes when I review the card, all rectangles are occluded at once and do not ‘flip’ when I click on them. Do I need to remove the Closet Setup script from my template to make it work?

Could be that the timeout isn’t long enough for your system. You could try to increase the 50 to 100. But that’s still unreliable in my opinion. I already asked Henrik for a better way to execute the script after Closet. Let’s see what he has to say…


Actually, closetPromise.then(() => { script }) would work, if the script were inserted below the declaration of closetPromise - instead of setTimeout. I’ll look into it.

2 Likes

I guess the canonical way would be to use aftermath actions:

You can see them in action in the cloze incremental reveal examples on the website.

While trying to implement it myself, I realized, that there needs to be a way to pass deferred options, when using closet.wrappers.aftermath, so you can set a lower priority, and make sure it’s executed after the rects were rendered, otherwise there’s no way to implement it canonically currently :frowning:
I’ll open a bug report for it.

2 Likes

I updated the script in my post above. Now, it executes after the first rectangle is rendered. This should make it work for you too.

Let me know if there are any other hurdles we need to tackle for your workflow.

1 Like

I’m still getting all occlusions blocked out at once, and nothing happens when I click on them, I have to hit the answer button which causes all boxes to reveal. I’m on Anki 2.1.35, is that causing an issue?

My front template set up right now is:
Anki persistence (in its own script)
Closet set up (in its own script)
The newest code you posted above (var observer) (in its own script)

Back template is:
Anki persistence
Closet set up

What am I doing wrong?? (Thanks so much for your help)

I just tried it with 2.1.35 and it worked :thinking:

Here’s a sample note: Incremental Image Occlusion Sample - AnkiWeb

If that works, you could compare the Asset Manager setup of that note with your own to find the problem. Otherwise, we can start a private chat so as to not bloat this thread too much and I’m sure we’ll find a solution.

I find your idea very intriguing and I’d like to make it more viable in a general sense. This will take some more time though.


@Random231 That sample note could be helpful for you too. It has the default Closet setup. To get more cards, simply add more cmds fields to your note type + more card templates in the template editor, open Asset Manager and click “Write to Templates”.

1 Like

I wanted add this set up:
Graphical effects

i follow the youtube video (Image Occlusions, Clozes, Multiple Choice, Shuffling | Closet Introduction and Tutorial - YouTube) but couldn’t get it.

My question is: The video is outdated or did i overlook something?

In my asset manager there’s no Closet user code, only Closet set up.

That worked!!! Seriously, thank you so much. This is such a huge asset for my workflow. If you do decide to tweak it and I can help test it, let me know. But for now this is perfect.

2 Likes

That’s the same thing. Within the setup, there is a section where it says

/* here goes the setup - change it to fit your own needs */

That’s where you put your custom code.

Both the YouTube tutorial and the website examples are a bit outdated. The necessary changes you need to make have already been discussed in this thread, but to save you some time, here’s what you need to do to get your multiple choice setup working:

Styling (CSS)

Closet no longer injects styling via the user setup, so you need to move these parts to the note template.

What you need to do

Add the following CSS to the styling section of your note template:

.cl--container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  grid-gap: 0px 40px;
  margin: 40px auto;
}

.cl--card {
  cursor: pointer;
  position: relative;
  height: 0;
  padding-bottom: 100%;
  transition: transform 0.6s ease;
  --translate: 0;
  transform: translate(var(--translate), var(--translate));
}

.cl--card:hover {
  --translate: calc(-5px);
  transition: transform 0.3s ease;
}

.cl--child {
  position: absolute;
  width: 100%;
  height: 80%;

  padding: 8px 16px;
  background: #fff;
  box-shadow: 0px 4px 8px rgba(128, 128, 128, 0.1), 0px -4px 8px rgba(255, 255, 255, 0.8);
  border-radius: 6px;
  transition: inherit;
  transform: translate(var(--translate), var(--translate));
  z-index: 5;
}

.cl--child > h3 {
  color: black;
}

.cl--reveal .cl--category-0 {
  background-color: lime;
}

.cl--reveal .cl--category-1 {
  background-color: coral;
}

Changed file structure

Since version 0.5.0, Closet has a slightly different file structure.

closet.recipes

became

closet.flashcard.recipes
What you need to do

Insert the following code into the closet setup. This is the same code as seen on the website, but with the necessary changes applied to get it working again.

/** Fancy multiple choice */

const wrappedMultipleChoiceShow = closet.wrappers.aftermath(closet.flashcard.recipes.multipleChoice.show, (e, inter) => {
  document.querySelectorAll('.cl--child')
    .forEach(v => v.addEventListener('click', () => {
      const container = document.querySelector('.cl--container')

      if (container) {
        container.classList.add('cl--reveal')
      }
    }))

  const keyword = 'fancyMultipleChoice'

  if (!inter.environment.has(keyword)) {
    inter.environment.set(keyword, true)
  }
})

const wrapItem = (v, _i, cat) => `<div class="cl--card"><div class="cl--child cl--category-${cat}"><h3>${v}</h3></div></div>`

filterManager.install(wrappedMultipleChoiceShow({
  tagname: 'mc',
  frontStylizer: closet.Stylizer.make({
    mapper: wrapItem,
    separator: '',
    processor: (v) => `<div class="cl--container">${v}</div>`,
  }),
  backStylizer: closet.Stylizer.make({
    mapper: wrapItem,
    separator: '',
    processor: (v) => `<div class="cl--container cl--reveal">${v}</div>`,
  }),
}))

That should be all the changes you need to make to get this effect working:
image

1 Like

My set up
C8GPTktoTn

Card template:

y5rKtbXzDQ

It doesn’t seem to work.

Do i need anki persistence?