RisingOrange / anki-enhanced-cloze

20 stars 3 forks source link

Enhanced Cloze cards show up blank on AnkiWeb #81

Open asheeeep opened 1 year ago

asheeeep commented 1 year ago

My cards are showing up blank when I am using AnkiWeb. When I click “edit,” all the information is there, but nothing shows up on the card. Any suggestions on how to address this?

Thank you!

practical-solutions commented 5 months ago

This is due to AnkiWeb not using jQuery. I tried a bit and it can be done. It isn't working perfectly (yet), becaus if you use AnkiWeb, it loads the awnser oft the last question into the front side of the next. But at least, you can click on show awnser and see it correctly then. The was my first try (quick and dirty), but may be a starting point. Maybe you can clean up the code based on this solution. In general, I think it would be better to create code without jquery.

Here the code (only front side modified):

<!-- VERSION 1.9 -->
<!-- modified for AnkiWeb comptability -->

<script>
var already = false;

function loadjQuery(url, callback) {
   var script = document.createElement("script");
   script.type = "text/javascript";

   // When the script loads, run the callback
   script.onload = function() {
      callback();
   };

   script.src = url;
      document.getElementsByTagName("head")[0].appendChild(script);
   }

   // Check if jQuery is loaded
   if (typeof jQuery === 'undefined') {
      // If jQuery is not loaded, load it from a CDN
      loadjQuery("https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js", function() {
         document.getElementById("status").innerHTML = "jQuery has been loaded.";
                    loadIt();
      });
   } else {
      // jQuery is already loaded
      //document.getElementById("status").innerHTML = "jQuery was already loaded.";
          already = true;
}
</script>

<script>
    var scrollToClozeOnToggle = true
    var animateScroll = true
    var showHintsForPseudoClozes = true
    var underlineRevealedPseudoClozes = false
    var underlineRevealedGenuineClozes = true
    var revealPseudoClozesByDefault = false

    // Shortcut options
    var revealNextGenuineClozeShortcut = "J"
    var revealAllGenuineClozesShortcut = "Shift+J"

    var revealNextPseudoClozeShortcut = "N"
    var revealAllPseudoClozesShortcut = "Shift+N"
</script>
<!-- CONFIG END -->

<div id="card-body">
    <div id="main-section" class="content">
        <!-- this element will contain the actual content - the enhanced clozes -->
        <span id="enhanced-clozes"></span>
    </div>
    <br>
    <br>

        <div id="functional-elements">
            <div id="show-one-cloze-left"></div>
            <div id="show-one-cloze-right"></div>
            <div id="no-more-cloze"></div>
        </div>
    </div>
</div>

<!-- ENHANCED_CLOZE -->
<span id="enhanced-cloze-content" style="display:none">{{Text}}</span>
<span style="display:none;" id="edit-clozes">{{edit:cloze:Text}}</span>

<!-- this needs to exist so that Anki does not complain -->
<span style="display:none">{{cloze:Text}}</span>

<script>

function loadIt(){

    var enhancedClozesData = {
        "clozeId": [],
        "answers": [],
        "hints": [],
    }

    $(function () {
        defineEnhancedClozeAddEventListener()
        prepareEnhancedClozes()
        initializeEnhancedClozes()
        setupEditFieldDuringReview()
        insertStyling()

        function prepareEnhancedClozes(genuineClozeOrd) {
            var ord =
                `{{#c1}}1{{/c1}}{{#c2}}2{{/c2}}{{#c3}}3{{/c3}}{{#c4}}4{{/c4}}{{#c5}}5{{/c5}}{{#c6}}6{{/c6}}{{#c7}}7{{/c7}}{{#c8}}8{{/c8}}{{#c9}}9{{/c9}}{{#c10}}10{{/c10}}{{#c11}}11{{/c11}}{{#c12}}12{{/c12}}{{#c13}}13{{/c13}}{{#c14}}14{{/c14}}{{#c15}}15{{/c15}}{{#c16}}16{{/c16}}{{#c17}}17{{/c17}}{{#c18}}18{{/c18}}{{#c19}}19{{/c19}}{{#c20}}20{{/c20}}{{#c21}}21{{/c21}}{{#c22}}22{{/c22}}{{#c23}}23{{/c23}}{{#c24}}24{{/c24}}{{#c25}}25{{/c25}}{{#c26}}26{{/c26}}{{#c27}}27{{/c27}}{{#c28}}28{{/c28}}{{#c29}}29{{/c29}}{{#c30}}30{{/c30}}{{#c31}}31{{/c31}}{{#c32}}32{{/c32}}{{#c33}}33{{/c33}}{{#c34}}34{{/c34}}{{#c35}}35{{/c35}}{{#c36}}36{{/c36}}{{#c37}}37{{/c37}}{{#c38}}38{{/c38}}{{#c39}}39{{/c39}}{{#c40}}40{{/c40}}{{#c41}}41{{/c41}}{{#c42}}42{{/c42}}{{#c43}}43{{/c43}}{{#c44}}44{{/c44}}{{#c45}}45{{/c45}}{{#c46}}46{{/c46}}{{#c47}}47{{/c47}}{{#c48}}48{{/c48}}{{#c49}}49{{/c49}}{{#c50}}50{{/c50}}{{#c51}}51{{/c51}}{{#c52}}52{{/c52}}{{#c53}}53{{/c53}}{{#c54}}54{{/c54}}{{#c55}}55{{/c55}}{{#c56}}56{{/c56}}{{#c57}}57{{/c57}}{{#c58}}58{{/c58}}{{#c59}}59{{/c59}}{{#c60}}60{{/c60}}{{#c61}}61{{/c61}}{{#c62}}62{{/c62}}{{#c63}}63{{/c63}}{{#c64}}64{{/c64}}{{#c65}}65{{/c65}}{{#c66}}66{{/c66}}{{#c67}}67{{/c67}}{{#c68}}68{{/c68}}{{#c69}}69{{/c69}}{{#c70}}70{{/c70}}{{#c71}}71{{/c71}}{{#c72}}72{{/c72}}{{#c73}}73{{/c73}}{{#c74}}74{{/c74}}{{#c75}}75{{/c75}}{{#c76}}76{{/c76}}{{#c77}}77{{/c77}}{{#c78}}78{{/c78}}{{#c79}}79{{/c79}}{{#c80}}80{{/c80}}{{#c81}}81{{/c81}}{{#c82}}82{{/c82}}{{#c83}}83{{/c83}}{{#c84}}84{{/c84}}{{#c85}}85{{/c85}}{{#c86}}86{{/c86}}{{#c87}}87{{/c87}}{{#c88}}88{{/c88}}{{#c89}}89{{/c89}}{{#c90}}90{{/c90}}{{#c91}}91{{/c91}}{{#c92}}92{{/c92}}{{#c93}}93{{/c93}}{{#c94}}94{{/c94}}{{#c95}}95{{/c95}}{{#c96}}96{{/c96}}{{#c97}}97{{/c97}}{{#c98}}98{{/c98}}{{#c99}}99{{/c99}}{{#c100}}100{{/c100}}{{#c101}}101{{/c101}}{{#c102}}102{{/c102}}{{#c103}}103{{/c103}}{{#c104}}104{{/c104}}{{#c105}}105{{/c105}}{{#c106}}106{{/c106}}{{#c107}}107{{/c107}}{{#c108}}108{{/c108}}{{#c109}}109{{/c109}}{{#c110}}110{{/c110}}{{#c111}}111{{/c111}}{{#c112}}112{{/c112}}{{#c113}}113{{/c113}}{{#c114}}114{{/c114}}{{#c115}}115{{/c115}}{{#c116}}116{{/c116}}{{#c117}}117{{/c117}}{{#c118}}118{{/c118}}{{#c119}}119{{/c119}}{{#c120}}120{{/c120}}{{#c121}}121{{/c121}}{{#c122}}122{{/c122}}{{#c123}}123{{/c123}}{{#c124}}124{{/c124}}{{#c125}}125{{/c125}}{{#c126}}126{{/c126}}{{#c127}}127{{/c127}}{{#c128}}128{{/c128}}{{#c129}}129{{/c129}}{{#c130}}130{{/c130}}{{#c131}}131{{/c131}}{{#c132}}132{{/c132}}{{#c133}}133{{/c133}}{{#c134}}134{{/c134}}{{#c135}}135{{/c135}}{{#c136}}136{{/c136}}{{#c137}}137{{/c137}}{{#c138}}138{{/c138}}{{#c139}}139{{/c139}}{{#c140}}140{{/c140}}{{#c141}}141{{/c141}}{{#c142}}142{{/c142}}{{#c143}}143{{/c143}}{{#c144}}144{{/c144}}{{#c145}}145{{/c145}}{{#c146}}146{{/c146}}{{#c147}}147{{/c147}}{{#c148}}148{{/c148}}{{#c149}}149{{/c149}}{{#c150}}150{{/c150}}{{#c151}}151{{/c151}}{{#c152}}152{{/c152}}{{#c153}}153{{/c153}}{{#c154}}154{{/c154}}{{#c155}}155{{/c155}}{{#c156}}156{{/c156}}{{#c157}}157{{/c157}}{{#c158}}158{{/c158}}{{#c159}}159{{/c159}}{{#c160}}160{{/c160}}{{#c161}}161{{/c161}}{{#c162}}162{{/c162}}{{#c163}}163{{/c163}}{{#c164}}164{{/c164}}{{#c165}}165{{/c165}}{{#c166}}166{{/c166}}{{#c167}}167{{/c167}}{{#c168}}168{{/c168}}{{#c169}}169{{/c169}}{{#c170}}170{{/c170}}{{#c171}}171{{/c171}}{{#c172}}172{{/c172}}{{#c173}}173{{/c173}}{{#c174}}174{{/c174}}{{#c175}}175{{/c175}}{{#c176}}176{{/c176}}{{#c177}}177{{/c177}}{{#c178}}178{{/c178}}{{#c179}}179{{/c179}}{{#c180}}180{{/c180}}{{#c181}}181{{/c181}}{{#c182}}182{{/c182}}{{#c183}}183{{/c183}}{{#c184}}184{{/c184}}{{#c185}}185{{/c185}}{{#c186}}186{{/c186}}{{#c187}}187{{/c187}}{{#c188}}188{{/c188}}{{#c189}}189{{/c189}}{{#c190}}190{{/c190}}{{#c191}}191{{/c191}}{{#c192}}192{{/c192}}{{#c193}}193{{/c193}}{{#c194}}194{{/c194}}{{#c195}}195{{/c195}}{{#c196}}196{{/c196}}{{#c197}}197{{/c197}}{{#c198}}198{{/c198}}{{#c199}}199{{/c199}}{{#c200}}200{{/c200}}{{#c201}}201{{/c201}}{{#c202}}202{{/c202}}{{#c203}}203{{/c203}}{{#c204}}204{{/c204}}{{#c205}}205{{/c205}}{{#c206}}206{{/c206}}{{#c207}}207{{/c207}}{{#c208}}208{{/c208}}{{#c209}}209{{/c209}}{{#c210}}210{{/c210}}{{#c211}}211{{/c211}}{{#c212}}212{{/c212}}{{#c213}}213{{/c213}}{{#c214}}214{{/c214}}{{#c215}}215{{/c215}}{{#c216}}216{{/c216}}{{#c217}}217{{/c217}}{{#c218}}218{{/c218}}{{#c219}}219{{/c219}}{{#c220}}220{{/c220}}{{#c221}}221{{/c221}}{{#c222}}222{{/c222}}{{#c223}}223{{/c223}}{{#c224}}224{{/c224}}{{#c225}}225{{/c225}}{{#c226}}226{{/c226}}{{#c227}}227{{/c227}}{{#c228}}228{{/c228}}{{#c229}}229{{/c229}}{{#c230}}230{{/c230}}{{#c231}}231{{/c231}}{{#c232}}232{{/c232}}{{#c233}}233{{/c233}}{{#c234}}234{{/c234}}{{#c235}}235{{/c235}}{{#c236}}236{{/c236}}{{#c237}}237{{/c237}}{{#c238}}238{{/c238}}{{#c239}}239{{/c239}}{{#c240}}240{{/c240}}{{#c241}}241{{/c241}}{{#c242}}242{{/c242}}{{#c243}}243{{/c243}}{{#c244}}244{{/c244}}{{#c245}}245{{/c245}}{{#c246}}246{{/c246}}{{#c247}}247{{/c247}}{{#c248}}248{{/c248}}{{#c249}}249{{/c249}}{{#c250}}250{{/c250}}
    {{#c251}}251{{/c251}}{{#c252}}252{{/c252}}{{#c253}}253{{/c253}}{{#c254}}254{{/c254}}{{#c255}}255{{/c255}}{{#c256}}256{{/c256}}{{#c257}}257{{/c257}}{{#c258}}258{{/c258}}{{#c259}}259{{/c259}}{{#c260}}260{{/c260}}{{#c261}}261{{/c261}}{{#c262}}262{{/c262}}{{#c263}}263{{/c263}}{{#c264}}264{{/c264}}{{#c265}}265{{/c265}}{{#c266}}266{{/c266}}{{#c267}}267{{/c267}}{{#c268}}268{{/c268}}{{#c269}}269{{/c269}}{{#c270}}270{{/c270}}{{#c271}}271{{/c271}}{{#c272}}272{{/c272}}{{#c273}}273{{/c273}}{{#c274}}274{{/c274}}{{#c275}}275{{/c275}}{{#c276}}276{{/c276}}{{#c277}}277{{/c277}}{{#c278}}278{{/c278}}{{#c279}}279{{/c279}}{{#c280}}280{{/c280}}{{#c281}}281{{/c281}}{{#c282}}282{{/c282}}{{#c283}}283{{/c283}}{{#c284}}284{{/c284}}{{#c285}}285{{/c285}}{{#c286}}286{{/c286}}{{#c287}}287{{/c287}}{{#c288}}288{{/c288}}{{#c289}}289{{/c289}}{{#c290}}290{{/c290}}{{#c291}}291{{/c291}}{{#c292}}292{{/c292}}{{#c293}}293{{/c293}}{{#c294}}294{{/c294}}{{#c295}}295{{/c295}}{{#c296}}296{{/c296}}{{#c297}}297{{/c297}}{{#c298}}298{{/c298}}{{#c299}}299{{/c299}}{{#c300}}300{{/c300}}{{#c301}}301{{/c301}}{{#c302}}302{{/c302}}{{#c303}}303{{/c303}}{{#c304}}304{{/c304}}{{#c305}}305{{/c305}}{{#c306}}306{{/c306}}{{#c307}}307{{/c307}}{{#c308}}308{{/c308}}{{#c309}}309{{/c309}}{{#c310}}310{{/c310}}{{#c311}}311{{/c311}}{{#c312}}312{{/c312}}{{#c313}}313{{/c313}}{{#c314}}314{{/c314}}{{#c315}}315{{/c315}}{{#c316}}316{{/c316}}{{#c317}}317{{/c317}}{{#c318}}318{{/c318}}{{#c319}}319{{/c319}}{{#c320}}320{{/c320}}{{#c321}}321{{/c321}}{{#c322}}322{{/c322}}{{#c323}}323{{/c323}}{{#c324}}324{{/c324}}{{#c325}}325{{/c325}}{{#c326}}326{{/c326}}{{#c327}}327{{/c327}}{{#c328}}328{{/c328}}{{#c329}}329{{/c329}}{{#c330}}330{{/c330}}{{#c331}}331{{/c331}}{{#c332}}332{{/c332}}{{#c333}}333{{/c333}}{{#c334}}334{{/c334}}{{#c335}}335{{/c335}}{{#c336}}336{{/c336}}{{#c337}}337{{/c337}}{{#c338}}338{{/c338}}{{#c339}}339{{/c339}}{{#c340}}340{{/c340}}{{#c341}}341{{/c341}}{{#c342}}342{{/c342}}{{#c343}}343{{/c343}}{{#c344}}344{{/c344}}{{#c345}}345{{/c345}}{{#c346}}346{{/c346}}{{#c347}}347{{/c347}}{{#c348}}348{{/c348}}{{#c349}}349{{/c349}}{{#c350}}350{{/c350}}{{#c351}}351{{/c351}}{{#c352}}352{{/c352}}{{#c353}}353{{/c353}}{{#c354}}354{{/c354}}{{#c355}}355{{/c355}}{{#c356}}356{{/c356}}{{#c357}}357{{/c357}}{{#c358}}358{{/c358}}{{#c359}}359{{/c359}}{{#c360}}360{{/c360}}{{#c361}}361{{/c361}}{{#c362}}362{{/c362}}{{#c363}}363{{/c363}}{{#c364}}364{{/c364}}{{#c365}}365{{/c365}}{{#c366}}366{{/c366}}{{#c367}}367{{/c367}}{{#c368}}368{{/c368}}{{#c369}}369{{/c369}}{{#c370}}370{{/c370}}{{#c371}}371{{/c371}}{{#c372}}372{{/c372}}{{#c373}}373{{/c373}}{{#c374}}374{{/c374}}{{#c375}}375{{/c375}}{{#c376}}376{{/c376}}{{#c377}}377{{/c377}}{{#c378}}378{{/c378}}{{#c379}}379{{/c379}}{{#c380}}380{{/c380}}{{#c381}}381{{/c381}}{{#c382}}382{{/c382}}{{#c383}}383{{/c383}}{{#c384}}384{{/c384}}{{#c385}}385{{/c385}}{{#c386}}386{{/c386}}{{#c387}}387{{/c387}}{{#c388}}388{{/c388}}{{#c389}}389{{/c389}}{{#c390}}390{{/c390}}{{#c391}}391{{/c391}}{{#c392}}392{{/c392}}{{#c393}}393{{/c393}}{{#c394}}394{{/c394}}{{#c395}}395{{/c395}}{{#c396}}396{{/c396}}{{#c397}}397{{/c397}}{{#c398}}398{{/c398}}{{#c399}}399{{/c399}}{{#c400}}400{{/c400}}{{#c401}}401{{/c401}}{{#c402}}402{{/c402}}{{#c403}}403{{/c403}}{{#c404}}404{{/c404}}{{#c405}}405{{/c405}}{{#c406}}406{{/c406}}{{#c407}}407{{/c407}}{{#c408}}408{{/c408}}{{#c409}}409{{/c409}}{{#c410}}410{{/c410}}{{#c411}}411{{/c411}}{{#c412}}412{{/c412}}{{#c413}}413{{/c413}}{{#c414}}414{{/c414}}{{#c415}}415{{/c415}}{{#c416}}416{{/c416}}{{#c417}}417{{/c417}}{{#c418}}418{{/c418}}{{#c419}}419{{/c419}}{{#c420}}420{{/c420}}{{#c421}}421{{/c421}}{{#c422}}422{{/c422}}{{#c423}}423{{/c423}}{{#c424}}424{{/c424}}{{#c425}}425{{/c425}}{{#c426}}426{{/c426}}{{#c427}}427{{/c427}}{{#c428}}428{{/c428}}{{#c429}}429{{/c429}}{{#c430}}430{{/c430}}{{#c431}}431{{/c431}}{{#c432}}432{{/c432}}{{#c433}}433{{/c433}}{{#c434}}434{{/c434}}{{#c435}}435{{/c435}}{{#c436}}436{{/c436}}{{#c437}}437{{/c437}}{{#c438}}438{{/c438}}{{#c439}}439{{/c439}}{{#c440}}440{{/c440}}{{#c441}}441{{/c441}}{{#c442}}442{{/c442}}{{#c443}}443{{/c443}}{{#c444}}444{{/c444}}{{#c445}}445{{/c445}}{{#c446}}446{{/c446}}{{#c447}}447{{/c447}}{{#c448}}448{{/c448}}{{#c449}}449{{/c449}}{{#c450}}450{{/c450}}{{#c451}}451{{/c451}}{{#c452}}452{{/c452}}{{#c453}}453{{/c453}}{{#c454}}454{{/c454}}{{#c455}}455{{/c455}}{{#c456}}456{{/c456}}{{#c457}}457{{/c457}}{{#c458}}458{{/c458}}{{#c459}}459{{/c459}}{{#c460}}460{{/c460}}{{#c461}}461{{/c461}}{{#c462}}462{{/c462}}{{#c463}}463{{/c463}}{{#c464}}464{{/c464}}{{#c465}}465{{/c465}}{{#c466}}466{{/c466}}{{#c467}}467{{/c467}}{{#c468}}468{{/c468}}{{#c469}}469{{/c469}}{{#c470}}470{{/c470}}{{#c471}}471{{/c471}}{{#c472}}472{{/c472}}{{#c473}}473{{/c473}}{{#c474}}474{{/c474}}{{#c475}}475{{/c475}}{{#c476}}476{{/c476}}{{#c477}}477{{/c477}}{{#c478}}478{{/c478}}{{#c479}}479{{/c479}}{{#c480}}480{{/c480}}{{#c481}}481{{/c481}}{{#c482}}482{{/c482}}{{#c483}}483{{/c483}}{{#c484}}484{{/c484}}{{#c485}}485{{/c485}}{{#c486}}486{{/c486}}{{#c487}}487{{/c487}}{{#c488}}488{{/c488}}{{#c489}}489{{/c489}}{{#c490}}490{{/c490}}{{#c491}}491{{/c491}}{{#c492}}492{{/c492}}{{#c493}}493{{/c493}}{{#c494}}494{{/c494}}{{#c495}}495{{/c495}}{{#c496}}496{{/c496}}{{#c497}}497{{/c497}}{{#c498}}498{{/c498}}{{#c499}}499{{/c499}}{{#c500}}500{{/c500}}`
            ord = ord.trim()

            var content = document.getElementById("enhanced-cloze-content").innerHTML

            // the extra (?:) at the beginning is there so that Anki doesn't think this is a field
            var clozeRe = /{(?:){c(\d+)::([\W\w]*?)(?:::([\W\w]*?))?}}/g

            // fill enhancedClozesData
            var match = clozeRe.exec(content);
            while (match != null) {
                enhancedClozesData["clozeId"].push(match[1])
                enhancedClozesData["answers"].push(match[2])
                enhancedClozesData["hints"].push(match[3] !== undefined ? match[3] : "")
                match = clozeRe.exec(content);
            }

            // create html with enhanced-clozes and insert it into the enhanced-clozes element
            var html = ""
            var ctr = 0
            var prevLastIndex = 0
            match = clozeRe.exec(content);
            while (match !== null) {
                var startIdx = clozeRe.lastIndex - match[0].length
                html += content.slice(prevLastIndex, startIdx)

                var clozeType = ord == enhancedClozesData["clozeId"][ctr] ? "genuine-cloze" : "pseudo-cloze"
                html +=
                    `<span class="${clozeType}" show-state="hint" cid="${enhancedClozesData["clozeId"][ctr]}" index="${ctr}">${enhancedClozesData["hints"][ctr]}</span>`

                prevLastIndex = clozeRe.lastIndex
                match = clozeRe.exec(content);
                ctr += 1
            }
            html += content.slice(prevLastIndex)

            var enhDiv = document.getElementById("enhanced-clozes")
            enhDiv.innerHTML = html
        }

        function initializeEnhancedClozes() {

            // genuine clozes refer to those belong to current card and need to be answered, e.g. { {c2::abc} } on card2
            // pseudo clozes refer to the opposite, e.g. { {c1::abc} } and { {c3::abc} } on card2
            $('.genuine-cloze, .pseudo-cloze').each(function (index, elem) {
                toggleCloze(elem, 'hint')
            });

            // SCROLL TO FIRST CLOZE
            if ($('.genuine-cloze').length != 0) {
                maybeScrollToCloze($('.genuine-cloze').first().get(0));
            }

            $('.pseudo-cloze').css('cursor', 'pointer')
            $('.genuine-cloze').css('cursor', 'pointer')
            $('#show-one-cloze-left').css('cursor', 'pointer')
            $('#show-one-cloze-right').css('cursor', 'pointer')

            // this prevents the blue selection briefly showing up on mobile when tapping on a cloze
            $('.pseudo-cloze').addClass('disable-select')
            $('.genuine-cloze').addClass('disable-select')
            $('#show-one-cloze-left').addClass('disable-select')
            $('#show-one-cloze-right').addClass('disable-select')

            if (typeof firstTimeLoadingEnhancedCloze === 'undefined') {
                firstTimeLoadingEnhancedCloze = false

                if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator
                    .userAgent)) {
                    $(document).on('touchstart', '.pseudo-cloze', function (event) {
                        toggleCloze(event.target, 'toggle');
                    });

                    $(document).on('touchstart', '.genuine-cloze', function (event) {
                        toggleCloze(event.target, 'toggle');
                    });

                    $(document).on('touchstart', '#show-one-cloze-left', function (event) {
                        revealOneClozeOfAType("genuine");
                    });

                    $(document).on('touchstart', '#show-one-cloze-right', function (event) {
                        revealOneClozeOfAType("pseudo");
                    });

                } else {
                    $(document).on('click touchstart', '.pseudo-cloze', function (event) {
                        toggleCloze(event.target, 'toggle');
                    });

                    $(document).on('click', '.genuine-cloze', function (event) {
                        toggleCloze(event.target, 'toggle');
                    });

                    $(document).on('click', '#show-one-cloze-left', function (event) {
                        revealOneClozeOfAType("genuine");
                    });

                    $(document).on('click', '#show-one-cloze-right', function (event) {
                        revealOneClozeOfAType("pseudo");
                    });
                }
            }

            window.enhancedClozeAddEventListener("keydown", (evt) => {
                if (shortcutMatcher(revealNextGenuineClozeShortcut)(event)) {
                    revealOneClozeOfAType("genuine");
                }
                if (shortcutMatcher(revealAllGenuineClozesShortcut)(event)) {
                    toggleAllClozesOfAType("genuine")
                }
                if (shortcutMatcher(revealNextPseudoClozeShortcut)(event)) {
                    revealOneClozeOfAType("pseudo");
                }
                if (shortcutMatcher(revealAllPseudoClozesShortcut)(event)) {
                    toggleAllClozesOfAType("pseudo");
                }
            })

        }

        function setupEditFieldDuringReview() {
            moveEditClozesElm()

            $("#enhanced-clozes").off('click').on('click', function (event) {
                if (document.getElementsByClassName("EFDRC-outline").length == 0) return
                if (!ctrlDown) return
                activateEditFieldDuringReview()
            });

            function moveEditClozesElm() {
                var editClozesElm = document.getElementById("edit-clozes")
                document.getElementById("main-section").appendChild(editClozesElm)
            }

            function activateEditFieldDuringReview() {
                var enhancedClozesElm = document.getElementById("enhanced-clozes")
                var editClozesElm = document.getElementById("edit-clozes")
                if (["inline", ""].includes(enhancedClozesElm.style.display)) {
                    enhancedClozesElm.style.display = "none";
                    editClozesElm.style.display = "inline";
                } else {
                    enhancedClozesElm.style.display = "inline";
                    editClozesElm.style.display = "none";
                }
                setTimeout(() => {
                    editable = editClozesElm.getElementsByClassName(
                        "EFDRC-outline")[0]
                    editable.onfocus()
                    editable.focus()
                })
            }

        }

        function insertStyling() {
            if (document.getElementById("enhanced-clozes-style")) return;

            mainSection = document.getElementById("main-section")
            style = document.createElement("style")

            // this css is also in the css file, but inserting the css here is easier than updating the css file for all users
            style.id = "enhanced-clozes-style"
            style.innerHTML = `
                .disable-select {
                    -webkit-touch-callout: none;
                    user-select: none;
                }
            `

            if (underlineRevealedPseudoClozes) {
                style.innerHTML += `
                .pseudo-cloze {
                    border-bottom: 1px solid #4285f4;
                    padding-bottom: 1px;
                }`
            }
            if (underlineRevealedGenuineClozes) {
                style.innerHTML += `
                .genuine-cloze {
                    border-bottom: 1px solid #ff5c82;
                    padding-bottom: 1px;
                }`
            }
            mainSection.insertBefore(style, mainSection.children[0])
        }

        function revealOneClozeOfAType(clozeType) {
            if (!["genuine", "pseudo"].includes(clozeType)) {
                console.log(`clozeType has unexpected value: ${clozeType}`)
            }

            if (!$(`.${clozeType}-cloze[show-state="hint"]`).length) {
                $('#no-more-cloze').animate({
                    display: "toggle",
                }, 500);
                return
            }

            var hiddenClozes = $(`.${clozeType}-cloze[show-state="hint"]`)
            if (hiddenClozes.length != 0) {
                revealCloze(hiddenClozes[0]);
            }
        }

        function toggleAllClozesOfAType(clozeType) {
            if (!["genuine", "pseudo"].includes(clozeType)) {
                console.log(`clozeType has unexpected value: ${clozeType}`)
            }

            var allRevealed = !$(`.${clozeType}-cloze[show-state="hint"`).length
            $(`.${clozeType}-cloze`).each(function (index, elem) {
                toggleCloze(elem, allRevealed ? "hint" : "answer");
            })
        }

        function revealCloze(elem) {
            if (!isVisible(elem)) {
                maybeScrollToCloze(elem);
            } else {
                toggleCloze(elem, 'answer');
                if (!isVisible(elem)) {
                    maybeScrollToCloze(elem);
                } else { }
                $(elem).hide(0);
                $(elem).fadeIn(500);
            }
        }

        function isVisible(elm) {
            var rect = elm.getBoundingClientRect();
            var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
            return !(rect.bottom < 0 || rect.top - viewHeight >= 0);
        }

        function maybeScrollToCloze(elem) {
            if (!scrollToClozeOnToggle) return
            $('html, body').animate({
                scrollTop: $(elem).offset().top - 60
            }, animateScroll ? 500 : 0);
        }

        function defineEnhancedClozeAddEventListener() {
            // define enhancedClozeAddEventListener
            // this function is almost identical to `document.addEventListener`
            // but removes the event listener attached on previous card / front side
            // using this function
            if (typeof window.enhancedClozeEventListener != "undefined") {
                for (const listener of window.enhancedClozeEventListener) {
                    const type = listener[0]
                    const handler = listener[1]
                    document.removeEventListener(type, handler)
                }
            }
            window.enhancedClozeEventListener = []

            window.enhancedClozeAddEventListener = function (type, handler) {
                document.addEventListener(type, handler)
                window.enhancedClozeEventListener.push([type, handler])
            }
        }

        var specialCharCodes = {
            "-": "minus",
            "=": "equal",
            "[": "bracketleft",
            "]": "bracketright",
            ";": "semicolon",
            "'": "quote",
            "`": "backquote",
            "\\": "backslash",
            ",": "comma",
            ".": "period",
            "/": "slash",
        };

        // Returns function that match keyboard event to see if it matches given shortcut.
        function shortcutMatcher(shortcut) {
            var shortcutKeys = shortcut.toLowerCase().split(/[+]/).map(key => key.trim())
            var mainKey = shortcutKeys[shortcutKeys.length - 1]
            if (mainKey.length === 1) {
                if (/\d/.test(mainKey)) {
                    mainKey = "digit" + mainKey
                } else if (/[a-zA-Z]/.test(mainKey)) {
                    mainKey = "key" + mainKey
                } else {
                    var code = specialCharCodes[mainKey];
                    if (code) {
                        mainKey = code
                    }
                }
            }
            var ctrl = shortcutKeys.includes("ctrl")
            var shift = shortcutKeys.includes("shift")
            var alt = shortcutKeys.includes("alt")

            var matchShortcut = function (ctrl, shift, alt, mainKey, event) {
                if (event.originalEvent !== undefined) {
                    event = event.originalEvent
                }
                if (mainKey !== event.code.toLowerCase()) return false
                if (ctrl !== (event.ctrlKey || event.metaKey)) return false
                if (shift !== event.shiftKey) return false
                if (alt !== event.altKey) return false
                return true
            }.bind(window, ctrl, shift, alt, mainKey)

            return matchShortcut
        }

        ctrlDown = false;
        window.enhancedClozeAddEventListener("keydown", function (ev) {
            if (isCtrlKey(ev.code)) ctrlDown = true;
        })
        window.enhancedClozeAddEventListener("keyup", function (ev) {
            if (isCtrlKey(ev.code)) ctrlDown = false;
        })

        const isCtrlKey = function (keycode) {
            return ['ControlLeft', 'MetaLeft'].includes(keycode)
        }

    });

    function showNextElement(elem) {
        $(elem).next().show(0);
    };

    function toggleCloze(elem, displayOption) {

        if (elem == null) return

        // if the element is not a cloze get its ancestor cloze
        if (elem.classList.contains("genuine-cloze") || elem.classList.contains("pseudo-cloze"))
            cloze = elem
        else {
            cloze = $(elem).closest(".genuine-cloze")
            if (cloze == null)
                cloze = $(elem).closest(".pseudo-cloze")
        }

        var index = $(cloze).attr('index');
        var answer = enhancedClozesData["answers"][index]
        var hint = enhancedClozesData["hints"][index]

        if (!showHintsForPseudoClozes && cloze.classList.contains('pseudo-cloze')) {
            hint = ""
        }

        if (revealPseudoClozesByDefault || answer.startsWith('#')) {
            if (answer.startsWith('#')) {
                answer = answer.slice(1)
            }

            if ($(cloze).attr('class') == 'pseudo-cloze') {
                $(cloze).attr('show-state', 'answer');
                $(cloze).html(answer);
                return
            }
        }

        if (displayOption == 'answer' || (displayOption == 'toggle' && $(cloze).attr('show-state') == 'hint')) {
            $(cloze).attr('show-state', 'answer');
            $(cloze).html(answer);
        } else if (displayOption == 'hint' || (displayOption == 'toggle' && $(cloze).attr('show-state') == 'answer')) {
            $(cloze).attr('show-state', 'hint');
            hint = '&nbsp;&nbsp;[&nbsp;&nbsp;' + hint + '&nbsp;&nbsp;]&nbsp;&nbsp;';
            $(cloze).html(hint);
        }

        // rerun mathjax on the document so that the cloze text gets formatted
        // ... for MathJax 2
        try {
            MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
        } catch { }
        // ... for MathJax 3
        try {
            MathJax.typesetPromise()
        } catch { }

    }
    already=true;
}

if (already) {
    var enhancedClozesData = {
        "clozeId": [],
        "answers": [],
        "hints": [],
    }

    $(function () {
        defineEnhancedClozeAddEventListener()
        prepareEnhancedClozes()
        initializeEnhancedClozes()
        setupEditFieldDuringReview()
        insertStyling()

        function prepareEnhancedClozes(genuineClozeOrd) {
            var ord =
                `{{#c1}}1{{/c1}}{{#c2}}2{{/c2}}{{#c3}}3{{/c3}}{{#c4}}4{{/c4}}{{#c5}}5{{/c5}}{{#c6}}6{{/c6}}{{#c7}}7{{/c7}}{{#c8}}8{{/c8}}{{#c9}}9{{/c9}}{{#c10}}10{{/c10}}{{#c11}}11{{/c11}}{{#c12}}12{{/c12}}{{#c13}}13{{/c13}}{{#c14}}14{{/c14}}{{#c15}}15{{/c15}}{{#c16}}16{{/c16}}{{#c17}}17{{/c17}}{{#c18}}18{{/c18}}{{#c19}}19{{/c19}}{{#c20}}20{{/c20}}{{#c21}}21{{/c21}}{{#c22}}22{{/c22}}{{#c23}}23{{/c23}}{{#c24}}24{{/c24}}{{#c25}}25{{/c25}}{{#c26}}26{{/c26}}{{#c27}}27{{/c27}}{{#c28}}28{{/c28}}{{#c29}}29{{/c29}}{{#c30}}30{{/c30}}{{#c31}}31{{/c31}}{{#c32}}32{{/c32}}{{#c33}}33{{/c33}}{{#c34}}34{{/c34}}{{#c35}}35{{/c35}}{{#c36}}36{{/c36}}{{#c37}}37{{/c37}}{{#c38}}38{{/c38}}{{#c39}}39{{/c39}}{{#c40}}40{{/c40}}{{#c41}}41{{/c41}}{{#c42}}42{{/c42}}{{#c43}}43{{/c43}}{{#c44}}44{{/c44}}{{#c45}}45{{/c45}}{{#c46}}46{{/c46}}{{#c47}}47{{/c47}}{{#c48}}48{{/c48}}{{#c49}}49{{/c49}}{{#c50}}50{{/c50}}{{#c51}}51{{/c51}}{{#c52}}52{{/c52}}{{#c53}}53{{/c53}}{{#c54}}54{{/c54}}{{#c55}}55{{/c55}}{{#c56}}56{{/c56}}{{#c57}}57{{/c57}}{{#c58}}58{{/c58}}{{#c59}}59{{/c59}}{{#c60}}60{{/c60}}{{#c61}}61{{/c61}}{{#c62}}62{{/c62}}{{#c63}}63{{/c63}}{{#c64}}64{{/c64}}{{#c65}}65{{/c65}}{{#c66}}66{{/c66}}{{#c67}}67{{/c67}}{{#c68}}68{{/c68}}{{#c69}}69{{/c69}}{{#c70}}70{{/c70}}{{#c71}}71{{/c71}}{{#c72}}72{{/c72}}{{#c73}}73{{/c73}}{{#c74}}74{{/c74}}{{#c75}}75{{/c75}}{{#c76}}76{{/c76}}{{#c77}}77{{/c77}}{{#c78}}78{{/c78}}{{#c79}}79{{/c79}}{{#c80}}80{{/c80}}{{#c81}}81{{/c81}}{{#c82}}82{{/c82}}{{#c83}}83{{/c83}}{{#c84}}84{{/c84}}{{#c85}}85{{/c85}}{{#c86}}86{{/c86}}{{#c87}}87{{/c87}}{{#c88}}88{{/c88}}{{#c89}}89{{/c89}}{{#c90}}90{{/c90}}{{#c91}}91{{/c91}}{{#c92}}92{{/c92}}{{#c93}}93{{/c93}}{{#c94}}94{{/c94}}{{#c95}}95{{/c95}}{{#c96}}96{{/c96}}{{#c97}}97{{/c97}}{{#c98}}98{{/c98}}{{#c99}}99{{/c99}}{{#c100}}100{{/c100}}{{#c101}}101{{/c101}}{{#c102}}102{{/c102}}{{#c103}}103{{/c103}}{{#c104}}104{{/c104}}{{#c105}}105{{/c105}}{{#c106}}106{{/c106}}{{#c107}}107{{/c107}}{{#c108}}108{{/c108}}{{#c109}}109{{/c109}}{{#c110}}110{{/c110}}{{#c111}}111{{/c111}}{{#c112}}112{{/c112}}{{#c113}}113{{/c113}}{{#c114}}114{{/c114}}{{#c115}}115{{/c115}}{{#c116}}116{{/c116}}{{#c117}}117{{/c117}}{{#c118}}118{{/c118}}{{#c119}}119{{/c119}}{{#c120}}120{{/c120}}{{#c121}}121{{/c121}}{{#c122}}122{{/c122}}{{#c123}}123{{/c123}}{{#c124}}124{{/c124}}{{#c125}}125{{/c125}}{{#c126}}126{{/c126}}{{#c127}}127{{/c127}}{{#c128}}128{{/c128}}{{#c129}}129{{/c129}}{{#c130}}130{{/c130}}{{#c131}}131{{/c131}}{{#c132}}132{{/c132}}{{#c133}}133{{/c133}}{{#c134}}134{{/c134}}{{#c135}}135{{/c135}}{{#c136}}136{{/c136}}{{#c137}}137{{/c137}}{{#c138}}138{{/c138}}{{#c139}}139{{/c139}}{{#c140}}140{{/c140}}{{#c141}}141{{/c141}}{{#c142}}142{{/c142}}{{#c143}}143{{/c143}}{{#c144}}144{{/c144}}{{#c145}}145{{/c145}}{{#c146}}146{{/c146}}{{#c147}}147{{/c147}}{{#c148}}148{{/c148}}{{#c149}}149{{/c149}}{{#c150}}150{{/c150}}{{#c151}}151{{/c151}}{{#c152}}152{{/c152}}{{#c153}}153{{/c153}}{{#c154}}154{{/c154}}{{#c155}}155{{/c155}}{{#c156}}156{{/c156}}{{#c157}}157{{/c157}}{{#c158}}158{{/c158}}{{#c159}}159{{/c159}}{{#c160}}160{{/c160}}{{#c161}}161{{/c161}}{{#c162}}162{{/c162}}{{#c163}}163{{/c163}}{{#c164}}164{{/c164}}{{#c165}}165{{/c165}}{{#c166}}166{{/c166}}{{#c167}}167{{/c167}}{{#c168}}168{{/c168}}{{#c169}}169{{/c169}}{{#c170}}170{{/c170}}{{#c171}}171{{/c171}}{{#c172}}172{{/c172}}{{#c173}}173{{/c173}}{{#c174}}174{{/c174}}{{#c175}}175{{/c175}}{{#c176}}176{{/c176}}{{#c177}}177{{/c177}}{{#c178}}178{{/c178}}{{#c179}}179{{/c179}}{{#c180}}180{{/c180}}{{#c181}}181{{/c181}}{{#c182}}182{{/c182}}{{#c183}}183{{/c183}}{{#c184}}184{{/c184}}{{#c185}}185{{/c185}}{{#c186}}186{{/c186}}{{#c187}}187{{/c187}}{{#c188}}188{{/c188}}{{#c189}}189{{/c189}}{{#c190}}190{{/c190}}{{#c191}}191{{/c191}}{{#c192}}192{{/c192}}{{#c193}}193{{/c193}}{{#c194}}194{{/c194}}{{#c195}}195{{/c195}}{{#c196}}196{{/c196}}{{#c197}}197{{/c197}}{{#c198}}198{{/c198}}{{#c199}}199{{/c199}}{{#c200}}200{{/c200}}{{#c201}}201{{/c201}}{{#c202}}202{{/c202}}{{#c203}}203{{/c203}}{{#c204}}204{{/c204}}{{#c205}}205{{/c205}}{{#c206}}206{{/c206}}{{#c207}}207{{/c207}}{{#c208}}208{{/c208}}{{#c209}}209{{/c209}}{{#c210}}210{{/c210}}{{#c211}}211{{/c211}}{{#c212}}212{{/c212}}{{#c213}}213{{/c213}}{{#c214}}214{{/c214}}{{#c215}}215{{/c215}}{{#c216}}216{{/c216}}{{#c217}}217{{/c217}}{{#c218}}218{{/c218}}{{#c219}}219{{/c219}}{{#c220}}220{{/c220}}{{#c221}}221{{/c221}}{{#c222}}222{{/c222}}{{#c223}}223{{/c223}}{{#c224}}224{{/c224}}{{#c225}}225{{/c225}}{{#c226}}226{{/c226}}{{#c227}}227{{/c227}}{{#c228}}228{{/c228}}{{#c229}}229{{/c229}}{{#c230}}230{{/c230}}{{#c231}}231{{/c231}}{{#c232}}232{{/c232}}{{#c233}}233{{/c233}}{{#c234}}234{{/c234}}{{#c235}}235{{/c235}}{{#c236}}236{{/c236}}{{#c237}}237{{/c237}}{{#c238}}238{{/c238}}{{#c239}}239{{/c239}}{{#c240}}240{{/c240}}{{#c241}}241{{/c241}}{{#c242}}242{{/c242}}{{#c243}}243{{/c243}}{{#c244}}244{{/c244}}{{#c245}}245{{/c245}}{{#c246}}246{{/c246}}{{#c247}}247{{/c247}}{{#c248}}248{{/c248}}{{#c249}}249{{/c249}}{{#c250}}250{{/c250}}
    {{#c251}}251{{/c251}}{{#c252}}252{{/c252}}{{#c253}}253{{/c253}}{{#c254}}254{{/c254}}{{#c255}}255{{/c255}}{{#c256}}256{{/c256}}{{#c257}}257{{/c257}}{{#c258}}258{{/c258}}{{#c259}}259{{/c259}}{{#c260}}260{{/c260}}{{#c261}}261{{/c261}}{{#c262}}262{{/c262}}{{#c263}}263{{/c263}}{{#c264}}264{{/c264}}{{#c265}}265{{/c265}}{{#c266}}266{{/c266}}{{#c267}}267{{/c267}}{{#c268}}268{{/c268}}{{#c269}}269{{/c269}}{{#c270}}270{{/c270}}{{#c271}}271{{/c271}}{{#c272}}272{{/c272}}{{#c273}}273{{/c273}}{{#c274}}274{{/c274}}{{#c275}}275{{/c275}}{{#c276}}276{{/c276}}{{#c277}}277{{/c277}}{{#c278}}278{{/c278}}{{#c279}}279{{/c279}}{{#c280}}280{{/c280}}{{#c281}}281{{/c281}}{{#c282}}282{{/c282}}{{#c283}}283{{/c283}}{{#c284}}284{{/c284}}{{#c285}}285{{/c285}}{{#c286}}286{{/c286}}{{#c287}}287{{/c287}}{{#c288}}288{{/c288}}{{#c289}}289{{/c289}}{{#c290}}290{{/c290}}{{#c291}}291{{/c291}}{{#c292}}292{{/c292}}{{#c293}}293{{/c293}}{{#c294}}294{{/c294}}{{#c295}}295{{/c295}}{{#c296}}296{{/c296}}{{#c297}}297{{/c297}}{{#c298}}298{{/c298}}{{#c299}}299{{/c299}}{{#c300}}300{{/c300}}{{#c301}}301{{/c301}}{{#c302}}302{{/c302}}{{#c303}}303{{/c303}}{{#c304}}304{{/c304}}{{#c305}}305{{/c305}}{{#c306}}306{{/c306}}{{#c307}}307{{/c307}}{{#c308}}308{{/c308}}{{#c309}}309{{/c309}}{{#c310}}310{{/c310}}{{#c311}}311{{/c311}}{{#c312}}312{{/c312}}{{#c313}}313{{/c313}}{{#c314}}314{{/c314}}{{#c315}}315{{/c315}}{{#c316}}316{{/c316}}{{#c317}}317{{/c317}}{{#c318}}318{{/c318}}{{#c319}}319{{/c319}}{{#c320}}320{{/c320}}{{#c321}}321{{/c321}}{{#c322}}322{{/c322}}{{#c323}}323{{/c323}}{{#c324}}324{{/c324}}{{#c325}}325{{/c325}}{{#c326}}326{{/c326}}{{#c327}}327{{/c327}}{{#c328}}328{{/c328}}{{#c329}}329{{/c329}}{{#c330}}330{{/c330}}{{#c331}}331{{/c331}}{{#c332}}332{{/c332}}{{#c333}}333{{/c333}}{{#c334}}334{{/c334}}{{#c335}}335{{/c335}}{{#c336}}336{{/c336}}{{#c337}}337{{/c337}}{{#c338}}338{{/c338}}{{#c339}}339{{/c339}}{{#c340}}340{{/c340}}{{#c341}}341{{/c341}}{{#c342}}342{{/c342}}{{#c343}}343{{/c343}}{{#c344}}344{{/c344}}{{#c345}}345{{/c345}}{{#c346}}346{{/c346}}{{#c347}}347{{/c347}}{{#c348}}348{{/c348}}{{#c349}}349{{/c349}}{{#c350}}350{{/c350}}{{#c351}}351{{/c351}}{{#c352}}352{{/c352}}{{#c353}}353{{/c353}}{{#c354}}354{{/c354}}{{#c355}}355{{/c355}}{{#c356}}356{{/c356}}{{#c357}}357{{/c357}}{{#c358}}358{{/c358}}{{#c359}}359{{/c359}}{{#c360}}360{{/c360}}{{#c361}}361{{/c361}}{{#c362}}362{{/c362}}{{#c363}}363{{/c363}}{{#c364}}364{{/c364}}{{#c365}}365{{/c365}}{{#c366}}366{{/c366}}{{#c367}}367{{/c367}}{{#c368}}368{{/c368}}{{#c369}}369{{/c369}}{{#c370}}370{{/c370}}{{#c371}}371{{/c371}}{{#c372}}372{{/c372}}{{#c373}}373{{/c373}}{{#c374}}374{{/c374}}{{#c375}}375{{/c375}}{{#c376}}376{{/c376}}{{#c377}}377{{/c377}}{{#c378}}378{{/c378}}{{#c379}}379{{/c379}}{{#c380}}380{{/c380}}{{#c381}}381{{/c381}}{{#c382}}382{{/c382}}{{#c383}}383{{/c383}}{{#c384}}384{{/c384}}{{#c385}}385{{/c385}}{{#c386}}386{{/c386}}{{#c387}}387{{/c387}}{{#c388}}388{{/c388}}{{#c389}}389{{/c389}}{{#c390}}390{{/c390}}{{#c391}}391{{/c391}}{{#c392}}392{{/c392}}{{#c393}}393{{/c393}}{{#c394}}394{{/c394}}{{#c395}}395{{/c395}}{{#c396}}396{{/c396}}{{#c397}}397{{/c397}}{{#c398}}398{{/c398}}{{#c399}}399{{/c399}}{{#c400}}400{{/c400}}{{#c401}}401{{/c401}}{{#c402}}402{{/c402}}{{#c403}}403{{/c403}}{{#c404}}404{{/c404}}{{#c405}}405{{/c405}}{{#c406}}406{{/c406}}{{#c407}}407{{/c407}}{{#c408}}408{{/c408}}{{#c409}}409{{/c409}}{{#c410}}410{{/c410}}{{#c411}}411{{/c411}}{{#c412}}412{{/c412}}{{#c413}}413{{/c413}}{{#c414}}414{{/c414}}{{#c415}}415{{/c415}}{{#c416}}416{{/c416}}{{#c417}}417{{/c417}}{{#c418}}418{{/c418}}{{#c419}}419{{/c419}}{{#c420}}420{{/c420}}{{#c421}}421{{/c421}}{{#c422}}422{{/c422}}{{#c423}}423{{/c423}}{{#c424}}424{{/c424}}{{#c425}}425{{/c425}}{{#c426}}426{{/c426}}{{#c427}}427{{/c427}}{{#c428}}428{{/c428}}{{#c429}}429{{/c429}}{{#c430}}430{{/c430}}{{#c431}}431{{/c431}}{{#c432}}432{{/c432}}{{#c433}}433{{/c433}}{{#c434}}434{{/c434}}{{#c435}}435{{/c435}}{{#c436}}436{{/c436}}{{#c437}}437{{/c437}}{{#c438}}438{{/c438}}{{#c439}}439{{/c439}}{{#c440}}440{{/c440}}{{#c441}}441{{/c441}}{{#c442}}442{{/c442}}{{#c443}}443{{/c443}}{{#c444}}444{{/c444}}{{#c445}}445{{/c445}}{{#c446}}446{{/c446}}{{#c447}}447{{/c447}}{{#c448}}448{{/c448}}{{#c449}}449{{/c449}}{{#c450}}450{{/c450}}{{#c451}}451{{/c451}}{{#c452}}452{{/c452}}{{#c453}}453{{/c453}}{{#c454}}454{{/c454}}{{#c455}}455{{/c455}}{{#c456}}456{{/c456}}{{#c457}}457{{/c457}}{{#c458}}458{{/c458}}{{#c459}}459{{/c459}}{{#c460}}460{{/c460}}{{#c461}}461{{/c461}}{{#c462}}462{{/c462}}{{#c463}}463{{/c463}}{{#c464}}464{{/c464}}{{#c465}}465{{/c465}}{{#c466}}466{{/c466}}{{#c467}}467{{/c467}}{{#c468}}468{{/c468}}{{#c469}}469{{/c469}}{{#c470}}470{{/c470}}{{#c471}}471{{/c471}}{{#c472}}472{{/c472}}{{#c473}}473{{/c473}}{{#c474}}474{{/c474}}{{#c475}}475{{/c475}}{{#c476}}476{{/c476}}{{#c477}}477{{/c477}}{{#c478}}478{{/c478}}{{#c479}}479{{/c479}}{{#c480}}480{{/c480}}{{#c481}}481{{/c481}}{{#c482}}482{{/c482}}{{#c483}}483{{/c483}}{{#c484}}484{{/c484}}{{#c485}}485{{/c485}}{{#c486}}486{{/c486}}{{#c487}}487{{/c487}}{{#c488}}488{{/c488}}{{#c489}}489{{/c489}}{{#c490}}490{{/c490}}{{#c491}}491{{/c491}}{{#c492}}492{{/c492}}{{#c493}}493{{/c493}}{{#c494}}494{{/c494}}{{#c495}}495{{/c495}}{{#c496}}496{{/c496}}{{#c497}}497{{/c497}}{{#c498}}498{{/c498}}{{#c499}}499{{/c499}}{{#c500}}500{{/c500}}`
            ord = ord.trim()

            var content = document.getElementById("enhanced-cloze-content").innerHTML

            // the extra (?:) at the beginning is there so that Anki doesn't think this is a field
            var clozeRe = /{(?:){c(\d+)::([\W\w]*?)(?:::([\W\w]*?))?}}/g

            // fill enhancedClozesData
            var match = clozeRe.exec(content);
            while (match != null) {
                enhancedClozesData["clozeId"].push(match[1])
                enhancedClozesData["answers"].push(match[2])
                enhancedClozesData["hints"].push(match[3] !== undefined ? match[3] : "")
                match = clozeRe.exec(content);
            }

            // create html with enhanced-clozes and insert it into the enhanced-clozes element
            var html = ""
            var ctr = 0
            var prevLastIndex = 0
            match = clozeRe.exec(content);
            while (match !== null) {
                var startIdx = clozeRe.lastIndex - match[0].length
                html += content.slice(prevLastIndex, startIdx)

                var clozeType = ord == enhancedClozesData["clozeId"][ctr] ? "genuine-cloze" : "pseudo-cloze"
                html +=
                    `<span class="${clozeType}" show-state="hint" cid="${enhancedClozesData["clozeId"][ctr]}" index="${ctr}">${enhancedClozesData["hints"][ctr]}</span>`

                prevLastIndex = clozeRe.lastIndex
                match = clozeRe.exec(content);
                ctr += 1
            }
            html += content.slice(prevLastIndex)

            var enhDiv = document.getElementById("enhanced-clozes")
            enhDiv.innerHTML = html
        }

        function initializeEnhancedClozes() {

            // genuine clozes refer to those belong to current card and need to be answered, e.g. { {c2::abc} } on card2
            // pseudo clozes refer to the opposite, e.g. { {c1::abc} } and { {c3::abc} } on card2
            $('.genuine-cloze, .pseudo-cloze').each(function (index, elem) {
                toggleCloze(elem, 'hint')
            });

            // SCROLL TO FIRST CLOZE
            if ($('.genuine-cloze').length != 0) {
                maybeScrollToCloze($('.genuine-cloze').first().get(0));
            }

            $('.pseudo-cloze').css('cursor', 'pointer')
            $('.genuine-cloze').css('cursor', 'pointer')
            $('#show-one-cloze-left').css('cursor', 'pointer')
            $('#show-one-cloze-right').css('cursor', 'pointer')

            // this prevents the blue selection briefly showing up on mobile when tapping on a cloze
            $('.pseudo-cloze').addClass('disable-select')
            $('.genuine-cloze').addClass('disable-select')
            $('#show-one-cloze-left').addClass('disable-select')
            $('#show-one-cloze-right').addClass('disable-select')

            if (typeof firstTimeLoadingEnhancedCloze === 'undefined') {
                firstTimeLoadingEnhancedCloze = false

                if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator
                    .userAgent)) {
                    $(document).on('touchstart', '.pseudo-cloze', function (event) {
                        toggleCloze(event.target, 'toggle');
                    });

                    $(document).on('touchstart', '.genuine-cloze', function (event) {
                        toggleCloze(event.target, 'toggle');
                    });

                    $(document).on('touchstart', '#show-one-cloze-left', function (event) {
                        revealOneClozeOfAType("genuine");
                    });

                    $(document).on('touchstart', '#show-one-cloze-right', function (event) {
                        revealOneClozeOfAType("pseudo");
                    });

                } else {
                    $(document).on('click touchstart', '.pseudo-cloze', function (event) {
                        toggleCloze(event.target, 'toggle');
                    });

                    $(document).on('click', '.genuine-cloze', function (event) {
                        toggleCloze(event.target, 'toggle');
                    });

                    $(document).on('click', '#show-one-cloze-left', function (event) {
                        revealOneClozeOfAType("genuine");
                    });

                    $(document).on('click', '#show-one-cloze-right', function (event) {
                        revealOneClozeOfAType("pseudo");
                    });
                }
            }

            window.enhancedClozeAddEventListener("keydown", (evt) => {
                if (shortcutMatcher(revealNextGenuineClozeShortcut)(event)) {
                    revealOneClozeOfAType("genuine");
                }
                if (shortcutMatcher(revealAllGenuineClozesShortcut)(event)) {
                    toggleAllClozesOfAType("genuine")
                }
                if (shortcutMatcher(revealNextPseudoClozeShortcut)(event)) {
                    revealOneClozeOfAType("pseudo");
                }
                if (shortcutMatcher(revealAllPseudoClozesShortcut)(event)) {
                    toggleAllClozesOfAType("pseudo");
                }
            })

        }

        function setupEditFieldDuringReview() {
            moveEditClozesElm()

            $("#enhanced-clozes").off('click').on('click', function (event) {
                if (document.getElementsByClassName("EFDRC-outline").length == 0) return
                if (!ctrlDown) return
                activateEditFieldDuringReview()
            });

            function moveEditClozesElm() {
                var editClozesElm = document.getElementById("edit-clozes")
                document.getElementById("main-section").appendChild(editClozesElm)
            }

            function activateEditFieldDuringReview() {
                var enhancedClozesElm = document.getElementById("enhanced-clozes")
                var editClozesElm = document.getElementById("edit-clozes")
                if (["inline", ""].includes(enhancedClozesElm.style.display)) {
                    enhancedClozesElm.style.display = "none";
                    editClozesElm.style.display = "inline";
                } else {
                    enhancedClozesElm.style.display = "inline";
                    editClozesElm.style.display = "none";
                }
                setTimeout(() => {
                    editable = editClozesElm.getElementsByClassName(
                        "EFDRC-outline")[0]
                    editable.onfocus()
                    editable.focus()
                })
            }

        }

        function insertStyling() {
            if (document.getElementById("enhanced-clozes-style")) return;

            mainSection = document.getElementById("main-section")
            style = document.createElement("style")

            // this css is also in the css file, but inserting the css here is easier than updating the css file for all users
            style.id = "enhanced-clozes-style"
            style.innerHTML = `
                .disable-select {
                    -webkit-touch-callout: none;
                    user-select: none;
                }
            `

            if (underlineRevealedPseudoClozes) {
                style.innerHTML += `
                .pseudo-cloze {
                    border-bottom: 1px solid #4285f4;
                    padding-bottom: 1px;
                }`
            }
            if (underlineRevealedGenuineClozes) {
                style.innerHTML += `
                .genuine-cloze {
                    border-bottom: 1px solid #ff5c82;
                    padding-bottom: 1px;
                }`
            }
            mainSection.insertBefore(style, mainSection.children[0])
        }

        function revealOneClozeOfAType(clozeType) {
            if (!["genuine", "pseudo"].includes(clozeType)) {
                console.log(`clozeType has unexpected value: ${clozeType}`)
            }

            if (!$(`.${clozeType}-cloze[show-state="hint"]`).length) {
                $('#no-more-cloze').animate({
                    display: "toggle",
                }, 500);
                return
            }

            var hiddenClozes = $(`.${clozeType}-cloze[show-state="hint"]`)
            if (hiddenClozes.length != 0) {
                revealCloze(hiddenClozes[0]);
            }
        }

        function toggleAllClozesOfAType(clozeType) {
            if (!["genuine", "pseudo"].includes(clozeType)) {
                console.log(`clozeType has unexpected value: ${clozeType}`)
            }

            var allRevealed = !$(`.${clozeType}-cloze[show-state="hint"`).length
            $(`.${clozeType}-cloze`).each(function (index, elem) {
                toggleCloze(elem, allRevealed ? "hint" : "answer");
            })
        }

        function revealCloze(elem) {
            if (!isVisible(elem)) {
                maybeScrollToCloze(elem);
            } else {
                toggleCloze(elem, 'answer');
                if (!isVisible(elem)) {
                    maybeScrollToCloze(elem);
                } else { }
                $(elem).hide(0);
                $(elem).fadeIn(500);
            }
        }

        function isVisible(elm) {
            var rect = elm.getBoundingClientRect();
            var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
            return !(rect.bottom < 0 || rect.top - viewHeight >= 0);
        }

        function maybeScrollToCloze(elem) {
            if (!scrollToClozeOnToggle) return
            $('html, body').animate({
                scrollTop: $(elem).offset().top - 60
            }, animateScroll ? 500 : 0);
        }

        function defineEnhancedClozeAddEventListener() {
            // define enhancedClozeAddEventListener
            // this function is almost identical to `document.addEventListener`
            // but removes the event listener attached on previous card / front side
            // using this function
            if (typeof window.enhancedClozeEventListener != "undefined") {
                for (const listener of window.enhancedClozeEventListener) {
                    const type = listener[0]
                    const handler = listener[1]
                    document.removeEventListener(type, handler)
                }
            }
            window.enhancedClozeEventListener = []

            window.enhancedClozeAddEventListener = function (type, handler) {
                document.addEventListener(type, handler)
                window.enhancedClozeEventListener.push([type, handler])
            }
        }

        var specialCharCodes = {
            "-": "minus",
            "=": "equal",
            "[": "bracketleft",
            "]": "bracketright",
            ";": "semicolon",
            "'": "quote",
            "`": "backquote",
            "\\": "backslash",
            ",": "comma",
            ".": "period",
            "/": "slash",
        };

        // Returns function that match keyboard event to see if it matches given shortcut.
        function shortcutMatcher(shortcut) {
            var shortcutKeys = shortcut.toLowerCase().split(/[+]/).map(key => key.trim())
            var mainKey = shortcutKeys[shortcutKeys.length - 1]
            if (mainKey.length === 1) {
                if (/\d/.test(mainKey)) {
                    mainKey = "digit" + mainKey
                } else if (/[a-zA-Z]/.test(mainKey)) {
                    mainKey = "key" + mainKey
                } else {
                    var code = specialCharCodes[mainKey];
                    if (code) {
                        mainKey = code
                    }
                }
            }
            var ctrl = shortcutKeys.includes("ctrl")
            var shift = shortcutKeys.includes("shift")
            var alt = shortcutKeys.includes("alt")

            var matchShortcut = function (ctrl, shift, alt, mainKey, event) {
                if (event.originalEvent !== undefined) {
                    event = event.originalEvent
                }
                if (mainKey !== event.code.toLowerCase()) return false
                if (ctrl !== (event.ctrlKey || event.metaKey)) return false
                if (shift !== event.shiftKey) return false
                if (alt !== event.altKey) return false
                return true
            }.bind(window, ctrl, shift, alt, mainKey)

            return matchShortcut
        }

        ctrlDown = false;
        window.enhancedClozeAddEventListener("keydown", function (ev) {
            if (isCtrlKey(ev.code)) ctrlDown = true;
        })
        window.enhancedClozeAddEventListener("keyup", function (ev) {
            if (isCtrlKey(ev.code)) ctrlDown = false;
        })

        const isCtrlKey = function (keycode) {
            return ['ControlLeft', 'MetaLeft'].includes(keycode)
        }

    });

    function showNextElement(elem) {
        $(elem).next().show(0);
    };

    function toggleCloze(elem, displayOption) {

        if (elem == null) return

        // if the element is not a cloze get its ancestor cloze
        if (elem.classList.contains("genuine-cloze") || elem.classList.contains("pseudo-cloze"))
            cloze = elem
        else {
            cloze = $(elem).closest(".genuine-cloze")
            if (cloze == null)
                cloze = $(elem).closest(".pseudo-cloze")
        }

        var index = $(cloze).attr('index');
        var answer = enhancedClozesData["answers"][index]
        var hint = enhancedClozesData["hints"][index]

        if (!showHintsForPseudoClozes && cloze.classList.contains('pseudo-cloze')) {
            hint = ""
        }

        if (revealPseudoClozesByDefault || answer.startsWith('#')) {
            if (answer.startsWith('#')) {
                answer = answer.slice(1)
            }

            if ($(cloze).attr('class') == 'pseudo-cloze') {
                $(cloze).attr('show-state', 'answer');
                $(cloze).html(answer);
                return
            }
        }

        if (displayOption == 'answer' || (displayOption == 'toggle' && $(cloze).attr('show-state') == 'hint')) {
            $(cloze).attr('show-state', 'answer');
            $(cloze).html(answer);
        } else if (displayOption == 'hint' || (displayOption == 'toggle' && $(cloze).attr('show-state') == 'answer')) {
            $(cloze).attr('show-state', 'hint');
            hint = '&nbsp;&nbsp;[&nbsp;&nbsp;' + hint + '&nbsp;&nbsp;]&nbsp;&nbsp;';
            $(cloze).html(hint);
        }

        // rerun mathjax on the document so that the cloze text gets formatted
        // ... for MathJax 2
        try {
            MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
        } catch { }
        // ... for MathJax 3
        try {
            MathJax.typesetPromise()
        } catch { }

    }
    already=true;
}

</script>

<div id="status" style="margin-bottom:1em;color:gray;font-size:60%;display:inline-block;padding:2px 10px"></div>