[Wiki] AnKore for ABR Diagnostic Radiology Core Exam by Ankore

Yeah it’s me, I’m the one at fault here.

Long story short, I pushed an update to address some cosmetic features in the Extras field, that broke mobile, and then I pushed another update to fix it and then somehow in the Ankihub backend I lost the ability to further edit templates. An interim solution for everyone until I can work with the people at Ankihub to fix the backend issue is for you guys to 1) disable ankihub updates for the Ankore deck and 2) replace the Back template with the following text (Tools > Manage Note Types > Cloze-AnKingRads (AnKore for ABR Diagnostic Radiology Core Exam / Ankore) > “Cards” button > replace the current contents of the Back template text box with the pre-update text:

<div class="section_title">{{Section Title}}</div>
<br>

<script>
// ##############  HINT REVEAL SHORTCUTS  ##############
// All shortcuts will also open with "H" if using the Hint Hotkeys add-on 
var ButtonShortcuts = {
    "Personal Notes" : "Alt+1",
    "Missed Questions" : "Alt+2",
    "Core Radiology" : "Alt+3",
    "Crack the Core" : "Alt+4",
    "War Machine" : "Alt+5",
    "Sectional Anatomy": "",
    "Additional Resources" : "Alt+9",
}
var ToggleAllButtonsShortcut = "'"
var ToggleNextButtonShortcut = "H";
// ##############  SHOW HINTS AUTOMATICALLY  ##############
var ButtonAutoReveal = {
    "Personal Notes" : false,
    "Missed Questions" : false,
    "Core Radiology" : false,
    "Crack the Core" : false,
    "War Machine" : false,
    "Sectional Anatomy": false,
    "Additional Resources" : true,
}

var ScrollToButton = true;

// ##############  TAG SHORTCUT  ##############
var toggleTagsShortcut = "C";

// ENTER THE TAG TERM WHICH, WHEN PRESENT, WILL TRIGGER A RED BACKGROUND
var tagID = "XXXYYYZZZ"

// WHETHER THE WHOLE TAG OR ONLY THE LAST PART SHOULD BE SHOWN

var numTagLevelsToShow = 0;

// ##############  CLOZE ONE BY ONE  ##############
var revealNextShortcut = "N" 
var revealNextWordShortcut = "Shift+N"
var toggleAllShortcut = ","

// Changes how "Reveal Next" and clicking behaves. Either "cloze" or "word".
// "word" reveals word by word. 
var revealNextClozeMode = "cloze" 

// What cloze is hidden with
var clozeHider = (elem) => "👑"
/* 
You can replace the above line with below examples. '█' or '_' works well for hiding clozes.

// Fixed length:
var clozeHider = (elem) => "███"
// Replace each character with "█":
var clozeHider = (elem) => "█".repeat(elem.textContent.length)
// Show whitespaces:
var clozeHider = (elem) => "[" + elem.textContent.split(" ").map((t) => "█".repeat(t.length)).join(" ") + "]"
// Color-filled box (doesn't hide images):
var clozeHider = (elem) => `<span style="background-color: red; color: transparent;">${elem.innerHTML}</span>`
*/

</script>


<div class="clozefield" id="text">{{cloze:Text}}</div>

<!-- ##############  EDIT CLOZE DURING REVIEW  ##############
			-change below (not above) to  "edit:cloze:Text" for editable field, 
				but be sure to have the correct add-on installed-->

<div class="editcloze" id="text">{{edit:cloze:Text}}</div>


<br>

<!-- ##############  TEXT-TO-SPEECH ##############
replace the arrows/dashes from the statement below with double curly brackets-->

<!--tts en_US voices=Apple_Samantha speed=1.4:cloze-only:Text-->


<hr>

<!-- BUTTON FIELDS -->
<!-- ClOZE ONE BY ONE BUTTONS -->

<div id="one-by-one" style="display: none;">{{One by one}}</div>

<div id="1by1-btns" style="display: none;">
  <button id="button-reveal-next" class="button-general" onclick="revealNextCloze()">Reveal Next</button>
  <button id="button-toggle-all" class="button-general" onclick="toggleAllCloze()">Toggle All</button>
</div>

<script>
  (() => {
    let clozeOneByOneEnabled = true;
      clozeOneByOneEnabled = document.getElementById("one-by-one").textContent !== "";
    
    if (clozeOneByOneEnabled) {
      document.getElementById("1by1-btns").style.display = "block";
    }
    })()
  </script>

<!-- BUTTON FIELDS -->
{{#Personal Notes}}
<span id = "hint-ln" class="hintBtn" data-name="Personal Notes">
  <a href="#" class="hint" onclick="toggleHintBtn('hint-ln')"></a>
  <button id="button-ln" class="button-general" onclick="toggleHintBtn('hint-ln')">
    <img src="_personal_notes.icon.png"> Personal Notes
  </button>
  <div id="notes" class="hints" style="display: none;">{{edit:Personal Notes}}</div>
</span>
{{/Personal Notes}}
<br>

{{#Missed Questions}}
<span id = "hint-mq" class="hintBtn" data-name="Missed Questions">
  <a href="#" class="hint" onclick="toggleHintBtn('hint-mq')"></a>
  <button id="button-mq" class="button-general" onclick="toggleHintBtn('hint-mq')">
    <img src="_missed_questions.icon.png"> Missed Questions
  </button>
  <div id="missed" class="hints" style="display: none;">{{edit:Missed Questions}}</div>
</span>
{{/Missed Questions}}

<!-- Extra field -->
{{#Extra}}<p></p>
<div id="extra">{{edit:Extra}}</div>
<br>{{/Extra}}

{{#Core Radiology}}
<span id = "hint-pat" class="hintBtn" data-name="Core Radiology">
  <a href="#" class="hint" onclick="toggleHintBtn('hint-pat')"></a>
  <button id="button-pat" class="button-general" onclick="toggleHintBtn('hint-pat')">
    <img src="_core_radiology.icon.png"> Core Radiology
  </button>
  <div id="core_radiology" class="hints" style="display: none;">{{edit:Core Radiology}}</div>
</span>
{{/Core Radiology}}
<br>
{{#Crack the Core}}
<span id = "hint-bb" class="hintBtn" data-name="Crack the Core">
  <a href="#" class="hint" onclick="toggleHintBtn('hint-bb')"></a>
  <button id="button-bb" class="button-general" onclick="toggleHintBtn('hint-bb')">
    <img src="_crack_the_core.icon.png"> Crack the Core
  </button>
  <div id="crack_the_core" class="hints" style="display: none;">{{edit:Crack the Core}}</div>
</span>
{{/Crack the Core}}
<br>

{{#War Machine}}
<span id = "hint-fa" class="hintBtn" data-name="War Machine">
  <a href="#" class="hint" onclick="toggleHintBtn('hint-fa')"></a>
  <button id="button-fa" class="button-general" onclick="toggleHintBtn('hint-fa')">
    <img src="_war_machine.icon.png"> War Machine
  </button>
  <div id="war_machine" class="hints" style="display: none;">{{edit:War Machine}}</div>
</span>
{{/War Machine}}
<br>

{{#Fundamentals of Diagnostic Radiology}}
<span id = "hint-physeo" class="hintBtn" data-name="Fundamentals of Diagnostic Radiology">
  <a href="#" class="hint" onclick="toggleHintBtn('hint-physeo')"></a>
  <button id="button-physeo" class="button-general" onclick="toggleHintBtn('hint-physeo')">
    <img src="_fundamentals_DR.icon.png"> Fundamentals of Diagnostic Radiology
  </button>
  <div id="fundamentals_DR" class="hints" style="display: none;">{{edit:Fundamentals of Diagnostic Radiology}}</div>
</span>
{{/Fundamentals of Diagnostic Radiology}}
<br>

{{#Sectional Anatomy}}
<span id = "hint-sketchy2" class="hintBtn" data-name="Sectional Anatomy">
  <a href="#" class="hint" onclick="toggleHintBtn('hint-sketchy2')"></a>
  <button id="button-sketchy2" class="button-general" onclick="toggleHintBtn('hint-sketchy2')">
    <img src="_sectional_anatomy.icon.png"> Sectional Anatomy
  </button>
  <div id="sectional_anatomy" class="hints" style="display: none;">{{edit:Sectional Anatomy}}</div>
</span>
{{/Sectional Anatomy}}
<br>

{{#Additional Resources}}
<span id = "hint-ar" class="hintBtn" data-name="Additional Resources">
  <a href="#" class="hint" onclick="toggleHintBtn('hint-ar')"></a>
  <button id="button-ar" class="button-general" onclick="toggleHintBtn('hint-ar')">
    <img src="_additional_resources.icon.png"> Additional Resources
  </button>
  <div id="additional" class="hints" style="display: none;">{{edit:Additional Resources}}</div>
</span>
{{/Additional Resources}}

<!-- NOT-PERSISTING EVENT LISTENER -->
<script>
  if (window.ankingEventListeners) {
    for (const listener of ankingEventListeners) {
      const type = listener[0]
      const handler = listener[1]
      document.removeEventListener(type, handler)
    }
  }
  window.ankingEventListeners = []
  
  window.ankingAddEventListener = function(type, handler) {
    document.addEventListener(type, handler)
    window.ankingEventListeners.push([type, handler])
  }
</script>

<!-- Shortcut Matcher Function -->
<script>
  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) {
    let shortcutKeys = shortcut.toLowerCase().split(/[+]/).map(key => key.trim())
    let 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 {
        let code = specialCharCodes[mainKey];
        if (code) {
          mainKey = code
        }
      }
    }
    let ctrl = shortcutKeys.includes("ctrl")
    let shift = shortcutKeys.includes("shift")
    let alt = shortcutKeys.includes("alt")

    let matchShortcut = function (ctrl, shift, alt, mainKey, event) {
      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
  }
</script>

<!-- HINT BUTTONS SETUP -->
<script>
    (function() {
      window.toggleHintBtn = function(containerId, noScrolling=false) {
        const container = document.getElementById(containerId)
        const link = container.getElementsByTagName("a")[0]
        const button = container.getElementsByTagName("button")[0]
        const hint = container.getElementsByTagName("div")[0]
    
        if (hint.style.display == "none") {
          button.classList.add("expanded-button")
          hint.style.display = "block"
          link.style.display = "none"
          if (ScrollToButton && !noScrolling) {
            hint.scrollIntoView({
              behavior: "smooth", // "auto" for instant scrolling
              block: "start",
              inline: "nearest"
            });
          }
        } else {
          button.classList.remove("expanded-button")
          hint.style.display = "none"
          link.style.display = ""
        }
      }

      window.toggleNextButton = function(){
        // adapted from Hint Hotkey add-on
        var customEvent = document.createEvent('MouseEvents');
        customEvent.initEvent('click', false, true);
        var arr = document.getElementsByTagName('a');
        for (var i=0; i<arr.length; i++) {
          var el = arr[i];
          if (el.style.display === 'none') {
            continue;
          }
          if (el.classList.contains("hint")) {
            el.dispatchEvent(customEvent);
            break
          }
        }
      }
        
      const isToggleNextShortcut = shortcutMatcher(ToggleNextButtonShortcut)
      ankingAddEventListener("keydown", (evt) => {
        if (evt.repeat) return
        if (isToggleNextShortcut(evt)) {
          toggleNextButton()
        }
      })
    
      const setupHintBtn = function(elem) {
        const containerId = elem.id
        const fieldName = elem.dataset.name
        const button = elem.getElementsByClassName("button")[0]
        
        if (ButtonAutoReveal[fieldName]) {
          toggleHintBtn(containerId, noScrolling=true)
        }
    
        const isShortcut = shortcutMatcher(ButtonShortcuts[fieldName])
        const isToggleAllShortcut = shortcutMatcher(ToggleAllButtonsShortcut)
        ankingAddEventListener("keydown", (evt) => {
          if (evt.repeat) return
          if (isShortcut(evt) || isToggleAllShortcut(evt)) {
            toggleHintBtn(containerId)
          }
        })
      }
    
      const hints = document.getElementsByClassName("hintBtn")
      for (let i = 0; i < hints.length; i++) {
        setupHintBtn(hints[i])
      }
    })()
    </script>

<!-- AUTOFLIP BACK SCRIPT -->
<script>
    // autoflip hides card in front template
    document.getElementById("qa").style.removeProperty("display")
</script>

<!-- CLOZE ONE BY ONE SCRIPT -->
<style>
  .cloze[data-content]:hover {
    cursor: pointer;
  }
  .cloze[data-hint] {
    color: #009400 !important;
  }
</style>

<script>
  (function() {
    var clozeOneByOneEnabled = true;
      clozeOneByOneEnabled = document.getElementById("one-by-one").textContent !== "";

    if (!clozeOneByOneEnabled) {
      return
    }
    
    const revealCloze = function(elem) {
      // Checking for dataset.content is undefined may not be needed anymore?
      if (elem.dataset.content === undefined) {
        return
      }
      elem.innerHTML = elem.dataset.content
      rerunMathJax()

      delete elem.dataset.content
      delete elem.dataset.hint
    }

    const revealClozeWord = function(elem) {
      if (elem.dataset.content === undefined) {
        return
      }
      if (elem.dataset.hidden !== undefined) {
        let words = elem.dataset.hidden.split(" ");
        if (words.length == 1) {
          revealCloze(elem)
          delete elem.dataset.hidden
          delete elem.dataset.revealed
        } else {
          elem.dataset.revealed = elem.dataset.revealed + " " + words[0]
          elem.dataset.hidden = words.slice(1).join(" ");
          let temp = document.createElement("div");
          temp.innerHTML = elem.dataset.hidden;
          elem.innerHTML = elem.dataset.revealed + " " + clozeHider(temp);
          delete elem.dataset.hint
        }
      } else {
        let temp = document.createElement("div");
        temp.innerHTML = elem.dataset.content;
        elem.dataset.hidden = temp.textContent;
        elem.dataset.revealed = "";
        revealClozeWord(elem)
      }
      rerunMathJax()
    }

    window.revealNextCloze = function() {
      let nextHidden = document.querySelector(".cloze[data-content]")
      if(!nextHidden) {
          return
      } 
      if (revealNextClozeMode === "word") {
          revealClozeWord(nextHidden)
      } else {
          revealCloze(nextHidden)
      }
    }

    const hideAllCloze = function(initial) {
      let clozes = document.getElementsByClassName("cloze")
      let count = 0 // hidden cloze count
      for (let i = 0; i < clozes.length; i++) {
        let cloze = clozes[i]
        if (cloze.offsetWidth === 0) {
          continue
        }
        cloze.dataset.content = cloze.innerHTML
        if(window.clozeHints && window.clozeHints[count]) {
          cloze.innerHTML = window.clozeHints[count]
          cloze.dataset.hint = true
        } else {
          cloze.innerHTML = clozeHider(cloze)
        }
        count += 1
        if (initial === true) {
          cloze.addEventListener("touchend", revealClozeClicked)
          cloze.addEventListener("click", revealClozeClicked)
        }
      }
    }

    window.toggleAllCloze = function() {
      let elems = document.querySelectorAll(".cloze[data-content]")
      let button = document.getElementById("button-toggle-all")
      if(elems.length > 0) {
        for (let i = 0; i < elems.length; i++) {
            revealCloze(elems[i])
        }
      } else {
        hideAllCloze(initial=false)
      }
    }

    const revealClozeClicked = function(ev) {
      let elem = ev.currentTarget
      if (elem.dataset.content === undefined) {
        return
      }
      if (!ev.altKey && (revealNextClozeMode !== "word")) {
        revealCloze(elem)
      } else {
        revealClozeWord(elem)
      }
      ev.stopPropagation()
      ev.preventDefault()
    }      

    const rerunMathJax = function() {
      // 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 {}
    }
    
    hideAllCloze(initial=true)

    let isShowNextShortcut = shortcutMatcher(window.revealNextShortcut)
    let isShowWordShortcut = shortcutMatcher(window.revealNextWordShortcut)
    let isToggleAllShortcut = shortcutMatcher(window.toggleAllShortcut)
    ankingAddEventListener("keydown", (ev) => {
      let next = isShowNextShortcut(ev)
      let word = isShowWordShortcut(ev)
      let all = isToggleAllShortcut(ev)
      if (next || word) {
        let elem = document.querySelector(".cloze[data-content]")
        if (elem) {
          if (next) {
            revealCloze(elem)
          } else {
            revealClozeWord(elem)
          }
          ev.stopPropagation()
          ev.preventDefault()
        }
      } else if (all) {
        toggleAllCloze()
        ev.stopPropagation()
        ev.preventDefault()
      }
    });
  })()
</script>

<!-- CLICKABLE COLORFUL TAGS -->
{{#Tags}}
<div id="tags-container">{{clickable::Tags}}</div>
<script>
  var tagContainer = document.getElementById("tags-container")
  if (tagContainer.childElementCount == 0) {
    var tagList = tagContainer.innerHTML.split(" ");
    var kbdList = [];
    var newTagContent = document.createElement("div");

    for (var i = 0; i < tagList.length; i++) {
      var newTag = document.createElement("kbd");
      var tag = tagList[i];
      // numTagLevelsToShow == 0 means the whole tag should be shown
      if(numTagLevelsToShow != 0){
        tag = tag.split('::').slice(-numTagLevelsToShow).join("::");
      }
      newTag.innerHTML = tag;
      newTagContent.append(newTag)
    }
    tagContainer.innerHTML = newTagContent.innerHTML;
    tagContainer.style.cursor = "default";
  }
  if (tagContainer.innerHTML.indexOf(tagID) != -1) {
    tagContainer.style.backgroundColor = "rgba(251,11,11,.15)";
  }

  function showtags() {
    var tagContainerShortcut = document.getElementById("tags-container");

    if (tagContainerShortcut.style.display
      === "none") {
      tagContainerShortcut.style.display = "block";
    } else {
      tagContainerShortcut.style.display =
        "none";
    }
  }
  
  var isShortcut = shortcutMatcher(toggleTagsShortcut)
  ankingAddEventListener('keyup', function (e) {
      if (isShortcut(e)) {
          showtags();
      }
  });

</script>
{{/Tags}}

<!-- WIKIPEDIA SEARCHES -->
<div id="popup-container">
  <button id="close-popup-btn" onclick="closePopup(true)">&times;</button>
  <a id="open-wiki-btn" href="">&#8618;</a>
  <div id="tc"></div>
  <div id="fadebottom_v"></div>
  <div id="ic"><img id="popup-image"></div>
</div>
<style>
  #tc {
    color: #222222;
    position: absolute;
    top: 16px;
    margin: 0px;
    left: 15px;
    text-decoration: none;
    height: 320px;
    overflow: hidden;
    overflow-y: scroll;
    white-space: pre-wrap;
    width: 300px;
  }
  
  #tc p {
    margin: 0px;
  }
  
  #tc::-webkit-scrollbar {
    display: none;
  }
  
  #fadebottom_v {
    height: 30px;
    width: 300px;
    background: -webkit-linear-gradient(270deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 1));
    z-index: 111;
    position: absolute;
    bottom: 0px;
    left: 15px;
  }
  
  #hc {
    color: #666;
    font-weight: bold;
  }
  
  #ic {
    right: 0px;
    top: 30px;
    position: absolute;
  }
  
  #ic img {
    width: 160px;
    height: auto;
    object-fit: cover;
    overflow: hidden;
  }
  
  #popup-image {
    width: 140px;
    height: auto;
  }
  
  #popup-container {
    background: #fff;
    position: absolute;
    bottom: 30px;
    right: 10px;
    z-index: 110;
    -webkit-box-shadow: 0 30px 90px -20px rgba(0, 0, 0, 0.3), 0 0 1px 1px rgba(0, 0, 0, 0.05);
    box-shadow: 0 30px 90px -20px rgba(0, 0, 0, 0.3), 0 0 1px 1px rgba(0, 0, 0, 0.05);
    padding: 0;
    display: none;
    font-size: 17px;
    line-height: 20px;
    border-radius: 2px;
    width: 480px;
    height: 340px;
    overflow: hidden;
    font-family: Arial;
    text-align: left;
    border: 1px solid #d0d0d0;
    border-radius: 5px;
  }
  
  #close-popup-btn {
    position: absolute;
    top: 1px;
    right: 5px;
    width: 32px;
    height: 32px;
    background: none;
    border: 0;
    cursor: pointer;
    font-family: 'Josefin Sans', sans-serif;
    font-size: 20px;
    outline: none;
    text-align: right;
    z-index: 112;
  }
  
  #open-wiki-btn {
    position: absolute;
    top: 10px;
    right: 30px;
    width: 15px;
    height: 32px;
    background: none;
    border: 0;
    cursor: pointer;
    text-decoration: none;
    color: #222222;
    font-family: 'Josefin Sans', sans-serif;
    font-size: 17px;
    outline: none;
    text-align: left;
    z-index: 112;
  }
</style>

<script>
  function getSummaryFor(word) {
    word = word.replace(/^[\.,\/#\!$%\^&\*;:{}=\-_`~() \'\s]+|[\.,\/#\!$%\^&\*;:{}=\-_`~()\'\s]+$/g, "");
    var pc = document.getElementById("popup-container");
    var hc = document.getElementById("hc");
    var tc = document.getElementById("tc");
    var ic = document.getElementById("ic");
    var imgelem = document.getElementById("popup-image");
    imgelem.src = "";
    var shortsum = "";
    
    fetch("https://en.wikipedia.org/api/rest_v1/page/summary/" + word)
    .then(function (response) { return response.json(); })
    .then(function (response) {
      shortsum = response.description;
      shortsum = shortsum.replace(/(Disambiguation.*)/g, "Disambiguation");
      tc.innerHTML = "<span id='hc'>" + capfl(shortsum) + "</span>" + "\n" + response.extract_html + "\n";
      tc.style.width = "420px";
      if (response.extract_html && !response.extract.endsWith("to:")) {
        pc.style.display = "block";
        document.getElementById("open-wiki-btn").href = response.content_urls.desktop.page;
      } else { 
        pc.style.display = "none"; 
      }
      if (!response.thumbnail.source || response.type === "disambiguation") {
        tc.style.width = "420px";
      } else { 
        tc.style.width = "300px"; imgelem.src = response.thumbnail.source; 
      }
    })
    .catch(function (error) { 
      console.log(error); 
    });
  }
  
  function closePopup(deselectAlso = false) {
    pcc.style.display = 'none';
    if (deselectAlso) { clearSelection(); }
  }

  var pcc = document.getElementById("popup-container");
  var prevSel = "";
  ankingAddEventListener('click', function () {
    var currentSelection = getSelectionText();
    if (currentSelection !== "") { prevSel = currentSelection; }
    if (currentSelection && !mustClickW) {
      getSummaryFor(currentSelection);
    } else { closePopup(); }
  });

  ankingAddEventListener('keyup', function (e) {
    if (e.key == "w") {
      if (pcc.style.display === "block") { closePopup(); } else { getSummaryFor(prevSel); }
    }
  });

  function getSelectionText() {
    var text = "";
    if (window.getSelection) {
      text = window.getSelection().toString();
    } else if (document.selection && document.selection.type != "Control") { text = document.selection.createRange().text; }
    return text;
  }

  function capfl(s) {
    return s.charAt(0).toUpperCase() + s.slice(1);
  }

  function clearSelection() {
    if (window.getSelection) { window.getSelection().removeAllRanges(); }
    else if (document.selection) { document.selection.empty(); }
  }
  
  //CUSTOMIZATION
  //this is a variable controlling whether user must click the "w" key to open the popup.
  //if set to true: user must select text, then click the "w" key to open wikipedia popup. Clicking "w" key again will close the popup. 
  //if set to false: user only needs to select text. popup will open automatically. Clicking "w" is an alternative but not obligatory way of opening/closing the popup in this mode.
  //BELOW SET to true or to false. 
  var mustClickW = true;
  //END CUSTOMIZATION
</script>

<!-- BEGIN ANKIHUB MODFICATIONS -->
{{#ankihub_id}}
<a class='ankihub-view-note'
    href='https://app.ankihub.net/decks/notes/{{ankihub_id}}'>
    View Note on AnkiHub
</a>

<style>
.ankihub-view-note {
    display: none;
}

.mobile .ankihub-view-note
  {
    display: block;
    left: 50%;
    margin-right: -50%;
    padding: 8px;
    border-radius: 50px;
    background-color: #cde3f8;
    font-size: 12px;
    color: black;
    text-decoration: none;
}

/* AnkiDroid (Android)
The button is fixed to the bottom of the screen. */
.android .ankihub-view-note {
    position: fixed;
    bottom: 5px;
    transform: translate(-50%, -50%);
}

/* AnkiMobile (IPhone)
position: fixed doesn't work on AnkiMobile, so the button is just below the content instead. */
.iphone .ankihub-view-note,
.ipad .ankihub-view-note {
    position: relative;
    transform: translate(-50%, 0);
    width: fit-content;
    margin-top: 20px;
}
</style>

<script>
    if(document.querySelector("html").classList.contains("android")) {
        // Add a margin to the bottom of the card content so that the button doesn't
        // overlap the content.
        var container = document.querySelector('#qa');
        var button = document.querySelector('.ankihub-view-note');
        container.style.marginBottom = 2 * button.offsetHeight + "px";
    }
</script>

{{/ankihub_id}}
<!-- END ANKIHUB MODFICATIONS -->

<!--
ANKIHUB_END
Text below this comment will not be modified by AnkiHub or AnKing add-ons.
Do not edit or remove this comment if you want to protect the content below.
-->

Anyway, I am very embarrassed about how this came about and will do my best to be a better steward of the deck. Once we are able to find a solution to the backend stuff I’ll post a comment, but in the meantime updates will be at a standstill.

8 Likes

It happens! Thank you very much for managing the deck. My residency program loves it.

2 Likes

This fixed worked well for me! :slight_smile: Friendly reminder for anyone who implements it to make sure you replace the back template like RadioBro said. I replaced the front template without thinking, and it broke my cards haha. Luckily, I had the old note settings saved another device.

1 Like

Hello again.

This fix worked perfectly for me as well. Thank you so much. And thanks to Yoonsung14 for the double check of placing the fix on the Back Template.

Anyway, please don’t be discouraged about the updates. Hickups happen. Like I said, just focus on adding more content as oppose to restructuring. As radiologists we always want more images! All the best!

1 Like

Due to delayed support I will be exploring hosting further updates on Ankicollab. Kinda excited to try something FOSS, since it’s easier to audit bugs rather than waiting for support / AI chatbots lol. I’m sure it’ll have its own quirks.

If anyone is interested, there’s a new deck called Mastering Radiology that’s come out that looks really promising, so take a look at that as well.

Update:
The platform is free to use and has integrated media sync. Tags will change if you do synchronize, and I was able to fix the issue with mobile breaking on the new card format. The subscription key for the deck is hidden for now while I refactor the deck.

How does the Mastering Radiology deck compare to this ankore deck?

Made by one person, borrows some Ankore deck cards, has less resource (page by page) organization but pretty nice looking card format. I think the maintainer has big aspirations for making it comprehensive for residency and beyond. Idk if that’s really necessary, once you have the foundations of radiology, fellowship knowledge is mostly structured experience that’s trained into you, not memorized.

As for me, planning on continued iterative updates, adding more physics content, tagging for Titan Radiology videos, stuff like that. Looking forward to using the AnkiCollab’s anonymous usage data – lets you know which cards people are having more difficulty with and make targeted edits.

When you guys are pasting that in the back template to try to correct this, is anyone running into the issue where it will not save and the pasted content will erase and be replaced with the original code? Meaning, I copy and paste what was sent above into the back template, save and sync. Then when I see that it does not work, I look at the back template and see that the original, incorrect code is still present

AnkiHub addon will automatically replace with the server’s version. I unfortunately cannot fix this, which is why we switched to AnkiCollab. In the meantime, you should either disable AnkiHub addon or unsubscribe.

1 Like

Novice here, what’s the difference between ankicollab and ankihub? And is this a temporary switch or is this the start of a permanent move?

AnkiHub is a paid service made by the guy who did Anking deck and his team of devs. It’s $6/month and has many advanced features but has some quirks in management that are opaque since it’s a closed source product and the dev team is difficult to reach. AnkiCollab is an open source alternative that is free to use.

Both allow:

  • Users to make suggestions, which maintainers can approve
  • Synchronization of decks and media
  • Deck management tools
  • Addons for management of deck synchronization and edit suggestions.

AnkiCollab:

  • No cost to users or maintainers
  • No community forums (as far as I can tell, would need to make a discord/matrix chat room)
  • Open source, easier to troubleshoot
  • Database and tagging of cards seems less opaque/complex. Cards just sync into folders without need to manage tags to build subdecks.

We are thinking it’ll be a more permanent change since it’ll save users money and have the same critical functions of AnkiHub. In the meantime the current deck on AnkiHub is functional with the above template fix.

Sounds good. So your thought is to move the Ankore deck into AnkiCollab instead of Ankihub? Additionally, I am not sure if you meant that the above issue has been resolved because my anki mobile still is exhibiting the same issue.

Would like to switch to the AnkiCollab to get my mobile cards working again, but is the AnkiHub support being totally phased out for this deck? I use a couple decks and it doesn’t seem like there is a way to turn on/off ankihub syncing for individual decks, so I’m wondering if there is a way to get the AnkiCollab updates while still having ankihub work for my other decks

Yeah if you don’t unsubscribe from Ankore on AnkiHub, AnkiHub will keep pushing the defective card template that breaks mobile. See the above comment I made with the back template that functions.

Give me a few days to test out how the transition will work for current users. I want to make sure that there’s no destructive effects when people go from AnkiHub to AnkiCollab sync. I’m also doing some refactors on HTML. There haven’t been any major updates in the past week, so you’re not missing out on much.

As for using both AnkiHub and AnkiCollab, you likely could get away with unsubscribing from Ankore from AnkiHub and continue to use your other AnkiHub decks.

PS Also thanks for all your edits! Definitely made the deck better!

Ok, the new deck is posted in its forseeable form on AnkiCollab. Made a lot of updates to card design, cleaned up lots of junk HTML tags, etc. Recommend unsubscribing from Ankore from AnkiHub to prevent collisions. There’s more instructions on migration on the landing page for the deck on AnkiCollab.

Cheers!

Anyone else having trouble with their images being too small especially for the Core Radiology field? Also did the styling change for the cards?

Styling definitely changed a lot. I stole the color scheme from Radiopedia with some modifications.

Do you have a pic of the Core Radiology field being too small? The flex window that runs in the extra section and puts text to the right of images does cause the images to be smaller than they used to be on desktop (~40% viewfinder width). It’s a compromise between space efficiency and image size. Might bump the zoom on click script to make images bigger if you need that.

I’ll DM you.

Were you able to fix the AnkiHub note type version at all? I think that its great to try out a different platform, but I’ve got everything set up with a few different AnkiHub decks so I probably wont move over to AnkiCollab. I may also just switch to the Mastering Radiology deck if you feel like that might be more comprehensive. Regardless, thanks for all your hard work :slight_smile:

1 Like