javascriptで文章を黒塗りして暗記するのに便利なものを作成しました

2022年4月15日

円周率を2桁の数字ずつ覚える暗記術がありますが、それを簡単にできるように以下を作りました。

ボタンを押したら、数文字ずつ、黒塗りがはがれるます。
テキストも変更でき、黒塗りをはがす文字数も変更できます。
テスト勉強など何かの暗記に使えると思います。
Javascriptで作りました。

[]で囲ったところは黒塗りになりません。

Javascriptのソースは以下です。

<style>
#anki {
  font-size: 1.75em;
  font-weight: bold;
  padding: .25em .5em;
  line-height: 1.2;
}
#anki span {
  display: inline-block;
  padding: 0;
  margin: .05em .1em;
}
#anki span.hide {
  background-color: #000;
  position: relative;
}
#anki span.hide::before {
  content: '';
  position: absolute;
  border: .375em solid #000;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}
#anki span.kuuhaku {
  padding: 0 .25em;
}
#anki textarea {
  font-size: 1em;
  font-weight: bold;
  width: 100%;
  display: block;
  margin: 0 0 .125em 0;
}
#anki .anki_btn {
  padding: .125em 0;
  margin: 0;
}
#anki .anki_btn button {
  font-size: .625em;
  font-weight: bold;
  padding: .125em .25em;
  margin: 0 .75em 0 0;
}
#anki .anki_btn select {
  font-size: .625em;
  font-weight: bold;
  padding: .125em 0;
}
</style>
<div id="anki"></div>
<script>
"use strict";
function kuroNuri(id) {
  const d = document.getElementById(id);
  const cHide = "hide";
  const cBtn = "anki_btn";
  const cKuuhaku = "kuuhaku";
  let bkupTxt = "";
  
  init();
  
  function init() {
    d.innerHTML = '';
    
    let textarea = document.createElement("textarea");
    textarea.maxLength = 500;
    textarea.rows = 3;
    textarea.value = bkupTxt;
    d.appendChild(textarea);
    ajastTxtareaHeight(textarea);
    textarea.focus();
    
    let btnDiv = document.createElement("div");
    btnDiv.setAttribute("class",cBtn);
    
    let btn = document.createElement("button");
    btn.innerHTML = 'スタート';
    btn.onclick = function() {
      startKuronuri();
    }
    btnDiv.appendChild(btn);
    d.appendChild(btnDiv);
  }
  function startKuronuri () {
    let t = document.getElementsByTagName("textarea")[0];
    let txt = t.value.trim();
    t.value = txt;
    if (txt === "") {
      alert("入力してください。");
      t.focus();
      return;
    }
    if (txt.length > 500) {
      alert("500文字以上は入力できません。");
      t.focus();
      return;
    }
    bkupTxt = txt;
    setHideText(txt);
  }
  function setHideText (txt) {
    d.innerHTML = '';
    
    let arrTxt = txt.split('');
    let noHideChars = [" ",".",",","、","。","[","]"];
    let noHideArea = false;
    
    for (let i = 0; i < arrTxt.length; i++) {
        let sp = document.createElement("span");
        let c = arrTxt[i];
        if (noHideChars.includes(c) === false && noHideArea === false) {
          sp.setAttribute("class",cHide);
        } else {
          if (c === " ") {
            sp.setAttribute("class",cKuuhaku);
          }
          else if (c === "[") {
            noHideArea = true;
          }
          else if (c === "]") {
            noHideArea = false;
          }
        }
        c = changeTxt(c);
        
        if (c === "\n") {
          let br = document.createElement("br");
          d.appendChild(br);
        } else {
          sp.textContent = c;
          d.appendChild(sp);
        }
    }
    
    let btnDiv = document.createElement("div");
    btnDiv.setAttribute("class",cBtn);
    
    let sel = document.createElement("select");
    for (let i = 1; i <= 10; i++) {
      let opt = document.createElement("option");
      opt.value = i;
      opt.text = i + "文字";
      sel.add(opt, null);
    }
    sel.options[1].selected = true;
    btnDiv.appendChild(sel);
    
    let btnOpen = document.createElement("button");
    btnOpen.innerHTML = '開く';
    btnOpen.onclick = function() {
      let sel = d.getElementsByTagName("select")[0];
      if (sel !== undefined) {
        removeHideClass(sel.value);
      }
    }
    btnDiv.appendChild(btnOpen);
    
    let btnOpenAll = document.createElement("button");
    btnOpenAll.innerHTML = 'すべて開く';
    btnOpenAll.onclick = function() {
      removeHideClass(0);
    }
    btnDiv.appendChild(btnOpenAll);
    
    let btnReset = document.createElement("button");
    btnReset.innerHTML = 'テキストを変更する';
    btnReset.onclick = function() {
      init();
    }
    btnDiv.appendChild(btnReset);
    
    d.appendChild(btnDiv);
  }
  function changeTxt(c) {
    // 意味はあまりない
    if (c === "<") {
      c = "<";
    }
    else if (c === ">") {
      c = ">";
    }
    else if (c === "'") {
      c = "’";
    }
    else if (c === '"') {
      c = "”";
    }
    else if (c === "&") {
      c = "&";
    }
    return c;
  }
  function setTxt (txt) {
    if ( ! txt) {
      return;
    }
    let t = document.getElementsByTagName("textarea")[0];
    if (t !== undefined) {
      t.value = txt;
      ajastTxtareaHeight(t);
    }
  }
  function removeHideClass (cnt) {
    let tags = d.getElementsByTagName('span') ,tag;
    let x = 0;
    if (d.getElementsByClassName(cHide)[0] === undefined) {
      return;
    }
    cnt = Number(cnt);
    if (isNaN(cnt) || cnt < 0 || cnt > 10) {
      return;
    }
    if (cnt === 0) {
      cnt = tags.length;
    }
    for (let i = 0; i < tags.length; i++) {
      tag = tags[i];
      if (tag.classList.contains(cHide)) {
        tag.classList.remove(cHide);
        x++;
        if (x >= cnt) break;
      }
    }
  }
  function ajastTxtareaHeight (textarea) {
    if ( textarea.scrollHeight > textarea.clientHeight ) {
     textarea.style.height = (textarea.scrollHeight + 12) + 'px';
    }
  }
  return {
    setTxt: function (txt) {
      setTxt(txt);
    },
    startKuronuri: function () {
      startKuronuri();
    }
  };
}

let kuronuri = kuroNuri("anki");
let pai = "[円周率200桁:3.]\n1415926535 8979323846 2643383279 5028841971 6939937510 5820974944 5923078164 0628620899 8628034825 3421170679\n"
        + "8214808651 3282306647 0938446095 5058223172 5359408128 4811174502 8410270193 8521105559 6446229489 5493038196";
kuronuri.setTxt(pai);
kuronuri.startKuronuri();
</script>

同様な感じでクイズや問題を作成できるのも作りましたので、よろしければ以下も確認してください。