Randomize flashcard multi-answer question based on common marker?

I know this can be a feature request that will go unanswered for eons so I am leaving this at the mercy of javascript experts on this forum.
I have just started using/playing with flashcards and I already see an issue: for questions having multiple answers to choose from I can quickly learn the position of the correct answer without trying (visual memory?) so I imagine that some javascript wizardry can be applied to solve this one.
I don’t know if there are any other solutions to this, like plugins, but I tend to favor minimal code for every specific need, hence my thinking of javascript for the rescue here.
Say I have the following Question:

Which one of these statements about branches is true?
● Branches enable independent development of the project.
● All commits must belong to the master branch.
● Only one branch per project is allowed.

Based on the “●” symbol to mark the answers that need being randomized in the order they appear in text, I don’t imagine this would be very difficult to record each line that begins with “●” into an array and then randomize the position of the array elements inside the array and modify the block’s text.

PS: I don’t need letters (a,b,c, …) in front of the answers because I offer the answer in full text so as to not overcomplicate the function to also modify the child-block. I simply need shuffling the order of the “●”-marked lines each time the block is “loaded?” …

Could you provide the underlying html?

  • that is from the inspector
  • it would be easier if each answer was in its own element
    • e.g. <li>
    • even better if those elements had a css class

Here’s a screenshot of the Flashcards Engine (G F) Popup, where I would need the bulleted (“●”) lines shuffled:

The Cards Panel (G F) seems to be this one:

but i believe even the following could be targeted,a s it also has “cards” in its name:

The HTML of this section seems to be:

<div class="ui__modal-panel transform transition-all sm:min-w-lg sm ease-out duration-300 opacity-100 translate-y-0 sm:scale-100 enter-done"><div class="ui__modal-close-wrap"><a aria-label="Close" type="button" class="ui__modal-close"><svg stroke="currentColor" viewBox="0 0 24 24" fill="none" class="h-6 w-6"><path d="M6 18L18 6M6 6l12 12" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"></path></svg></a></div><div class="panel-content"><div class="flex-1 cards-review" style="height: 100%;"><div class="flex flex-row items-center justify-between cards-title"><div class="flex flex-row items-center"><span class="ui__icon ti ls-icon-infinity "><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-infinity" width="18" height="18" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" style="font-size: 20px;"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M9.828 9.172a4 4 0 1 0 0 5.656a10 10 0 0 0 2.172 -2.828a10 10 0 0 1 2.172 -2.828a4 4 0 1 1 0 5.656a10 10 0 0 1 -2.172 -2.828a10 10 0 0 0 -2.172 -2.828"></path></svg></span><div class="relative ui__dropdown-trigger"><div class="ml-1 text-sm font-medium cursor"><span class="flex">All<span style="margin-top: 2px;"><svg aria-hidden="true" version="1.1" viewBox="0 0 192 512" fill="currentColor" display="inline-block" class="h-4 w-4"><path d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z" fill-rule="evenodd"></path></svg></span></span></div></div></div><div class="flex flex-row items-center"><div class="" data-tooltipped="" aria-describedby="tippy-tooltip-404" style="display: inline;"><div class="opacity-60 text-sm mr-3">4<span>/</span>6</div></div><div class="tippy-hover" data-tooltipped="" aria-describedby="tippy-tooltip-405" style="display: inline;"><a id="preview-all-cards" class="opacity-60 hover:opacity-100 svg-small inline font-bold">A</a></div><div class="tippy-hover" data-tooltipped="" aria-describedby="tippy-tooltip-406" style="display: inline;"><a class="mt-1 ml-2 block opacity-60 hover:opacity-100"><span class="ui__icon ti ls-icon-arrows-shuffle "><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrows-shuffle" width="18" height="18" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" style="font-size: 18px; font-weight: 600;"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M18 4l3 3l-3 3"></path><path d="M18 20l3 -3l-3 -3"></path><path d="M3 7h3a5 5 0 0 1 5 5a5 5 0 0 0 5 5h5"></path><path d="M21 7h-5a4.978 4.978 0 0 0 -2.998 .998m-4.002 8.003a4.984 4.984 0 0 1 -3 .999h-3"></path></svg></span></a></div></div></div><div class="px-1"><div id="cards-modal"><div class="ls-card content flex flex-col resize overflow-y-auto modal-cards"><div style="margin-top: 20px;"><div class="breadcrumb block-parents  my-2"><a><div class="" data-tooltipped="" aria-describedby="tippy-tooltip-407" style="display: inline;"><a tabindex="0" data-ref="tuesday, 05.12.2023" draggable="true" class="page-ref">Tuesday, 05.12.2023</a></div></a><span class="ui__icon ti ls-icon-chevron-right opacity-50 mx-1"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-right" width="18" height="18" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" style="font-size: 20px;"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><polyline points="9 6 15 12 9 18"></polyline></svg></span><span class="opacity-70">⋯</span><span class="ui__icon ti ls-icon-chevron-right opacity-50 mx-1"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-right" width="18" height="18" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" style="font-size: 20px;"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><polyline points="9 6 15 12 9 18"></polyline></svg></span><a><span class="inline-wrap">📝<span data-ref="Jurnal" class="page-reference">Jurnal</span></span></a></div></div><div class="blocks-container flex-1"><div haschild="true" class="ls-block 656f8f7d-4fb0-408d-b428-fb775d66e6d8" blockid="656f8f7d-4fb0-408d-b428-fb775d66e6d8" id="ls-block-6-656f8f7d-4fb0-408d-b428-fb775d66e6d8" data-refs-self="[&quot;card&quot;, &quot;tangenttags&quot;, &quot;sursa&quot;]" data-refs="[]"><div class="block-main-container flex flex-row pr-2 "><div class="block-control-wrap flex flex-row items-center"><a id="control-656f8f7d-4fb0-408d-b428-fb775d66e6d8" class="block-control"><span class="control-hide"><span class="rotating-arrow not-collapsed"><svg aria-hidden="true" version="1.1" viewBox="0 0 192 512" fill="currentColor" display="inline-block" class="h-4 w-4" style="margin-left: 2px;"><path d="M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z" fill-rule="evenodd"></path></svg></span></span></a><a class="bullet-link-wrap"><span id="dot-656f8f7d-4fb0-408d-b428-fb775d66e6d8" draggable="true" blockid="656f8f7d-4fb0-408d-b428-fb775d66e6d8" class="bullet-container cursor "><span blockid="656f8f7d-4fb0-408d-b428-fb775d66e6d8" class="bullet"></span></span></a></div><div class="flex flex-col block-content-wrapper"><div class="flex flex-row"><div class="flex-1 w-full" style="display: flex;"><div id="block-content-656f8f7d-4fb0-408d-b428-fb775d66e6d8" blockid="656f8f7d-4fb0-408d-b428-fb775d66e6d8" data-type="default" class="block-content inline" style="width: 100%;"><div class="flex flex-row justify-between block-content-inner"><div class="flex-1 w-full"><span class="inline"><mark><span data-ref="card" class="page-reference"><div class="" data-tooltipped="" aria-describedby="tippy-tooltip-408" style="display: inline;"><a tabindex="0" data-ref="card" draggable="true" class="page-ref">⚡</a></div></span></mark> <mark><code>Flashcard</code></mark>  <a href="file:///D%3A/2.PersonalData/1.Projects/7.Journaling/%20'" data-href="D:/2.PersonalData/1.Projects/7.Journaling/ '" target="_blank">🏷️</a>  </span></div></div><div title="Click to edit this block's properties" class="block-properties"><div><div class="" data-tooltipped="" aria-describedby="tippy-tooltip-409" style="display: inline;"><a tabindex="0" data-ref="sursa" draggable="true" class="page-ref page-property-key block-property">sursa</a></div><span class="mr-1">:</span><div class="page-property-value inline"><div class="inline mr-1"></div></div></div><div><div class="" data-tooltipped="" aria-describedby="tippy-tooltip-410" style="display: inline;"><a tabindex="0" data-ref="tangenttags" draggable="true" class="page-ref page-property-key block-property">tangenttags</a></div><span class="mr-1">:</span><div class="page-property-value inline"><div class="inline mr-1"></div></div></div></div><div class="block-body"><div class="is-paragraph"><a href="file:///D%3A/2.PersonalData/1.Projects/7.Journaling/%20'" data-href="D:/2.PersonalData/1.Projects/7.Journaling/ '" target="_blank"></a><br>Which one of the following statements about version control is true?<br>● Version control only manages source code.<br>● You must be online to use distributed version control.<br>● With distributed version control, each user has a local copy of the project history.<br></div><div class="table-wrapper"><table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides" class="table-auto"><tbody></tbody><tbody><tr><td scope="col" class="org-left"><a href="file:///D%3A/2.PersonalData/1.Projects/7.Journaling/%23" data-href="D:/2.PersonalData/1.Projects/7.Journaling/#" target="_blank" title="With distributed version control, each user has a local copy of the project history. ">correct answer</a></td><td scope="col" class="org-left"><a href="file:///D%3A/2.PersonalData/1.Projects/7.Journaling/%23" data-href="D:/2.PersonalData/1.Projects/7.Journaling/#" target="_blank" title="Each user has a local repository, containing the project history as a collection of commits.">Notes</a></td></tr></tbody></table></div></div></div></div><div class="flex flex-row items-center"></div></div></div></div></div></div><div class="flex my-4 justify-between"><button type="button" id="card-answers" class="ui__button bg-indigo-600 hover:bg-indigo-700 focus:border-indigo-700 active:bg-indigo-700 text-center card-answers mr-2"><span>Show answers</span></button></div></div></div></div></div></div></div>

I find no way to copy this HTML as a tree structure so I don’t know if it’s of any help but in the screenshots I tried to get all that I believe is important…

I tried to collapse all elements that are not of interest for this endeavor so the ones in this screenshot should be ones that can be targeted to reach the lines to be shuffled:

ChatGPT to the rescue :partying_face::

<div class="ui__modal-panel transform transition-all sm:min-w-lg sm ease-out duration-300 opacity-100 translate-y-0 sm:scale-100 enter-done">
  <div class="ui__modal-close-wrap">
    <a aria-label="Close" type="button" class="ui__modal-close">
      <svg stroke="currentColor" viewBox="0 0 24 24" fill="none" class="h-6 w-6">
        <path d="M6 18L18 6M6 6l12 12" stroke-width="2" stroke-linejoin="round" stroke-linecap="round"></path>
      </svg>
    </a>
  </div>
  <div class="panel-content">
    <div class="flex-1 cards-review" style="height: 100%;">
      <div class="flex flex-row items-center justify-between cards-title">
        <div class="flex flex-row items-center">
          <span class="ui__icon ti ls-icon-infinity ">
            <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-infinity" width="18" height="18" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" style="font-size: 20px;">
              <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
              <path d="M9.828 9.172a4 4 0 1 0 0 5.656a10 10 0 0 0 2.172 -2.828a10 10 0 0 1 2.172 -2.828a4 4 0 1 1 0 5.656a10 10 0 0 1 -2.172 -2.828a10 10 0 0 0 -2.172 -2.828"></path>
            </svg>
          </span>
          <div class="relative ui__dropdown-trigger">
            <div class="ml-1 text-sm font-medium cursor">
              <span class="flex">All<span style="margin-top: 2px;">
                <svg aria-hidden="true" version="1.1" viewBox="0 0 192 512" fill="currentColor" display="inline-block" class="h-4 w-4">
                  <path d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z" fill-rule="evenodd"></path>
                </svg>
              </span>
              </span>
            </div>
          </div>
        </div>
        <div class="flex flex-row items-center">
          <div class="" data-tooltipped="" aria-describedby="tippy-tooltip-411" style="display: inline;">
            <div class="opacity-60 text-sm mr-3">4<span>/</span>6</div>
          </div>
          <div class="tippy-hover" data-tooltipped="" aria-describedby="tippy-tooltip-412" style="display: inline;">
            <a id="preview-all-cards" class="opacity-60 hover:opacity-100 svg-small inline font-bold">A</a>
          </div>
          <div class="tippy-hover" data-tooltipped="" aria-describedby="tippy-tooltip-413" style="display: inline;">
            <a class="mt-1 ml-2 block opacity-60 hover:opacity-100">
              <span class="ui__icon ti ls-icon-arrows-shuffle ">
                <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-arrows-shuffle" width="18" height="18" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" style="font-size: 18px; font-weight: 600;">
                  <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
                  <path d="M18 4l3 3l-3 3"></path>
                  <path d="M18 20l3 -3l-3 -3"></path>
                  <path d="M3 7h3a5 5 0 0 1 5 5a5 5 0 0 0 5 5h5"></path>
                  <path d="M21 7h-5a4.978 4.978 0 0 0 -2.998 .998m-4.002 8.003a4.984 4.984 0 0 1 -3 .999h-3"></path>
                </svg>
              </span>
            </a>
          </div>
        </div>
      </div>
      <div class="px-1">
        <div id="cards-modal">
          <div class="ls-card content flex flex-col resize overflow-y-auto modal-cards">
            <div style="margin-top: 20px;">
              <div class="breadcrumb block-parents my-2">
                <a>
                  <div class="" data-tooltipped="" aria-describedby="tippy-tooltip-414" style="display: inline;">
                    <a tabindex="0" data-ref="tuesday, 05.12.2023" draggable="true" class="page-ref">Tuesday, 05.12.2023</a>
                  </div>
                </a>
                <span class="ui__icon ti ls-icon-chevron-right opacity-50 mx-1">
                  <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-right" width="18" height="18" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" style="font-size: 20px;">
                    <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
                    <polyline points="9 6 15 12 9 18"></polyline>
                  </svg>
                </span>
                <span class="opacity-70">⋯</span>
                <span class="ui__icon ti ls-icon-chevron-right opacity-50 mx-1">
                  <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-right" width="18" height="18" viewBox="0 0 24 24

Edit:
If it would make it easier to target (even if this would make thinks more difficult to me bacause I would’t be able to drop question and aswers in the same place and would need to separately place the question in the block’s Title), I can leave just the lines to be shuffled inside the “block-body”:

Try adding the following in custom.js :

const modalObserver = new MutationObserver(function onMutated(){
    const div = document.querySelector(".ui__modal .is-paragraph")
    if (!div || div.textContent === div.oldContent) return

    const nodes = Array.prototype.map.call(div.childNodes, (n)=>n ).
                  filter( (n)=>n.nodeType===Node.TEXT_NODE )
    const factor = nodes.length - 1
    const random = nodes.map( ()=>Math.round(Math.random()*factor) )
    const t = document.createTextNode("")
    nodes.forEach( (n, i)=>{
        const o = nodes[random[i]]
        o.replaceWith(t)
        n.replaceWith(o)
        t.replaceWith(n)
    })
    div.oldContent = div.textContent
})
modalObserver.observe(document.querySelector(".ui__modal"), {
    childList: true,
    subtree: true,
    attributeFilter: ["class"]
})

This works wonderfully. I don’t understand all of the code but I managed to add a filter for the “●”-character so that it randomizes the order only for “'●”-including lines and it seems to work properly.

.filter( (n)=>n.textContent.includes('●') && n.nodeType===Node.TEXT_NODE);

I did this because I need my flashcards to also be atomic notes so they include a lot of info in them, including the answer and it might be that in future some other info gets included that will be randomized as well. Narrowing it down as much as possible will ensure long-term proper function.

Thanks for the code @mentaloid !